3 ルール言語リファレンス
Oracle Business Rules RL Language (RL Language)の構文、セマンティクスおよび組込み関数の完全なリファレンスが含まれています。
文法ルールでRL Languageが定義されています。各文法ルールでは、::=
記号の左側に記述された非終端記号が、::=
記号の右側に記述された1つ以上の非終端記号および終端記号に関して定義されています。
予約語
aggregate、boolean、break、byte、catch、char、class、constant、continue、double、else、exists、extends、fact、factpath、false、final、finally、float、for、function、hide、if、import、include、instanceof、int、long、modify、new、null、property、public、query、return、returns、rule、rulegroup、ruleset、short、supports、synchronized、throw、true、try、while、var
注意:
太字で記述されている予約語は、現行のリリースに適用されています。太字で記述されていない予約語(break、continueおよびqueryが該当)は、RL Languageの今後のリリースで使用される予定です。
3.1 ルールセット
ルールセットでは一連の定義がグループ化されます。ルールセットは、すべて同時に評価されることを意図したルールとその他の定義の集まりです。また、実行可能なアクションおよびその他のルールセットを含めたり、Javaのクラスやパッケージをインポートすることもできます。
書式
ruleset ::= named-ruleset | unnamed-ruleset named-ruleset ::= ruleset ruleset-name { unnamed-ruleset } unnamed-ruleset ::= ( import | include | named-ruleset | definition | action | fact-class | rulegroup)* ruleset-name ::= identifier
使用上の注意
named-rulesetでは、ruleset-nameという名前の指定したルールセットに定義が作成されるか、または定義が追加されます。
unnamed-rulesetでは、main
という名前のデフォルトのルールセットに定義が追加されます。
ルールセットはネストされる場合があります。つまり、他のルールセットが含まれている場合があります。ネストはルールセットのネーミングには影響を与えませんが、Javaのインポートがパッケージの可視性に影響を与えるのと同様に、ルールセットの可視性には影響を与えます。
ルールセットは、RL LanguageコマンドラインまたはJava RuleSession APIを使用して実行できます。
named-ruleset ruleset-nameは、RuleSession
内で一意であることが必要です。
例
次のコード例には、2つの定義enterRoom
およびsayHello
と2つのアクション(assertおよびrun)が含まれています。
次のコード例で示されているルールは、次の条件が満たされるまで起動されません。
-
enterRoom
ファクトがアサートされる。 -
run関数が実行される。つまり、ルールの包含ルールセットである
hello
がルールセット・スタックに追加される。
ruleset hello { class enterRoom { String who; } rule sayHello { if (fact enterRoom) { println("Hello " + enterRoom.who); } } assert(new enterRoom(who: "Bob")); run("hello"); }
例3-1で、ルールセットR2がルールセットR1内にネストされている場合、名前R2はルール・セッション内で一意である必要があります。R2は、R1に関連して名付けられるわけではありません。たとえば、R2で定義されるクラスC2のグローバル名はR2.C2であり、R1.R2.C2ではありません。R2がR1内にネストされている場合、R1で定義されているパブリック・クラスC1は、完全名R1.C1または短縮名C1 (R2でC1が定義されていないと仮定した場合)を使用してR2で参照できます。
例3-1 ネストされたルールセットの使用
ruleset R1 { public class C1 { public String s; } C1 apple = new C1(s: "apple"); ruleset R2 { public class C2 { public String s; } C1 c1 = apple; // finds C1 and apple in containing ruleset R1 c1.s = "delicious"; C2 c2 = new C2(s: "pear"); } R2.C2 pear = R2.c2; // finds R2.C2 and R2.c2 because they are fully qualified println(apple.s + " " + pear.s); // prints "delicious pear" pear = c2; // UndefinedException: c2 not in R1 or a containing ruleset }
3.2 型
RL Languageは、厳密な型指定の言語です。各変数と値には指定された型があります。
書式
type ::= simple-type [ [ ] ] simple-type ::= primitive | object-type primitive ::= boolean | numeric numeric ::= int | double | float | long | short | byte | char object-type ::= class-definition-name | Java-class-name class-definition-name ::= qname Java-class-name ::= qname
型変換
値をある型から別の型に変換する方法はいくつかあります。
-
String
連結演算子+
を使用した、任意の型からString
への変換。 -
コンテキストからの暗黙的変換。たとえば、
int
をdouble
に加算する場合は、最初にint
がdouble
に変換され、その後で2つのdouble
が加算されます。 -
2つの数値型間のキャスト。
-
継承で関連付けられた2つのクラス間のキャスト
-
変換を実行する関数またはメソッドの起動。たとえば、
toString
です。
表3-1は、様々な型の暗黙的変換の要約です。各行は、「変換元」列の型が、「変換先」列の型リストに示されているように暗黙的に変換される可能性があることを示しています。
表3-1 暗黙的な型変換
開始 | 終了 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注意:
オブジェクトはJavaまたはRL Languageのクラスまたは配列のインスタンスです。型変換が可能であるのは、クラスが継承(実装または拡張)で関連付けられている場合のみです。
表3-2は、様々な型について許可されているキャスト変換の要約です。キャストを使用すると、ビット数の多いプリミティブ型をビット数の少ないプリミティブ型に、例外をスローすることなく変換できます。
表3-2に示されている型変換には、明示的なキャスト演算子が必要です。次に例を示します。
int i = 1; short s = (short)i;
注意:
表3-2に示されているような数値型を含む型変換では、上位ビットが失われる可能性があり、オブジェクトが関係するこのような変換では、RLClassCastExeption
がスローされる場合があります。
表3-2 明示的な型の変換
開始 | 先 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
キャストを使用して、ビット数の多いプリミティブ型をビット数の少ないプリミティブ型に変換するとき、RL Languageでは、例外はスローされずに多い分の上位ビットが切り捨てられます。
次に例を示します。
short s = -134; byte b = (byte)s; println("s = " + s + ", b = " + b); prints: s = -134, b = 122
プリミティブ型
プリミティブ型は次のいずれかです。
-
int
。32ビットの整数。リテラル値はjava.lang.Integer.parseInt
で解析されます。 -
long
。リテラル値はjava.lang.Long.parseLong
で解析されます。 -
short
。リテラル値はjava.lang.Short.parseShort
で解析されます。 -
byte
。リテラル値はjava.lang.Byte.parseByte
で解析されます。 -
char
。 -
double
。リテラル値はjava.lang.Double.parseDouble
で解析されます。 -
float
。リテラル値はjava.lang.Float.parseFloat
で解析されます。 -
boolean
。true
またはfalse
。
オブジェクト型
オブジェクト型は次のいずれかです。
文字列型
RL LanguageではJava文字列が使用されます。この場合は次のように処理されます。
-
文字列はクラス
java.lang.String
のインスタンスです。 -
文字列リテラルは二重引用符で区切られます("string")。
文字列内に二重引用符を含める場合は\"を使用します。
-
文字列は、
+
演算子を使用して次のように連結されます。-
+
演算子のオペランドが文字列の場合は、残りのオペランドが文字列に変換され、各オペランドが連結されます。 -
オブジェクトは、その
toString
メソッドを使用して文字列に変換されます。 -
RL Languageクラスのインスタンスは、組込み変換を使用して文字列に変換されます。
-
配列型
大カッコ([
]
)は配列を示します。RL Languageの配列の構文およびセマンティクスは、Javaの1次元配列と同じです。
注意:
RL Languageではマルチディメンション配列はサポートされていません。
3.3 識別子
RL Languageでは、識別子および名前空間パッケージについてJavaとXMLバリアントの両方がサポートされます。XMLバリアントを使用するには、識別子を逆引用符で囲む必要があります。
書式
identifier ::= java-identifier | xml-identifier
java-identifier ::= valid-Java-identifier
xml-identifier ::= `valid-xml-identifierまたはURI ` ここで、 valid-Java-identifierは有効なJava識別子で(JLd_0など)、valid-xml-identifierは有効なXML識別子です(x-1など)。URI: 有効なUniform Resource Identifier(URI)。例: http://www.oracle.com/rules
使用上の注意
xml-identifierには、無効なJava識別子文字(例: 「:」および「-」)を含めることができます。JAXB仕様では、XML識別子からJava識別子への標準マッピングが定義されており、先頭大文字表記のJava表記規則も保持されています。JAXB仕様では、スキーマのターゲット名前空間URIからJavaパッケージ名への標準マッピング、および無名型からJava静的ネスト・クラスへのマッピングも定義されます。
例
RL Languageでは、識別子および名前空間またはパッケージについてJavaバリアントとXMLバリアントの両方がサポートされます。XMLバリアントを使用するには、例3-2で示すように、識別子を逆引用符で囲みます。
逆引用符の表記法は、RL Languageで識別子またはパッケージ名が有効であるすべての場所で使用できます。assertXPath
のString引数で識別子のXMLバリアントを使用する場合、逆引用符は必要ありません。
例3-2 逆引用符を使用したXML識別子のマッピングの例
`http://www.example.com/po.xsd` -> com.mycompany.po `my-attribute` -> myAttribute `Items/item` -> Items$ItemType
3.4 リテラル
表3-3は、RL Languageのリテラルの要約です。リテラルはJavaリテラルと同じです。
表3-3 RL Languageのリテラル
リテラル | 割当て可能な変数の型 |
---|---|
範囲0から127の整数、または範囲0から127のUCS2エンコーディングの |
|
範囲0から65535の整数または |
|
範囲-128から127の整数 |
|
範囲-32768から32767の整数 |
|
整数 |
|
末尾が |
|
浮動小数点定数 |
|
末尾が |
|
""で囲まれた文字列 |
|
3.5 定義
ルールセット内の定義が実行されると、誤りがないかチェックされ、ルール・セッションで後で使用するために保存されます。
書式
definition ::= variable | rule | rl-class-definition | function name ::= identifier qname ::= [ ruleset-or-packagename. ]name ruleset-or-packagename ::= qname
使用上の注意
各定義の名前は包含ルールセット内で一意であるため、修飾名qnameはルール・セッション内で一意です。
ルールセット・レベルで定義された変数はグローバルです。グローバル変数は、ルールセットに含まれているすべての式で変数名を使用して参照可能であり、他のルールセット内の式では変数のqnameを使用して参照可能です。関数およびパブリック・クラスも、それぞれのqnameを使用して他のルールセットから参照できます。
Javaクラスとそのメソッドおよびプロパティにもqnameがあります。
例3-3 名前付きルールセット内のクラス定義
ruleset hello { class enterRoom { String who; } rule sayHello { if (fact enterRoom) { println("Hello " + enterRoom.who); } } assert(new enterRoom(who: "Bob")); run("hello"); }
3.5.1 変数定義
変数はJavaと同様に宣言されますが、必ず初期化する必要があります。
書式
variable ::= [ final ] ( numeric name = numeric-expression
| boolean name = boolean-expression | type [ ] name = array-expression | null | object-type name = object-expression | null ) ) ;
使用上の注意
array-expressionで初期化される配列の型は、配列要素に対して指定されたtypeと同じであることが必要です。
変数には、プリミティブ型、Javaクラス名またはRL Languageクラス名を使用でき、同じ型の要素の配列にもできます。
object-expressionの型は、宣言対象の変数のobject-typeと同じであることが必要です。クラス・インスタンスまたは配列はnullに初期化できます。
変数はスコープ内でローカルまたはグローバルです。初期化式が必要です。ローカル変数はファイナルにはできません。
3.5.1.1 グローバル変数
ルールセットの直後に囲まれている(つまり定義内の)変数は、スコープ内のルール・セッションに対してグローバルです。ファイナル・グローバル変数の初期化式は、グローバル変数の定義時に実行されます。
非ファイナル・グローバル変数の初期化式は次の両方の場合に実行されます。
-
グローバル変数の定義時
-
reset
関数の毎コール時
ファイナルとして宣言されたグローバル変数は、初期化後変更できません。
ルール条件(fact-set-condition)で参照されるグローバル変数はファイナルであることが必要です。
例
次のコード例は、reset関数によって非ファイナル・グローバル変数i
の初期化が実行されることを示しています。したがって、この例では1ではなく0(ゼロ)が出力されます。
RL> int i = 0; RL> i++; RL> reset(); RL> println(i);
二次的作用のある関数でグローバル変数を初期化する場合には注意が必要です。resetのコール時に二次的作用が繰り返されないようにする場合は、変数をfinal
として宣言する必要があります。たとえば、例3-4ではonceは2回出力され、例3-5ではonceは1回出力されます。
例3-4 resetの二次的作用を受けるグローバル変数の初期化
RL> clear; RL> function once() returns int { println("once"); return 1; } RL> int i = once(); once RL> reset(); once RL>
ファイナル・グローバル変数のサンプル
例3-5 resetの二次的作用を回避するファイナル・グローバル変数の初期化
RL> clear; RL> function once() returns int { println("once"); return 1; } RL> final int i = once(); once RL> reset(); RL>
3.5.2 ルール定義
Oracle Rules Engineでは、ルール・セッション内のすべてのルールのfact-set-conditionに対してファクトが照合され、実行するルールのアジェンダが作成されます。ファクト・セットの行は、ルールの条件をtrueにするファクトの組合せです。アクティブ化は、ルールのaction-blockに関して組み合されたファクト・セットの行です。アジェンダは、ルール・セッション内の全アクティブ化のリストです。Oracle Rules Engineでは、作業メモリーの状態が変化した場合(通常はファクトがアサートまたは取り消された場合)に、ファクトおよびルールが照合されます。
run、runUntilHaltおよびstep関数によってアクティブ化が実行されます。アクティブ化は、実行後、またはファクト・セット行で参照されるファクトが変更または取り消され、ルールの条件と一致しなくなると、アジェンダから削除されます。
アクティブ化はルールセット・スタックの順に実行されます。ルールセット・スタックは、getRulesetStack、clearRulesetStack、pushRulesetおよびpopRuleset関数で管理できます。
ルールが起動するには、次の3つの事項が発生する必要があります。
-
そのルールのアクティブ化がアジェンダに存在すること。
-
包含ルールセットがルールセット・スタックの最上位にあること。
-
run、runUntilHaltまたはstepが実行されること。
fact-set-conditionで生成されるファクト・セットは、ルール・アクションで使用できます。ファクト・セット内の各行について、action-blockは次のようにアクティブ化されます。
-
ルールのaction-blockは、指定したルールのpriorityで実行されるようにスケジュールされます。
-
action-blockから一致ファクトへの参照は、現在の行にバインドされます。
-
action-blockの実行前に一致ファクトが取り消された場合、依存アクティブ化は破棄(アジェンダから削除)されます。
書式
rule ::= rule rule-name { property* fact-set-condition action-block }
rule-name ::= name property ::= priority | autofocus | logical | active priority ::= priority = numeric-expression autofocus ::= autofocus = boolean-literal logical ::= logical = ( boolean-literal | positive-integer-literal ) active ::= active = boolean-literal effectiveDateForm ::= effectiveDateForm = oracle.rules.rl.Rule: EDFORM_DATE、EDFORM_DATETIMEまたはEDFORM_TIMEに定義されたいずれかの値に制限されたint effectiveStartDate ::= effectiveStartDate = タイプjava.util.Calendar
の式 effectiveEndDate ::= effectiveEndDate = タイプ java.util.Calendar
の式 ここで、 positive-integer-literalは0よりも大きい整数リテラル
使用上の注意
priorityプロパティでは、ルールの優先度が指定されます。同じルールセットのルールのアクティブ化セット内では、アクティブ化は優先度順に実行されます(「ルール起動の順序付け」を参照)。ルールの優先度が異なる場合、優先度の高いルールが優先度の低いルールより先にアクティブ化されます。デフォルトの優先度は0(ゼロ)です。同じ優先度のルールのアクティブ化セット内では、最後に追加されたアクティブ化が最初に実行されますが、この動作は変更できます(getStrategy関数およびsetStrategy関数を参照)。
autofocusプロパティがtrue
のルールでは、ルールがアクティブ化されたときに包含ルールセットがルールセット・スタックに自動的に追加されます。
logicalプロパティが使用されているルールは、ルールのアクション・ブロックでアサートされたすべてのファクトが、ルールの条件によって照合された一部のファクトまたはすべてのファクトに依存するようにします。logicalプロパティに整数値nを指定すると、ルール条件内にある最初のn個の上位&&
edファクト・セット式に対する依存性が作成されます。logical
プロパティにブール値trueを指定すると、条件のファクト・セット式に対する依存性が作成されます。ファクト・セットの行内で参照されるファクトが、ルールの論理条件に該当しなくなるように変更された場合はいつでも、そのファクト・セット行に関連付けられているアクティブ化によってアサートされたファクトは自動的に取り消されます。論理プロパティが有効化されているルールでは、ルール内のアクション・ブロックによってアサートされた全ファクトが、ルール条件内で一致したファクトに依存します。ルールの条件が適用されなくなるなど、ルール条件で参照されていたファクトに変更があると、ルール条件によってアサートされたファクトは自動的に取り消されます。
activeプロパティは、デフォルトでtrue
に設定されます。
effectiveStartDateの日付は、デフォルトでnullに設定されます。
effectiveEndDateの日付は、デフォルトでnullに設定されます。
effectiveDateFormは、デフォルトでRule.EDFORM_DATETIME
に設定されます。
例
例3-6は、推論(ソクラテスは人間である。これはソクラテスは男性であるというファクトに依存する)のあるルールを示しています。
例3-6 ルールallMenAreMortalの定義および使用
RL> clear; RL> class Man {String name;} RL> class Mortal {String name;} RL> Mortal lastMortal = null; RL> rule allMenAreMortal { logical = true; if (fact Man) { assert(lastMortal = new Mortal(name: Man.name)); } } RL> watchAll(); RL> Man socrates = new Man(name: "Socrates"); RL> assert(socrates); ==> f-1 main.Man (name : "Socrates") ==> Activation: main.allMenAreMortal : f-1 RL> run(); Fire 1 main.allMenAreMortal f-1 ==> f-2 main.Mortal (name : "Socrates") <== Focus main, Ruleset stack: {} RL> retract(socrates); <== f-1 main.Man (name : "Socrates") <== f-2 main.Mortal (name : "Socrates") RL> showFacts(); f-0 initial-fact()
複数ルールでアサートされた同じファクトの例
例3-7は、同じファクトを複数のルールでアサートすること、または最上位のルールセット・アクションまたは関数でアサートすることが可能であることを示しています。このようなファクトは、すべてのアサータに自動取消をコールする論理句がないかぎり、自動的に取り消されません。最上位のアクションまたは関数でアサートされているファクトは、自動的に取り消されることはありません。
ソクラテスが人間であるというファクトは取り消されないことに注意してください。これは、ソクラテスが男性であるというファクトに依存していない最上位のアクションでアサートされているためです。
例3-7 ファクトの無条件アサート
RL> assert(socrates); ==> f-3 main.Man(name : "Socrates") ==> Activation: main.allMenAreMortal : f-3 RL> run(); Fire 1 main.allMenAreMortal f-3 ==> f-4 main.Mortal(name : "Socrates") <== Focus main, Ruleset stack: {} RL> assert(lastMortal); <=> f-4 main.Mortal(name : "Socrates") RL> retract(socrates); <== f-3 main.Man(name: "Socrates") RL> showFacts(); f-0 initial-fact() f-2 main.Mortal(name: "Socrates")
3.5.3 クラス定義
参照クラスはすべて、RL Languageクラス定義で定義されているか、またはJavaクラスパスに存在している(Javaクラスがインポートされている)必要があります。
RL LanguageクラスとJavaクラスの両方で、提供されているxpathでsupportsキーワードを使用してxpathをサポートできます。
書式
rl-class-definition ::= [ public ] [ final ] class name [ extends ] [ supports ] { type-property* }
type-property ::= [ public ] type name [ = expression ] ;
extends ::= extends qname extended-class-name
extended-class-name ::= qname
使用上の注意
オプションの初期化expressionの型は、プロパティの型またはその型に暗黙的に変換可能な型と同じであることが必要です。
パブリック・クラスはすべてのルールセットから参照可能です。非パブリック・クラスは、包含ルールセット内でのみ参照可能です。
ファイナル・クラスは拡張できません。
拡張クラスは、インポートされたJavaクラスではなく、定義済のRL Languageクラスであることが必要です。
各プロパティにオプションのイニシャライザを設定できます。イニシャライザは、クラスがnewでインスタンス化されるときに評価されます。newに初期値も渡された場合、クラス定義内のイニシャライザによって計算された値は、newに渡された値によって上書きされます。
パブリック・プロパティはすべてのルールセットから参照可能です。非パブリック・プロパティは、包含ルールセット内でのみ参照可能です。
例
RL Languageでは、プロパティのタイプとクラス定義を示す以下の例のように、プロパティのタイプは包含クラス定義の名前の場合があります。
class C0 { C0 next; }
RL Languageでは、Javaとは異なり、クラス定義の前方参照はサポートされていません(例3-8を参照)。
例3-8 前方参照のあるクラス定義が許可されない例
class C1 { C2 c2; // causes an UndefinedException } class C2 { C1 c1; }
3.5.3.1 xpathサポート
注意:
xpathサポートは非推奨となりました。詳細は、「assertTree」を参照してください。
RL LanguageクラスとJavaクラスの両方でxpathがサポートされています。
XML識別子は、xpath内では逆引用符で囲む必要はありません。
組込みのassertXPath関数では、オブジェクトのツリーをファクトとしてアサートするための簡単なxpathに似た構文がサポートされます。ツリーのノードは、xpathをサポートする同じパッケージまたはルールセット内のクラスのオブジェクトです。親ノードと子ノードの間のリンクはXLink
クラスのインスタンスです。xpathをサポートするクラス内のすべてのプロパティをxpath式で使用できます。
書式
supports ::= supports xpath
xpath ::= first-step next-step* first-step ::= ( . | /* | [ // ] ( identifier | * ) ) predicate* predicate ::= [ identifier xrelop literal ] next-step ::= ( / | // ) ( identifier | * ) predicate* xrelop ::= eq | lt | gt | le | ge | ne | == | < | > | <= | >= | != literal ::= integer-literal | decimal-literal | double-literal | string-literal | true | false | dateTime-literal | date-literal | time-literal integer-literal ::= [-] d+ d ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 decimal-literal ::= [-] ( . d+ | d+ . d*) double-literal ::= [-] ( . d+ | d+ [ . d* ] ) ( e | E ) [+ | -] d+ string-literal ::= " char* " | ' char* ' dateTime-literal ::= local-date T time-literal date-literal ::= local-date [ time-zone ] time-zone ::= Z | ( + | - ) d d : d d local-date ::= d d d d - d d - d d time-literal ::= d d : d d : d d [. d+] [ time-zone ]
使用上の注意
RL Languageのxpathサポートは、Java XML Binding (JAXB) 1.0標準に準拠するクラスで動作するように設計されました。特定のルートからxpathで選択された要素までを含めてすべてのJAXB要素がアサートされます。アサート要素間の親子関係に関するルールを記述できるように、追加のXLinkファクトがアサートされます。
JAXB要素が取り消されるか、またはassertを使用して再アサートされた場合、そのすべての子およびXLinkが取り消されます。再アサートするかわりに、assertXPathを再度使用してください。
RL LanguageのXpathは、W3C Xpath 2.0の正確なサブセットではありません。次の相違点に注意してください。
-
lt
と<
、gt
と>
がRL Languageでは同義ですが、W3Cでは異なります。 -
W3Cでは、日付リテラルで
xs:date()
およびその他のコンストラクタを使用する必要があります。 -
コンストラクタはRL Languageではサポートされていません。文字列リテラル以外のリテラルはRL Languageでは引用できません。
例
表3-4は、組込みのassertXPath関数で使用するxpath選択オプションを示しています。この説明部分で、選択とは、要素がファクトとしてアサートされ、アサート要素を表す要素プロパティがあるXLinkの選択プロパティがtrue
であることを意味します。選択した要素の祖先は、ルート要素まで含めて常にアサートされますが、必ずしも選択されるわけではありません。
表3-4 xpath選択文字列
xpath選択文字列 | 選択の説明 |
---|---|
//* |
ルートを含めてすべての要素を選択 |
.//* |
ルート以外のすべての要素を選択 |
. |
ルートのみを選択 |
//foo |
fooという名前のプロパティの値であるすべてのオブジェクトを選択 |
.[x==1]/y |
ルートに、名前がxで1と等しい子要素または属性がある場合にのみ、ルートの子または属性で名前がyであるものを選択 |
次の例では、PersonというRL Languageクラスがインスタンス化され、次のようなファミリ・ツリーが作成されます。
First Generation Second Generation Third Generation Ida Mary Fred John Rachel Sally Evan
前述の例では、2つのxpathでassertXPath関数が2回使用されています。
//kids[male==true] //kids[male==false]
例3-9では、次の2つのルールが定義されます。
-
sibling
: 兄弟姉妹関係のすべてのペアを出力 -
brotherSister
: 兄弟のすべてのペアおよび姉妹のすべてのペアを出力
結果は次のようになります。
f-0 initial-fact()
合計1ファクトの場合。
例3-9 supports xpathを使用したファミリ・ツリー・ルールの例
import java.util.*; ruleset xp { public class Person supports xpath { public String name; public boolean male; public List kids; } // Build the Family Tree Person p = new Person(name: "Fred", male: true); List k = new ArrayList(); k.add(p); p = new Person(name: "John", male: true); k.add(p); p = new Person(name: "Mary", male: false, kids: k); Person gramma = new Person(name: "Ida", male: false, kids: new ArrayList()); gramma.kids.add(p); p = new Person(name: "Sally", male: false); k = new ArrayList(); k.add(p); p = new Person(name: "Evan", male: true); k.add(p); p = new Person(name: "Rachel", male: false, kids: k); gramma.kids.add(p); // test for siblings. // Note the test id(p1) < id(p2) halves the Cartesian product p1 X p2. rule sibling { if (fact Person p1 && fact Person p2 && id(p1) < id(p2) && exists(fact XLink(element: p1) x && fact XLink(element: p2, parent: x.parent))) { println(p1.name + " is sibling of " + p2.name); } } // test for brothers and sisters, given the following 2 assertXPath() calls rule brotherSister { if (fact Person p1 && fact Person p2 && id(p1) < id(p2) && exists(fact XLink(element: p1, selected: true) x && fact XLink(element: p2, selected: true, parent: x.parent) y && x.samePath(y))) { println(p1.name + " and " + p2.name + " are " + (p1.male ? "brothers" : "sisters")); } } assertXPath("xp", gramma, "//kids[male==true]"); assertXPath("xp", gramma, "//kids[male==false]"); run("xp"); }
例3-10 ファミリ・ツリーの例の実行結果
Mary and Rachel are sisters Evan is sibling of Sally Fred and John are brothers Fred is sibling of John Mary is sibling of Rachel
取消し要素の結果のサンプル
例3-11は、assertXPath
でアサートされた要素を取り消すと、そのすべての子孫も取り消されることを示しています。
例3-11 ファミリ・ツリーの取消し
retract(xp.gramma); showFacts();
例3-12 クラスAncestorを使用した祖先のペアの出力
assertXPath("xp", xp.gramma, "//*"); class Ancestor { Object element; Object ancestor; } rule parents { if (fact XLink x) { assert(new Ancestor(element: x.element, ancestor: x.parent)); } } rule ancestors { if (fact XLink x && fact Ancestor(ancestor: x.element) a) { assert(new Ancestor(element: a.element, ancestor: x.parent)); } } rule printAncestor { if (fact xp.Person p && fact xp.Person a && fact Ancestor(element: p, ancestor: a) { println(a.name + " is an ancestor of " p.name); } } run();
Ancestorの例の実行結果のサンプル
例3-13 Ancestorの例の実行結果
Mary is an ancestor of John Ida is an ancestor of John Mary is an ancestor of Fred Ida is an ancestor of Fred Ida is an ancestor of Mary Rachel is an ancestor of Evan Ida is an ancestor of Evan Rachel is an ancestor of Sally Ida is an ancestor of Sally Ida is an ancestor of Rachel
3.5.4 関数定義
関数はJavaの静的メソッドと同じです。
書式
function ::= function name parameters [ returns type ] action-block
parameters ::= ( [ type identifier ( , type identifier )* ] )
使用上の注意
action-blockによって、定義されている関数を起動できます。ただし、action-blockには、まだ定義されていない関数の前方参照を含めることはできません(例3-14および例3-15を参照)。
関数はオーバーロード可能です。たとえば、組込みのprintln関数はオーバーロードされています。
例
例3-14 再帰的参照が含まれた有効な関数の定義
function factorial(long x) returns long { if (x <= 1) { return 1; } else { return x * factorial(x - 1); } }
例3-15 未定義関数の参照が含まれた無効な関数の定義
function f1() { f2(); // causes an UndefinedException } function f2() { }
3.6 ファクト・クラス宣言
すべてのJavaクラスを、ファクト・コンテキスト内でRL Languageファクトとして使用できます。
ファクト・コンテキストは次のいずれかです。
-
fact-class宣言のクラス
-
fact-set-patternのクラス
-
assert関数の引数の宣言クラス
-
retract関数の引数の宣言クラス
-
assertXPath関数の要素引数の宣言クラス
クラスまたはインタフェースB
がクラスまたはインタフェースA
を実装または拡張するとき、A
とB
の両方がファクト・コンテキスト内に出現する場合は、A
がB
の前に出現する必要があります。このルールに従わない場合はFactClassException
が発生します。
ファクト・クラス定義は、RL Languageクラスを使用する場合は必要ありません。
xpathサポートについては、RL Languageクラス定義のsupports xpath句を使用します。
書式
fact-class ::= fact class class-name [ supports ] ( fact-class-body | ; )
class-name ::= qname
fact-class-body ::= { [ hidden-properties | properties ]}
hidden-properties ::= hide property * ; | ( hide property ( ( name , )* name | * ) ; )+ properties ::= property * ; | ( property ( ( name , )* name | * ) ; )+
使用上の注意
fact-class-bodyはfact-class宣言ではオプションです。デフォルトのfact-class-bodyは次のとおりです。
{ property *; }
property
またはhide property
キーワードのいずれかを本体で使用できますが、両方は使用できません。
hide property
がプロパティ名のリストを指定して使用されている場合、これらのプロパティ名は非表示になり、RL Languageでは使用できません。
hide property
がワイルドカード*を指定して使用されている場合、スーパークラスまたはスーパーインタフェースで公開されているプロパティ以外のプロパティはRL Languageで使用できません。
property
がプロパティ名のリストを指定して使用されている場合、これらのプロパティは公開され、RL Languageで使用できます。propertyがワイルドカード*
を指定して使用されている場合、スーパークラスまたはスーパーインタフェースで非表示にされているプロパティ以外のすべてのプロパティをRL Languageで使用できます。
サブクラスで非表示のプロパティがスーパークラスで公開されている場合、またはスーパークラスで非表示のプロパティがサブクラスで公開されている場合は、HiddenPropertyException
がスローされます。
例
JavaクラスVehicle
にサブクラスCar
とTruck
があるとします。例3-16で示されるルールmatchVehicle
は、FactClassException
をラップするTypeCheckException
を生成します。これは、スーパークラスの前にサブクラスが参照されるためです。ラップは、FactClassException
とMultipleInheritanceException
の両方に対するサブクラス化のかわりに使用されます。これは、ファクト・コンテキストによっては、これらの例外が実行時までスローされず、RLRuntimeException
でラップされるためです。
例3-16 スーパークラスの前に参照されるサブクラスがあるmatchVehicleルール
assert(new Car()); // fact context for Car assert(new Truck()); // fact context for Truck rule matchVehicle { if (fact Vehicle v) { // fact context for Vehicle - too late! if (v instanceof Car) { println("car"); } else { println("truck"); } } } // generates a TypeCheckException wrapping a FactClassException
最初にスーパークラスの参照があるmatchVehicleルールのサンプル
例3-17では、matchVehicle
ルールがスーパークラスに対する最初の参照であるため、例外はスローされません。
例3-17 最初にスーパークラスの参照があるmatchVehicleルール
clear; rule matchVehicle { if (fact Vehicle v) { if (v instanceof Car) { println("car"); } else { println("truck"); } } } assert(new Car()); assert(new Truck()); run(); // prints "truck" then "car"
最初にクラス宣言があるmatchVehicleルールのサンプル
例3-18では、ファクト・クラス宣言がスーパークラスに対する最初の参照であるため、例外はスローされません。
例3-18 最初にスーパークラスの参照があるファクト・クラス宣言を含むmatchVehicleルール
clear; fact class Vehicle; assert(new Car()); assert(new Truck()); rule matchVehicle { if (fact Vehicle v) { if (v instanceof Car) { println("car"); } else { println("truck"); } } } run(); // prints "truck" then "car"
Javaクラスのサンプル
ファクトでは多重継承はサポートされません。例3-19に示されたJavaクラスとインタフェースについて考えてみます。
例3-19 Javaクラスと多重継承の例
package example; public class Car {} public interface Sporty {} public class SportsCar extends Car implements Sporty {}
ファクトに対するMultipleInheritance例外のサンプル
コマンドラインで入力された例3-20の結果、MultipleInheritanceException
をラップするTypeCheckException
がスローされます。TypeCheckException
でgetCause
メソッドを使用すると、ラップされたMultipleInheritanceException
例外を取得できます。
例3-20 ファクトに対するMultipleInheritance例外
import example.*; fact class Sporty; fact class Car; fact class SportsCar; // throws TypeCheckException wrapping a MultipleInheritanceException
RLランタイム例外のサンプル
例3-21は、Oracle Rules Engineでrx8
オブジェクトをアサートしようとしたときに、その実際の型がObject
ではなくSportsCar
であることが検出された場合に、実行時に発生する例外を示しています。MultipleInheritanceException
を回避するには、ファクト・クラス・コンテキストでSporty
を使用するかまたはCar
を使用するかを選択する必要があります。両方を使用することはできません。
例3-21 MultipleInheritanceExceptionをラップするRLRuntimeException
import example.*; fact class Sporty; fact class Car; Object rx8 = new SportsCar(); assert(rx8); // throws RLRuntimeException wrapping a MultipleInheritanceException
FactClassExceptionのサンプル
例3-22 FactClassExceptionの考えられる原因
oracle.rules.rl.FactClassException: fact class for 'X' should be declared earlier in rule session
ファクト・コンテキスト・ルール
XがYのサブクラスまたはサブインタフェースである場合、Yはファクト・コンテキストでXの前に出現する必要があります。ファクト・コンテキストは、fact-class宣言、ルール・ファクト・パターン、またはassert、assertXPath、retractの引数です。
場合によっては、ファクト・コンテキストを考慮する必要があります。たとえば、次のようなXMLスキーマがあるとします。
<schema> <element name=A type=T/> <complexType name=T> <sequence> <element name=B type=T/> </sequence> </complexType> </schema>
JAXBでは次のように生成されます。
interface T { List getB(); // List has TImpl objects } interface A extends T; class AImpl implements A extends TImpl; class TImpl implements T;
ファクト・コンテキスト内の出現順が次のようになる例の場合
-
fact
class
T
-
assertXPath
AImpl
-
assert
TImpl
(assertXPath
実装で内部的に実行)
AImpl
は順序付けでTImpl
より前にありますが、AImpl
はTImpl
を拡張し、このため例外が発生します。このファクト・コンテキストの修正は、ステップ2の前の任意の場所でfact class TImpl;
を明示的に発行することです。
3.7 import文
import文では、Javaクラスの参照時にパッケージ名修飾を省略できます。
使用上の注意
インポート・コマンドはルールセット内に配置でき、インポートのスコープがimportが置かれているルールセットであることを暗黙的に示しますが、実際にはグローバルに適用されます。たとえば、次のコードでインポートのスコープがルールセットに限定されている場合は、r2
のPrintWriter
参照はコンパイルされません。
class X { } ruleset rl { import java.io.*; rule A { if ( fact X ) {
@ PrintWriter pw = null; } } } ruleset r2 { rule B { if ( fact X ) { @ PrintWriter pw = null; } } }
3.8 Include文
URLで指定された位置のルールセットをインクルードします。
書式
include ::= include URL ;
ここで、URLは有効なUniform Resource Locatorです。
使用上の注意
file:
およびhttp:
スキームがサポートされています。
例
include file:example.rl;
3.9 式の使用
RL Languageの式では、一般的なJava構文が使用されます(これから説明するような多少の違いはあります)。次に例を示します。
(a + 1) * (b - 2)
式は条件またはアクションで使用しますが、いくつか制限事項があります。式は厳密に型指定されます。
3.9.1 ブール式
ブール式は、Javaと同じくtrue
またはfalse
です。
書式
boolean-expression ::= boolean-assignment
| boolean-expression ? boolean-expression : boolean-expression
| boolean-expression || boolean-expression
| boolean-expression && boolean-expression
| numeric-expression equal-op numeric-expression
| object-expression equal-op object-expression
| boolean-expression equal-op boolean-expression
| object-expression instanceof type-name
| numeric-expression relop numeric-expression
| string-expression relop string-expression
boolean-assignment ::= boolean-target-expression = boolean-expression
equal-op ::= == | != relop ::= < | > | <= | >= type-name ::= qname
使用上の注意
文字列に対して、<
はUnicode UCS2コード・ポイントの順序です。
オブジェクトに対して!=
を使用すると、オブジェクト参照が等価でないことはテストされず、equalsメソッドの否定になります。
次の文について考えてみます。
if (object1 != object2){}
これは、次の文と同じです。
if (! (object1.equals(object2)){}
Javaとは異なり、RL Languageはオブジェクト参照が等価であることのテストをサポートしていません。
例
例3-23に、RL Languageでのブール式の使用方法を示します。
例3-23 RLブール式
if ( (true ? "a" < "b" : false) && (1 == 0 || 1.0 > 0) && "x" instanceof Object ) { println("all true"); };
3.9.2 数式
数式では、Javaと同じく、他のオペランドが浮動小数点の場合、整数オペランドは浮動小数点に暗黙的に変換されます。表3-1に、その他の暗黙的な変換が示されています。
書式
numeric-expression ::= numeric-assignment
| boolean-expression ? numeric-expression : numeric-expression
| numeric-expression( + | - ) numeric-expression
| numeric-expression ( * | / | % ) numeric-expression
| numeric-expression ** numeric-expression
| ( numeric-cast ) numeric-expression
| ( + | - ) numeric-expression
| ( ++ | -- ) numeric-primary-expression
| numeric-primary-expression [ ++ | -- ]
numeric-assignment ::= numeric-target-expression ( = | += | -= | *= | /= | %= ) numeric-expression
numeric-cast ::= numeric
使用上の注意
表3-5は、numeric-expressionの優先順位を降順に示しています。
表3-5 式演算子の優先順位
記号 | カテゴリ | 説明 |
---|---|---|
|
後置インクリメントまたは後置デクリメント |
numeric-primary-expression [ ++ | -- ] |
|
前置インクリメントまたは前置デクリメント |
( ++ | -- ) numeric-primary-expression |
- + |
単項マイナスまたは単項プラス |
( + | - ) numeric-expression |
(タイプ) |
型キャスト |
( numeric cast ) numeric-expression |
|
指数 |
|
|
乗算または除算または剰余 |
numeric-expression ( * | / | % ) numeric-expression |
|
加算または減算 |
numeric-expression( + | - ) numeric-expression |
|
条件付き |
boolean-expression ? numeric-expression : numeric-expression |
|
代入演算子 |
numeric-target-expression ( = | += | -= | *= | /= | %= ) numeric-expression |
3.9.3 文字列式
Javaと同様に、式は連結演算子+
を使用して文字列に変換できます。RL Languageでは、Javaと異なり、配列が文字列に変換されるとき、配列の目次が文字列に変換され、配列の要素はカンマで区切られて中カッコで囲まれます。RL Languageクラスのインスタンスが文字列に変換されるときは、クラス名の後に、プロパティ値のペアが、カンマで区切られ、カッコで囲まれて表示されます。このRL Languageの機能は、ロギング、トレースおよびデバッグに便利です。
String
であるオペランドに+
演算子が適用されると、すべてのオペランドがStrings
に変換され、オペランドが連結されます。
書式
string-expression ::= string-assignment
| boolean-expression ? string-expression : string-expression
| string-expression + expression
| expression + string-expression
|
string-assignment ::= string-target-expression ( = | += ) string-expression
例
例3-24に、RL Languageでの文字列式の使用方法を示します。この例では、"1 2.0 true {1,2}"と出力されます。
例3-24 RL文字列式
int i = 1; double f = 2.0; boolean b = true; int[] v = new int[]{i, 2}; println(i + " " + f + " " + b + " " + v);
3.9.4 配列式
RL Languageの配列はJavaの配列と同様に動作しますが、1次元に制限されています。配列のベース型は、配列のメンバーの型です。すべてのメンバーが同じ型であることが必要です。配列の要素に配列を含めることができますが、これが可能であるのは、包含配列の型がObject[]
の場合のみです。
注意:
RL Languageではマルチディメンション配列は直接サポートされていません。
書式
array-expression ::= array-assignment
| boolean-expression ? array-expression : array-expression
| ( array-cast ) ( array-expression | object-expression )
array-assignment ::= array-target-expression = array-expression
array-cast ::= type
使用上の注意
array-castの型は配列型であることが必要です。
3.9.5 ファクト・セット式
fact-set-expressionでは、作業メモリーからのファクトの照合、フィルタ処理およびファクトを戻す処理が実行されます。fact-set-expressionはrule fact-set-conditionでのみ有効です。if
キーワードはfact-set-conditionを示しますが、fact-set-conditionはifアクションとは異なります。ルールのfact-set-conditionでは、fact-set-conditionと一致するファクト・セット内のすべての行が反復されます。ifアクションではブール式がテストされます。
書式
fact-set-condition ::= if fact-set-expression
fact-set-expression ::= fact-set-expression || fact-set-expression
| fact-set-expression && fact-set-expression
| fact-set-expression && boolean-expression
| exists fact-set-expression
| aggregate fact-set-pattern ::= fact [ ( property-pattern ( , property-pattern )* ) ] [ var ] local-object-variable local-object-variable ::= identifier property-pattern ::= property-name : field-pattern field-pattern ::= var local-property-variable | constraint
local-property-variable ::= identifier
simple-expression ::= string literal | object-target-expression | numeric literal | numeric-target-expression | boolean-literal | boolean-target-expression constraint ::= simple-expression property-name ::= name aggregate ::= aggregate fact-set-expression : aggregate-spec ( , aggregate-spec )* aggregate-spec ::= aggregate-function [ var ] identifier aggregate-function ::= average ( numeric-expression ) | sum ( numeric-expression ) | minimum ( comparable-expression ) | maximum ( comparable-expression ) | count () | collection ( object-expression ) | user-defined ( expression type Tin ) user-defined ::= qname
使用上の注意
fact-set-expressionでは、戻すファクトを制限できます。この制限には、制約としてfact-set-patternでsimple-expressionを使用するか、またはfact-set-expressionでサポートされている演算子を使用します。
fact-set-expressionには次のものを含めることはできません。
演算子の優先順位はJavaと同様です。優先順位を指定するにはカッコを使用します。次に例を示します。
fact person var p && (p.age < 21 || p.age > 65)
カッコがない場合は、p.age
のp
は未定義です(演算子の優先順位の詳細は表3-5を参照)。
local-object-variableまたはlocal-property-variableは、パターンに続いていて、&&
演算子で連結されるパターンに続くすべての式に対するスコープ内にあります。パターンがexists
, ||
または!
式に含まれていない場合は、変数もルールのaction-blockのスコープ内にあります。&&
'ed式では、戻されるファクトをフィルタ処理して、フィルタで除外されなかったファクトのみを戻すことができます。
ファクト・セット・パターン - 作業メモリーからのフェッチ
最も基本的なfact-set-expressionは、作業メモリーにアサートされている特定クラスのファクトの一部またはすべてを戻すfact-set-patternです。fact-set-patternでは、作業メモリーが検索され、特定クラスのファクト、およびプロパティ値にオプションのconstraintがあるファクトが検出されます。戻されるファクト・セットには、各一致ファクトに対する行が含まれます。各行を表すようにローカル行変数を定義するか、または行内のフィールドを表すようにローカル・フィールド変数を定義できます。ローカル行変数が指定されない場合は、各行を表すためにクラスのqnameの名前部分を使用できます(例3-28を参照)。
結合演算子
&&
演算子では、2つのfact-set-expressionオペランドのクロス積(結合)が定義されます。fact-set-expression &&
演算子の左側はファクト・セットであることが必要です。結合 演算子の右側は別のfact-set-expressionです。2つのファクト・セットに&&
演算子を適用した結果は結合ファクト・セットです。
フィルタ演算子
&&
演算子では、左側のfact-set-expression内のファクトの中で、右側のboolean-expressionと一致しないファクトを排除するフィルタ演算子が定義されます。フィルタの左側はfact-set-expressionであることが必要です。フィルタの右側は、boolean-expressionです。
フィルタの右側には、var
キーワードを使用して、左側で定義されている変数の参照を含めることができます。
和集合演算子
||
演算子では、2つのfact-set-expressionオペランドの和集合が定義されます。||
演算子をfact-set-expressionに適用するときは、次の点に注意してください。
-
式の
var
は、包含式の外部で参照できません。 -
||
は、その入力ファクト・セットの連結を戻しますが、生成されたファクト・セットの内容にはアクセスできません。したがって、||
は通常、!
またはexists
式で使用されます。条件内で最上位の||
を使用するかわりに、条件で定義されているvar
をaction-block
内で参照できるように、最上位の&&演算子で2つ以上のルールを使用することをお薦めします。
注意:
次の構成について考えてみます。
if (fact X || fact W) {}
X
とW
の両方がアサートされている場合、このルールは各ファクトごとに1回、合計2回起動されます。
空演算子
!
演算子では、fact-set-expressionが空であるかどうかがテストされます。!
をfact-set-expressionに適用するときは、次の点に注意してください。
-
式の
var
は、包含!
式の外部で参照できません。 -
!
演算子では、fact-set-expressionが空である場合は単一の行が戻されます。空でない場合は!
演算子では空のファクト・セットが戻されます。
存在(非空)演算子
exists
演算子では、fact-set-expressionが空でないかどうかがテストされます。
exists
演算子をfact-set-expressionに適用するときは、次の点に注意してください。
-
式の
var
は、包含exists
式の外部で参照できません。 -
exists
では、式が空でない場合は単一の行が戻されます。式が空の場合は、exists
では空のファクト・セットが戻されます。
varキーワード
var
を使用するときは、ファクトは、(元の名前を使用するのではなく)var
で定義された変数を使用してのみ参照可能であることに注意してください。したがって、次の例はaction.kind
が定義されていると仮定して動作します。
if (fact action) { println(action.kind); }
しかし、次の例の場合、var a
が定義された後では、action.kind
参照で構文エラーが発生します。これは、var a
の定義後はa.kind
を使用する必要があるためです。
if (fact action var a) { println(action.kind); }
集計
集計では次の関数がサポートされます。
表3-6 集計関数
関数 | 説明 |
---|---|
|
一致するファクトの平均を計算します。結果は |
|
一致するファクトの合計を計算します。結果は |
|
結果は |
|
一致するファクトの最小値を計算します。 |
|
一致するファクトの最大値を計算します。 |
|
結果はファクトの |
ユーザー定義 |
結果の型がToutのユーザー定義関数。 |
RL Languageでは、1つ以上の集計関数をfactRowCollection
に適用し、集計結果をパターン変数にバインドする集計パターンがサポートされています。通常のSQL組込み集計関数がサポートされており、ユーザー指定のJavaクラスが提供されている場合はユーザー定義の集計関数がサポートされます。
集計関数でプリミティブ型のラッパー型(Long、Doubleなど)を使用する場合、それらのラッパー型は、結果のバインド変数に適切なRAWプリミティブ型が設定されるように変換されます。
集計関数のファクト式が空の場合、ルールは起動されません。したがって、式に対する一致ファクトがない場合は、集計関数では、そのコンテキスト内で意味を持たない数値は戻されません。たとえば、サイズがゼロ(0)に設定されたプロパティを合計しても意味がありません。
たとえば、平均より高い給与が支払われている従業員の名前を出力します。
if fact Emp emp && aggregate fact Emp(salary: var sal) : average(sal) var avgSal && emp.salary > avgSal { println(emp.name); }
給与が$100,000を超える従業員の平均給与より高い給与が支払われている従業員の名前を出力します。
if fact Emp emp && aggregate fact Emp(salary: var sal) && Emp.salary > 100000 : average(sal) var avgSal && emp.salary > avgSal { println(emp.name); }
ユーザー定義の集計関数をサポートするには、次の内容を実装した、引数のないパブリック・コンストラクタを持つuser-defined
という名前のパブリック・クラスを用意します。
public interface IncrementalAggregate<Tin, Tout> extends Serializable { public void initialize(); public void add(Tin value); public void remove(Tin value); public Tout getResult(); public boolean isValid(); }
実装では次の起動順序をサポートする必要があります。
new (initialize (add|remove)+ isValid getResult)*
isValid
では、ユーザー定義の集計の結果が有効のときはtrue
、無効のときはfalse
が戻される必要があります。
例
例3-25は、値が1のすべてのCounter
ファクトに対してアクションがアジェンダに配置されることを示しています。
例3-25 Counter.valueに対するファクト・セット式
class Counter { int id; int value; } rule ex1a { if (fact Counter c && c.value == 1) { println("counter id " + c.id + " is 1"); } }
ファクト・セット制約のサンプル
例3-26は、constraintを使用して例3-25のルールを表す同等の方法を示しています。
例3-26 ファクト・セット制約の使用
rule ex1b { if (fact Counter(value: 1) c) { println("counter id " + c.id + " is 1"); } } assert(new Counter(id: 1, value: 99)); run(); // prints twice, once for each rule
ファクト・セットの無効な使用方法のサンプル
例3-27は、ファクト・セットの無効な使用方法を示しています。これは、c
が定義前に使用されているためです。
例3-27 ファクト・セットの無効な使用方法
rule ex2 { if (c.value == 1 && fact Counter c) { println("counter id " + c.id + " is 1"); } }
Counterファクトについて&&演算子を使用したファクト・セットのサンプル
例3-28は、プロパティa2==0
で、相当する最初の要素であるCounterと一致しないすべてのAttFacts
に対してアクションがアジェンダに配置されることを示しています。
例3-28 Counterファクトについて&&を使用したファクト・セットの使用
class AttFact {int a1; int a2;} rule ex3 { if (fact AttFact(a2: 0) && ! fact Counter(id: AttFact.a1)) { println(AttFact.a1); } } assert(new AttFact()); // will match because a1=a2=0 assert(new AttFact(a1: 1, a2: 0)); // will not match run(); // rule fires once
&&演算子を使用したファクト・セットのサンプル
例3-29は、条件if (fact Ca a && fact Cb(v: a.v) b)
が次のように解釈されることを示しています。
-
fact Ca a
では、a(v: 1), a(v: 2), a(v: 3)
を含んだファクト・セットが戻されます。 -
&&
演算子では、2つの行{a(v: 1),b(v: 1)}, {a(v: 2),b(v: 2)}
を含んだファクト・セットが戻されます。
例3-29 &&演算子を使用したファクト・セットの使用
class Ca {int v;} assert(new Ca(v: 1)); assert(new Ca(v: 2)); assert(new Ca(v: 3)); class Cb {int v;} assert(new Cb(v: 0)); assert(new Cb(v: 1)); assert(new Cb(v: 2)); rule r { if (fact Ca a && fact Cb(v: a.v) b) { println("row: " + a + " " + b); } } run(); // prints 2 rows
3.9.7 オブジェクト式
オブジェクトに対する式演算子は、代入とキャストのみです。
書式
object-expression ::= object-assignment | ( ob-cast ) object-expression | boolean-expression ? object-expression : object-expression
object-assignment ::= object-target-expression = object-primary-expression
ob-cast ::= object-type
3.9.8 1次式
1次式には、変数、プロパティ、配列要素、クラス・メンバー、およびその他の密バインディングの式構文(リテラル、メソッドや関数のコール、オブジェクトやファクトの構成など)の代入ターゲットが含まれます。構文は、記述されている場合を除いてJavaとほぼ同じです。
書式
primary-expression ::= array-primary-expression
array-primary-expression ::=
| (配列を戻す)function-call
| (1次元のJava配列を戻す)method-call*
| ( array-expression )
array-constructor ::= new (
simple-type [ numeric-expression integer ]
| numeric [ ] { numeric-expression ( , numeric-expression )* }(数式は暗黙的にベースに変換可能であることが必要)
| boolean [ ] { boolean-expression ( , boolean-expression )* }
| object-type [ ] { object-expression ( , object-expression )* }
)
array-target-expression ::=
qname(配列型の変数)
| (配列型の)member
| array-primary-expression(ベース型はObject)[ numeric-expression int ]
string-primary-expression ::=
文字列リテラル(「リテラル」を参照)
| object-primary-expression(オブジェクトはjava.lang.String)
string-target-expression ::= object-target-expression(オブジェクトはjava.lang.String)
numeric-primary-expression ::=
数値リテラル
| (数値を戻す)function-call
| (数値を戻す)method-call
| array-primary-expression . length
| ( numeric-expression )
numeric-target-expression ::=
qname(数値型の変数)
| (数値型の)member
| array-primary-expression(ベース型は数値) [ numeric-expression ]
boolean-primary-expression ::=
| (ブールを戻す)function-call
| (ブールを戻す)method-call
| ( boolean-expression )
boolean-literal ::= true | false
boolean-target-expression ::=
qname(ブール型の変数)
| (ブール型の)member
| array-primary-expression(ベース型はブール)[ numeric-expression int ]
object-primary-expression ::=
new class-definition-name ( [ expression ( , expression )* ] 引数リスト )
| new class-definition-name ( [ property-pattern ( , property-pattern )* ] プロパティと値のペア )
| (Javaオブジェクトを戻す)function-call
| (Javaオブジェクトを戻す)method-call
object-target-expression ::=
qname(オブジェクト型の変数)
| (Javaオブジェクト型の)member
| array-primary-expression(ベース型はオブジェクト) [ numeric-expression int ]
function-call ::= qname関数名 ( [ expression ( , expression )* ] 引数リスト )
method-call ::= object-primary-expression . identifier メソッド名 ( [ expression ( , expression )* ] 引数リスト )
member ::= object-primary-expression . identifier メンバー名
例
例3-30は、RL Languageリテラル構文(Javaと同じです)を示しています。
メソッドおよび関数はオーバーロードできます。ただし、Javaとは異なり、RL Languageでは、実際の引数リストとオーバーロード関数の照合に前詰め法が使用されます。
例3-30 リテラルの使用
String s = "This is a string." int i = 23; double f = 3.14; boolean b = false;
オーバーロードのサンプル
例3-31にオーバーロードの例を示します
例3-31 オーバーロード
function f(int i); function f(Object o); function f(String s); // can never be called f(1); // calls first f f("a"); // calls second f, because "a" is an Object
3.9.8.1 new
RL Languageクラスにはユーザー定義コンストラクタはありません。デフォルト・コンストラクタによって、プロパティはデフォルト値に初期化されます。RL Languageのnew
演算子では、一部のプロパティ値を指定できます(Java Beanのプロパティに対しても動作します)。
Java Beanのプロパティにはgetterはありsetterがない場合があります。このようなプロパティは変更できません。
例
例3-32 new演算子を使用した初期化
class C { int i = 1; int j = 2; } C c = new C(); println(c); // c.i == 1 and c.j == 2 c = new C(i: 3); println(c); // c.i == 3 and c.j == 2 c = new C(i: 0, j: 0); println(c); // c.i == c.j == 0
3.10 アクションおよびアクション・ブロック
Javaと異なり、RL Languageにはアクション・ブロックが必要であり、単一のセミコロンの終了アクションは許可されていません。
書式
action ::= action-block | if | while | for | try | synchronized | return | throw
使用上の注意
アクション・ブロックは、任意の数のローカル変数宣言とアクションです。変数は、同じアクション・ブロック内の後続の変数初期化式およびアクションで参照可能です。
RL Languageでは、Javaとは異なり、すべてのローカル変数が宣言時に初期化される必要があります。ローカル変数はファイナルにはできません。
終了するには、アクション内からSystem.exit(int)メソッドを起動できます。
例
例3-33 アクション・ブロックの例
RL> { int i = 2; while (i-- > 0) { println("bye"); } } bye bye RL>
3.10.1 if elseアクション・ブロック
if elseアクションを使用すると、テストがtrue
の場合は最初のアクション・ブロックが実行され、テストがfalse
の場合はオプションのelse部分(別のifアクションまたはアクション・ブロックの場合があります)が実行されます。
Javaと異なり、RL Languageにはアクション・ブロックが必要であり、単一のセミコロンの終了アクションは許可されていません。
例3-34 if elseアクションの例
String s = "b"; if (s=="a") { println("no"); } else if (s=="b") { println("yes");} else { println("no"); }
例3-35 アクション・ブロックのない無効なifアクション
if (s=="a") println("no");
3.10.2 whileアクション・ブロック
3.10.3 forアクション・ブロック
RL Languageには、Javaと同じくforループがあります。forアクション・ブロックを使用すると、for-initが実行され、その後boolean-expressionがtrue
の間は、指定のアクション・ブロックが最初に実行された後、for-updateが実行されます。return、throwまたはhaltでアクション・ブロックを終了できます。
書式
for ::= for ( for-init ; boolean-expression ; for-update ) action-block
for-init ::= variable | for-update for-update ::= incr-decr-expression | assign | primary-expression
使用上の注意
RL Languageでは、for init
またはfor update句内でカンマ区切りの式リストは使用できません(Javaでは使用できます)。
例
例3-38は、int[]
をdouble[]
に変換するRL Languageコードを示しています。
例3-38 forアクション
int[] is = new int[]{1,2,3}; double[] fs = is; // error! double[] fs = new double[3]; for (int i = 0; i < is.length; ++i) { fs[i] = is[i]; } println(fs);
3.10.4 try catch finallyアクション・ブロック
最初のアクション・ブロックが実行されます。実行時にスローされた、catch句のThrowable
クラスと一致する例外が捕捉されます。最初の一致については、関連付けられたcatchアクション・ブロックが実行されます。Throwable
クラス・インスタンスが特定の識別子にバインドされ、catchアクション・ブロックで使用できるようになります。tryアクション・ブロックで例外がスローされるかどうかに関係なく、finallyアクション・ブロックが指定されている場合は、finallyアクション・ブロックが実行されます。
捕捉されない例外は、RL Languageコマンドラインを使用しているときはエラー・メッセージとして出力され、RuleSessionのexecuteRuleset
またはcallFunction
メソッドを使用しているときはRLExceptions
としてスローされます。RL Languageのtry
、catch
およびfinally
は、構文およびセマンティクスの両方においてJavaと類似しています。少なくとも1つのcatch
またはfinally
句が必要です。
書式
try ::= try action-block
( catch (class-implementing-throwable identifier ) action-block )* [ finally action-block ] class-implementing-throwable ::= qname
使用上の注意
RL Languageで例外を補足する方法を完全に理解するには、ルール実行時にスタック・フレームがどのようにネストされているかを理解する必要があります。ルールでは、関数またはメソッドで他の関数またはメソッドがコールされるように他のルールはコールされません。したがって、あるルールのアクション・ブロックでcatchブロックを使用して、別のルールのアクション・ブロックの例外を補足することはできません。ルール起動時にスローされた例外は、起動ルールのアクション・ブロックで処理されるか、またはルールの起動元であるrun、runUntilHaltまたはstep関数のコール元で処理される必要があります。
例
例3-39は、try catchおよびfinallyアクションを示しています。この例の実行結果は次のとおりです。
exception in invoked Java method this is really bad! but at least it's over!
RL Languageでは、明示的にスローされたException ("this is really bad!")
は、起動されたJavaメソッドの例外として処理され、Exception
はJavaException
にラップされます。明示的にスローされたException
は、JavaException
の原因として使用できます。
例3-39 try catchおよびfinallyアクション・ブロック
try { throw new Exception("this is really bad!"); } catch (Exception e) { println(e.getMessage()); println(e.getCause().getMessage()); } finally { println("but at least it's over!"); }
3.10.5 synchronizedアクション・ブロック
Javaと同様に、synchronizedアクションは複数のスレッドのアクションを同期化する際に役立ちます。synchronizedアクション・ブロックを使用すると、指定したオブジェクトのロックを取得してからaction-blockを実行し、実行後にロックを解放できます。
書式
synchronized ::= synchronized object-primary-expression action-block
例
例3-40は、Person
オブジェクトの名前を変更し、旧姓をニックネームに追加し、Javaオブジェクトの同時読取りユーザー(同時に同期化中)がPerson
の一貫したビューを参照するように同期化します(Person
Beanの詳細は例3-9を参照)。
例3-40 synchronizedアクション
import example.Person; // this Java bean is defined in example J1 function changeName(Person p, String first, String last) { synchronized(p) { java.util.Set s = p.getNicknames(); s.add(p.getFirstName()); s.add(p.getLastName()); p.setFirstName(first); p.setLastName(last); } assert(p); } Person person = new Person("Elmer", "Fudd", new String[]{"Wabbit Wuver"}); println(person.nicknames.toArray()); changeName(person, "Bugs", "Bunny"); println(person.nicknames.toArray());
3.10.6 modifyアクション
modifyアクションでは、関連付けられた式を使用して名前付きプロパティが更新されます。また、関連付けられたシャドウ・ファクト(ある場合)も更新され、更新対象プロパティを参照し、true
と評価される条件を含むルールがアクティブ化されます。更新対象プロパティを参照しない条件を含むルールはアクティブ化されません。
更新するオブジェクト引数は、すでにアサートされたオブジェクトであることが必要です。オブジェクトの値は更新され、ネットワークはスロット固有のセマンティクスで更新されます。結果として、オブジェクトとネットワークが一貫性のある状態になります。
書式
modify ::= modify (object-expression , property-update ( , property-update )* )
property-update ::= property-name : expression.
使用上の注意
通常、ファクトには、ルールによって設定または変更されるプロパティがあります。たとえば、あるアプリケーションの顧客には、""、"silver"または"gold"のステータスが設定されます。このステータスは、顧客の他のプロパティや関連ファクト(過去の注文など)を調べるルールによって設定されます。こうした計算されたプロパティをさらにルール条件で使用することも一般的です。たとえば、goldの顧客には10%の割引を与える場合があります。ファクトを変更しそのファクトを再アサートするルールでは、ルール自体が何度も繰り返してリアクティブされないように、追加の条件を付加する必要があります。たとえば、次のルールは1回起動されると、その後何度も繰り返して起動されます。
if fact Customer c && c.pastYearSpend > 1000 { c.status = "gold"; assert(c); }
次のルール定義を使用すると、このループを修正できます。
if fact Customer c && c.pastYearSpend > 1000 && c.status != "gold" { c.status = "gold"; assert(c); }
例3-41では、ループは回避されますが、goldの顧客を検索するルールがアクティブ化されません。
例3-41は、不適切なルール・プログラミング例を示しています。問題は、顧客オブジェクトの値を変更しているにもかかわらず、シャドーである顧客ファクトの値を変更していないことにあります。modifyアクションを使用することで、オブジェクトとファクトを一緒に更新できます。modifyは、更新されたプロパティをテストするルールもアクティブ化しますが、更新されていないプロパティをテストするルールはアクティブ化しません。
if fact Customer c && c.pastYearSpend > 1000 { modify(c, status: "gold"); }
このルールは、テスト対象プロパティと変更対象プロパティが別々であるため、ループしません。このルールは、ステータス=="gold"をテストする後続のルールを起動するための推論で使用できます。
例3-41 避ける必要がある不適切なルール・プログラミング方法を示す例
if fact Customer c && c.pastYearSpend > 1000 { c.status = "gold"; }
無限ループ・ルール
次のルールは、無限ループを示す別のルールです。
所得が$50,000以上の従業員には、5%の昇給を適用します。
if Employee emp && emp.sal > 50000 { modify(emp, sal: sal * 1.05); }
このルールは、変更対象プロパティと同じプロパティ(sal
)をテストし、変更後にテストがtrue
となるため、modifyを使用しても自己トリガーします。この場合、ループを回避するために、次のようにraise
プロパティをテストに追加することもできます。
if Employee emp && emp.sal > 50000 && !emp.raise { modify(emp, sal: emp.sal * 1.05, raise: true); }
また、この場合のループを回避するために、raiseを処理するファクトを追加することもできます。次に例を示します。
public class RaiseGiven { Employee emp; // or possibly just an employee ID } if Employee emp && emp.sal > 500000 && !RaiseGiven(emp: emp) { modify(emp, sal: sal * 1.05); assert(new RaiseGiven(emp: emp)); }
3.10.7 returnアクション
returnアクションは、関数またはルールのアクション・ブロックから戻ります。
ルール内のreturnアクションはルールセット・スタックをポップするため、実行は現在ルールセット・スタックの最上部にあるルールセットからのアジェンダに対するアクティブ化に進みます。
ルールの実行がrunまたはstep関数で開始され、returnアクションによってルールセット・スタックから最後のルールセットが削除された場合、制御はrun
またはstep関数のコール元に戻されます。
ルールの実行がrunUntilHalt関数で開始された場合、returnアクションではルールセット・スタックから最後のルールセットは削除されません。最後のルールセットは、残っているアクティブ化がなくなったときにrunUntilHaltで削除されます。その後、Oracle Rules Engineは次のアクティブ化の出現を待機します。アクティブ化が出現すると、ルールセットの起動が再開される前に、ルールセット・スタックに最後のルールセットが配置されます。
書式
return ::= return [ return-value] ;
return-value ::= expression
関数にreturns
句がある場合、return-valueが指定され、その型がreturns
句で指定されている型であることが必要です。
使用上の注意
ルールまたはfunction
内でreturns
句が指定されていないreturnアクションでは、return-valueは指定しないでください。
3.10.8 throwアクション
例外がスローされます。例外は、java.lang.Throwable
を実装するJavaオブジェクトであることが必要です。スローされた例外は、try
アクション・ブロック内のcatchで捕捉できます。
3.10.9 assignアクション
RL Languageの代入は、Javaと同様に、アクションとして出現可能な式です。
書式
assign ::= assignment-expression ;
assignment-expression ::= boolean-assignment | numeric-assignment | string-assignment | object-assignment | array-assignment
例
例3-42は、RL Languageの代入式の使用方法を示しています。この例では"6 5
"と出力されます。
例3-42 代入式
clear; int i = 1; int j = 2; i += j += 3; println(i + " " + j);
3.10.10 インクリメントまたはデクリメント式
RL Languageのインクリメントまたはデクリメントは、Javaと同様に、アクションとして出現可能な式です。
書式
incr-decr ::= incr-decr-expression ;
incr-decr-expression ::= ( ++ | -- ) numeric-target-expression | numeric-target-expression ( ++ | -- )
例
例3-43は、RL Languageのデクリメント・アクションの使用方法を示しています。この例では"0
"と出力されます。
例3-43 デクリメント・アクション
clear; int i = 1; --i; println(i);
3.10.11 基本アクション
基本アクションは、関数コール、assertまたはJavaメソッド・コールなど、その二次的作用のために実行される基本的な式です。たとえば、println
関数は基本アクションとしてよく使用されます。
書式
primary-action ::= primary-expression ;
3.11 ルールグループ
ルールグループでは、デシジョン表のオーバーライドがサポートされます。これにより、1つのルールで1つ以上の別のルールをオーバーライドするというデシジョン表の機能がサポートされます。
書式
rulegroup ::= rulegroup rulegroup-name { rulegroup-property* ( rule | rulegroup )* } rulegroup-name ::= identifier rulegroup-property ::= mutex mutex ::= mutex = boolean-literal ;
使用上の注意
ルールグループ構成は、ルールセットの最上位の構成です。ルールグループには、オプションのbooleanプロパティがあります。
-
mutex: mutexプロパティでは、ルール間での相互排他が可能です。mutexをtrueに設定した同一のルールグループに複数のルールが存在する場合がよくあります。より複雑なルールグループ階層の場合、最も近くにある共通の祖先のルールグループのmutexをtrueに設定すると、2つのルールが相互に除外されます。ルールが起動されると、相互に除外されるルールの既存のアクティブ化がアジェンダから削除され、起動されなくなります。これらのアクティブ化は、それらをアジェンダに配置した一連のファクトによる識別どおりに直接関連付ける必要があります。このことから、相互に除外されるすべてのルールの条件は、同じ順序で指定された同じファクト句を持つという要件が生じます。当然デシジョン表の場合も必要です。
例
例3-44は、mutexプロパティを持つルールグループの使用方法を示しています。r2およびr3は、ルール条件内で同じファクト・タイプ・セットを同じ順序で参照していることに注意してください。これはmutexグループ内で必要になります。パターン内のテストは同じでなくてもかまいません。mutexグループ内のルール条件の形状に関する制限は、下位グループにも適用されます。したがって、ルールr4とr5も同じファクト・タイプ・セットを同じ順序で参照する必要があります。Aの1つのインスタンスとBの1つのインスタンスがアサートされており、r1、r2、r3、r4およびr5はアジェンダにアクティブ化があるとします。r3は優先度が高いため起動されます。r2はmutex=trueのグループ内にあるため、r2のアクティブ化は起動することなく削除されます。group2はgroup1のメンバーであるため、r4とr5のアクティブ化も起動することなく削除されます。ルールr1は起動します。ここで、r2、r4およびr5はアジェンダにアクティブ化があり、r4が最初に起動するとします。相互に起動するgroup2内のルールはr2とr3の両方を除外するため、r2のアクティブ化は起動することなく削除されます。r5は起動します。group2にはmutex=trueがないため、相互に排除されることはありません。
例3-44 ファクト参照順序が指定されたルールグループを含むルールセット
ruleset set1 { rule r1 { ... } rulegroup group1 { mutex = true; rule r2 { if fact A && fact B ... { ... }} rule r3 { priority = 2; if fact A && fact B ... { ... }} rulegroup group2 { rule r4 { if fact A && fact B ... { ... }} rule r5 { if fact A && fact B ... { ... }} } } }
3.12 組込み関数
この項では、次のRL Language組込み関数について説明します。
assert、assertTree、assertXPath、clearRule、clearRulesetStack、clearWatchRules_ clearWatchActivations_ clearWatchFacts_ clearWatchFocus_ clearWatchCompilations_ clearWatchAll、contains、getCurrentDate、getDecisionTrace、getDecisionTraceLevel、getDecisionTraceLimit、getEffectiveDate、getFactsByType、getRulesetStack、getRuleSession、getStrategy、halt、id、isErrorInRuleConditionSuppressedobject、println、popRuleset、pushRuleset、retract、reset、run、runUntilHalt、setCurrentDate、setDecisionTraceLevel、setDecisionTraceLimit、setEffectiveDate、setRulesetStack、setStrategy、showActivations、showFacts、step、watchRules_ watchActivations_ watchFacts_ watchFocus_ watchCompilations
3.12.1 assert
提供オブジェクトobjのプロパティに基づいて、ファクトを作業メモリーに追加するか、またはすでに作業メモリーにあるファクトを更新します。提供オブジェクトobjがJavaインスタンスの場合、プロパティは、関連付けられたBeanInfo
クラスまたはgetterメソッドとsetterメソッドの存在によって定義されるJava Beanプロパティです。objがRL Languageクラス・インスタンスの場合、プロパティはクラスのフィールドです。
書式
function assert(Object obj);
使用上の注意
作業メモリー内のファクトは、提供オブジェクトobjのシャドウであり、このシャドウには、各プロパティpropのコピー、クローンまたは参照が含まれています。propがプリミティブ型である場合、propはシャドウのコピーです。propでJava Cloneable
インタフェースが実装される場合、propのクローン(シャロー・コピー)がシャドウ化されます。それ以外の場合、propの参照のみがシャドウ化されます。シャドウでそのオブジェクトのプロパティをコピーできる量が多いほど、複数のファクトに関するルールがより最適化されます。
RL LanguageでObject
に適用されるときの==
および!=
では、常にObject
equalsメソッドが起動されるため、シャドウにコピー、クローンまたは参照が含まれているかどうかは、RL Languageプログラムには透過的です。
アサートはアジェンダに影響を与える可能性があります。新規ファクトが原因でファクト・セットが戻されるようになった条件があるルールによって、アクティブ化がアジェンダに配置されます。!
を使用してファクトが存在しないことをテストするアクティブ化が、アジェンダから削除される可能性があります。ファクトの更新はアジェンダに影響を与える場合があります。変更されたファクトと一致しなくなったルール条件があるアクティブ化は、アジェンダから削除されます。変更されたファクトが原因でファクト・セットが戻される条件があるルールによって、アクティブ化がアジェンダに配置されます。
アサートは、objの状態の一部が更新され、ルール条件に影響を与える可能性がある場合に、作業メモリー内のファクトを更新するために使用してください。ただし、objがJava Beanであり登録プロパティ変更リスナーをサポートしている場合、および変更内容がすべてBeanプロパティの値である場合を除きます。
例3-45 highestSalaryルールでのassert関数の使用
class Emp { String ename; double salary; } rule highestSalary { if (fact Emp hi && !(fact Emp e && e.salary > hi.salary)) { println(hi.ename + " has highest salary " + hi.salary); } } Emp e1 = new Emp(ename: "Pavi", salary: 55000.00); assert(e1); // put in working memory Emp e2 = new Emp(ename: "Fred", salary: 60000.00); assert(e2); // put in working memory e1.salary += 10000.00; // Pavi is now the highest paid assert(e1); // MUST re-assert before allowing rules to fire run();
assert関数のサンプル
例3-46 emptyDeptルールでのassert関数の使用
import java.util.*; class Dept { int deptno; List emps = new ArrayList(); } rule emptyDept { if (fact Dept d && d.emps.isEmpty()) { println("dept " + d.deptno + " has no employees!"); } } Dept d = new Dept(deptno: 10); d.emps.add(e1); assert(d); // put in working memory with 1 employee d.emps.remove(0); assert(d); // MUST re-assert before allowing rules to fire run();
関連項目
3.12.2 assertTree
assertTree組込み関数では、オブジェクト・ツリーのオブジェクトがファクトとしてアサートされます。
assertTree組込み関数では、JAXB 2.0がサポートされます。
書式
assertTree(Object root) assertTree(String spec, Object root)
使用上の注意
assertTree()シグネチャには、次の2つがあります。
-
assertTree(Object root)はSDK2で必要になります。このフォーマットは、オブジェクト・グラフを横断し、SDK2によって生成された内部メタデータの指示に従ってオブジェクトをアサートします。
-
assertTree(String spec, Object root)は、SDK2を起動していないときに必要になります。assertXPathと同様、specは、複数のパッケージをコロンで区切って指定できるように拡張されたパッケージ仕様です。このフォーマットでは、指定したパッケージのいずれかにオブジェクトが含まれる場合に、オブジェクトがアサートされ、オブジェクトのBeanプロパティが横断されます。通常、このパッケージ仕様は、JAXBContextを設定するときに使用されるものと同じです。
assertTree関数では、次のことが実行されます。
-
ルートで始まるオブジェクト、およびそのルートから参照されるすべてのファクト(参照可能なファクト・タイプが宣言されているオブジェクト)を再帰的にアサートします。
-
検出されたJAXBElementインスタンスをアサートし、それに含まれる値クラス・オブジェクトを抽出して続行します。
関連項目
3.12.3 assertXPath
assertXPath関数は非推奨です。かわりにassertTreeを使用してください。
ルートとして指定した要素とXMLのxpathに似た式を使用して、ファクトのツリーを作業メモリーに追加し、ツリー内のオブジェクトを定義します。pkgは、ツリー内のオブジェクトのクラスが含まれるJavaパッケージまたはRL Languageルールセットです。ツリー内のすべてのオブジェクトが同じパッケージまたはルールセット内に存在する必要があります。
要素および選択した子をアサートする以外に、親オブジェクトと子オブジェクトをリンクするXLinkファクトがアサートされます。ツリー内のすべてのオブジェクトのクラスで、RLクラス(rl-class-definition)またはfact-class宣言のsupports xpath(supports)句を使用する必要があります。
書式
function assertXPath(String pkg, Object 要素, String xpath);
3.12.4 clearRule
名前付きのルールをルール・セッションから消去します。ルールのアクティブ化はすべてアジェンダから削除されます。
書式
function clearRule(String 名前);
関連項目
3.12.6 clearWatchRules、clearWatchActivations、clearWatchFacts、clearWatchFocus、clearWatchCompilations、clearWatchAll
clearWatch関数は、デバッグ情報の出力を停止します。
書式
function clearWatchRules(); function clearWatchActivations(); function clearWatchFacts(); function clearWatchFocus(); function clearWatchCompilations(); function clearWatchAll();
3.12.7 contains
contains()
関数はJava Collection
のcontains()
メソッドに似ていますが、コレクション内のJAXBElementの存在を処理する機能を持っています。
書式
contains(Collection c, Object o) returns boolean
使用方法
contains()
は、コレクションc
内でJAXBElementを検出すると、そのJAXBElementから値クラスを取得して、オブジェクトo
と比較します。
関連項目
3.12.8 getCurrentDate
getCurrentDate関数では、CurrentDateファクトに関連付けられている日付が戻されます。
書式
getCurrentDate() returns Calendar
使用上の注意
有効日と現在の日付は、直交する2つのアイテムです。有効日は、有効開始日および有効終了日のプロパティに従って有効になっているルールを判別するのに使用します。CurrentDateファクトでは、ルール・エンジンが管理している現在の日付を表すファクトを推論の対象にできます。
現在の日付を設定しても、有効日のセマンティクスには影響を与えません。
日付を推論の対象にするためのルールをルール内に明示的に作成する場合は、CurrentDateファクトを使用します。有効開始日または有効終了日、あるいはその両方をルールに割り当て、データ内の日付から判別されるルールを有効にする場合は、setEffectiveDate()
を使用します。
3.12.9 getDecisionTrace
現在のトレースを戻し、新しいトレースを開始します。
書式
getDecisionTrace() returns DecisionTrace
使用上の注意
3.12.10 getDecisionTraceLevel
現在のデシジョン・トレース・レベルを取得します。
書式
getDecisionTraceLevel() returns int
使用上の注意
サポートされているデシジョン・トレース・レベルには、次のレベルが含まれます。
-
オフ: デシジョン・トレースは無効です。これは、
RuleSession.DECISION_TRACE_OFF
として定義されます。 -
本番: 起動されたルールがトレースに表示されます。これは、
RuleSession.DECISION_TRACE_PRODUCTION
として定義されます。 -
開発:
watchAll()
によく似た詳細なデシジョン・トレース。これは、RuleSession.DECISION_TRACE_DEVELOPMENT
として定義されます。
3.12.11 getDecisionTraceLimit
トレース内のイベント数に対する現在の制限値を戻します。
書式
getDecisionTraceLimit() returns int
使用上の注意
3.12.12 getEffectiveDate
getEffectiveDate関数では、有効日の現在値が戻されます。
書式
getEffectiveDate() returns Calendar
使用上の注意
有効日と現在の日付は、直交する2つのアイテムです。有効日は、有効開始日および有効終了日のプロパティに従って有効になっているルールを判別するのに使用します。CurrentDateファクトでは、エンジンが管理している現在の日付を表すファクトを推論の対象にできます。どちらも明示的に設定できます。
現在の日付を設定しても、有効日のセマンティクスには影響を与えません。有効日を設定しても、CurrentDateファクトには影響を与えません。
日付を推論の対象にするためのルールをルール内に明示的に作成する場合は、CurrentDate (setCurrentDate()
)を使用します。有効開始日または有効終了日、あるいはその両方をルールに割り当て、データ内の日付から判別されるルールを有効にする場合は、setEffectiveDate()
を使用します。
3.12.13 getFactByType
この関数では、作業メモリー内にインスタンスが1つのみ存在するときに、classNameで識別されるファクト・タイプが戻されます。存在しない場合は、nullが戻されます。作業メモリー内にそのファクト・タイプの複数のインスタンスが存在する場合、例外がスローされます。
書式
function getFactByType(String className) returns Object
関連項目
3.12.14 getFactsByType
指定したクラスのインスタンスである、作業メモリー内のすべてのファクトのリストが戻されます。
書式
function getFactsByType(String className) returns List
3.12.15 getRulesetStack
ルールセット・スタックをルールセット名の配列として戻します。
書式
function getRulesetStack() returns String[];
使用上の注意
戻り値: ルールセット名の配列としてのルールセット・スタック
スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。
3.12.16 getRuleSession
Java RuleSession
オブジェクトを戻します。RL Languageプログラムでは、このRuleSession
を使用して、新規のクラス、ルール、関数または変数を動的に定義できます。
書式
function getRuleSession() returns RuleSession;
例
rule learn { if (fact f1 && …) { RuleSession rs = getRuleSession(); rs.executeRuleset("rule newRule { if fact f1 && fact f2 && … { … } }"); } }
関連項目
3.12.18 halt
halt関数では、現在起動中のルールの実行が停止され、停止されたルールの実行元であるrun、runUntilHaltまたはstep関数に制御が戻されます。アジェンダはそのままであるため、後続のrun、runUntilHaltまたはstepを実行するとルールの起動を再開できます。
halt関数は、run、runUntilHaltまたはstep関数のコンテキスト外で起動された場合は効果がありません。
書式
function halt();
関連項目
3.12.20 isErrorInRuleConditionSuppressed
エラーの抑制は、ルール条件の各テストで発生します。各テストは個別に評価されます。評価中にエラーが発生したときにエラーの抑制を有効にした場合は、エラーが抑制されます。テストの評価中にエラーが発生したということは、テストの結果が不明であることを意味します。内部的には、この状態(true/false/unknown、http://en.wikipedia.org/wiki/Three-valued_logicを参照)を表すために、ルール・エンジンで3値ロジックが使用されます。true/falseの値が必要な場合、unknown値がfalseにマッピングされます。
テスト中のエラーは、RLドメイン(エンジンで検出される)またはJavaドメイン(テストで呼び出したJavaメソッドによってスローされる)のいずれかで発生します。RLドメインでは、RL式でnullオブジェクト参照を逆参照しようとすることにより発生する、RLNullPointerException
が最も一般的なエラーです。RLArithmeticException
(整数のゼロによる除算)とRLIllegalArgumentExceptionは、ほとんど発生しません。RLArrayIndexOutOfBoundsException、RLClassCastException
およびRLCloneNotSupportedException
は、ごくまれに発生します。
Javaドメインの例外は、ルール条件から呼び出したJavaメソッドによってスローされる例外です。これらの例外は、RL例外JavaException
でラップされ、getCause()で取得できるメソッドでスローされます。Javaメソッドによってスローされた例外は、エンジンでさらに判別できません。たとえば、null値が渡されたことにより、メソッドで例外がスローされた可能性がある場合でも、ルール・エンジンには、nullが原因であるかどうかを知る方法がありません。
エラーの抑制は、組込み関数を呼び出すことで制御できます。一般的な呼出し元は、デシジョン関数の初期アクションです。
書式
isErrorInRuleConditionSuppressed() returns boolean
使用上の注意
RLのシグネチャ: isErrorInRuleConditionSuppressed() returns boolean
3.12.21 isRulesetsOnStackOnce
このルール実行設定の現在値を返します。
書式
function isRulesetsOnStackOnce() returns boolean
関連項目
setRulesetsOnStack
3.12.23 println
特定の値をRuleSession出力ライターに出力します。
書式
function println(char c);
function println(char[] ca);
function println(int i);
function println(long l);
function println(float f);
function println(double d);
function println(boolean b);
function println(Object obj);
3.12.24 popRuleset
スタックが空の場合、popRuleset
ではRLRuntimeException
がスローされます。スタックが空でない場合、popRuleset
ではスタックからフォーカスが削除され、戻されます。
すべてのエントリの位置が1つずつ下に移動します。新しいフォーカスは、スタックの新しい最上位であるエントリ0(ゼロ)です。
スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。
書式
function popRuleset() returns String;
例3-47 popRulesetの使用とRLRuntimeExceptionのスロー
clearRulesetStack(); popRuleset(); // RLRuntimeException
3.12.25 pushRuleset
特定のルールセットをスタックに追加し、そのルールセットをフォーカスにします。すでにフォーカスであるルールセットを追加するとエラーが発生します(このエラーについてはRLIllegalArgumentException
がスローされます)。
スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。
書式
function pushRuleset(String focus);
例3-48 pushRulesetの使用 - RLIllegalArgumentExceptionのスロー
clearRulesetStack(); pushRuleset("main"); // focus is "main" pushRuleset("main"); // RLIllegalArgumentException
例3-49 popRulesetの使用 - RLRuntimeExceptionのスロー
clearRulesetStack(); popRuleset(); // RLRuntimeException
3.12.27 reset
作業メモリーからすべてのファクトを消去し、アジェンダからすべてのアクティブ化を消去して、非ファイナル・グローバル変数の初期化式を再評価します。
書式
function reset();
関連項目
3.12.28 run
アジェンダに存在するルール・アクティブ化を、次の条件に該当するまで起動します。
-
ルール・アクションでhaltが直接または間接的にコールされるまで。たとえば、ルール・アクションによってコールされた関数でhaltがコールされる場合です。
-
アジェンダが空になるまで。
-
ルールセット・スタックが空になるまで。
書式
function run() returns int;
function run(String rulesetName) returns int;
使用上の注意
引数rulesetNameが指定された場合は、ルールの起動前に、名前付きルールセットがルールセット・スタックの最上位に追加されます。
nullのrulesetNameが指定された場合、ルールセット・スタックはルールの起動前に変更されません。
rulesetNameが指定されず、デフォルトのmain
ルールセットがルールセット・スタック上に存在しない場合は、ルールの起動前に、main
がルールセット・スタックの最下位に配置されます。
戻り値: int
。起動されたルールの数。
関連項目
3.12.29 runUntilHalt
この関数では、haltがコールされるまでルール・アクティブ化が起動されます。runおよびstepとは異なり、runUntilHaltは、アジェンダが空になっても戻りません。また、runUntilHaltでは、ルールセット・スタックから最下位のルールセット名は削除されません。かわりに、アジェンダにアクティブ化が格納されるのを待機します。
書式
function runUntilHalt() returns int;
使用上の注意
メインのRuleSessionスレッドがビジーであるときにアクティブ化をアジェンダに追加する唯一の方法であるrunUntilHaltの実行は、2番目のスレッドに対して行われ、次のいずれかが実行されます。
-
PropertyChangeListeners
を使用したJava Beanファクトの変更 -
assertまたは
retract
関数の実行
runUntilHaltの使用時はルールを注意して設計する必要があります。たとえば、プロパティが最小値のファクトを検出しようとするルールは、ファクトの最初のインスタンスがアサートされたときに起動され、その後は、それより小さい値のプロパティが設定された別のインスタンスがアサートされるたびに起動されます。
3.12.30 setCurrentDate
setCurrentDate
関数では、エンジンが管理している現在の日付を表すファクトを推論の対象にするための日付が設定されます(CurrentDate
ファクトを使用)。
書式
setCurrentDate(Calendar newDate)
使用上の注意
RLIllegalArgumentException
例外は、newDate引数がnullの場合にスローされます。
ルール内で日付を明示的に推論の対象にする必要がある場合は、CurrentDate
ファクトを使用します。有効開始日および有効終了日をルールに割り当て、データ内の日付から判別されるルールを有効にする場合は、setEffectiveDateを使用する必要があります。setEffectiveDate関数は、CurrentDate
ファクトに影響を与えません。
デフォルトでは、現在の日付の値はルール・エンジンが暗黙的に管理します。CurrentDate
ファクトの値は現在のシステム日付に更新され、組込み関数のrunファミリが起動されると、内部的に(再)アサートされます。これは、新しい現在の日付がルール条件で評価されるように、ルールが起動される前に行われます。runUntilHaltの場合は、アジェンダにあるルールが0個から1個以上に遷移するたびに、この更新が実行されます。
一度setCurrentDate
関数を呼び出すと、現在の日付を必要に応じて更新する作業はユーザーの役割になります。ルール・エンジンでは、有効日が暗黙的に管理されなくなります。この状態は、reset関数を起動するまで存続します。setCurrentDate
を使用して現在の日付を明示的に設定した場合、時間を逆戻りさせる(前の時点に設定される)ことになるsetCurrentDate
関数を起動すると、必ずエラーが発生し、RLIllegalArgumentException
がスローされます。reset関数を起動すると、現在の日付が任意の値に設定される場合があります。
3.12.31 setDecisionTraceLevel
デシジョン・トレース・レベルを指定したレベルに設定します。
書式
setDecisionTraceLevel(int level)
使用上の注意
サポートされているデシジョン・トレース・レベルには、次のレベルが含まれます。
-
オフ: デシジョン・トレースは無効です。これは、
RuleSession.DECISION_TRACE_OFF
として定義されます。 -
本番: 起動されたルールがトレースに表示されます。これは、
RuleSession.DECISION_TRACE_PRODUCTION
として定義されます。 -
開発:
watchAll()
によく似た詳細なデシジョン・トレース。これは、RuleSession.DECISION_TRACE_DEVELOPMENT
として定義されます。
3.12.32 setDecisionTraceLimit
トレース内のイベント数の制限値を設定します。
書式
setDecisionTraceLimit(int count)
使用上の注意
デフォルト値は10000です。
3.12.33 setEffectiveDate
setEffectiveDate関数では、ルール・エンジンの有効日が更新されます。
デフォルトでは、有効日の値は、ルール・エンジンによって暗黙的に管理されます。この場合、組込み関数のrunファミリが起動されると、有効日が現在のシステム日付に更新されます。これは、任意のルールが起動される前に実行されます。そのため、新しい有効日は、ルールの起動が開始される前に適用されます。runUntilHalt
の場合は、アジェンダにあるルールのアクティブ化が0個から1個以上に遷移するたびに、この更新が実行されます。
書式
setEffectiveDate(Calendar newDate)
使用上の注意
有効日を変更する唯一の方法は、setEffectiveDateを起動することです。reset関数を起動すると、有効日は任意の値に設定される場合があります。
RLIllegalArgumentException
例外は、newDate引数がnullの場合にスローされます。
一度setEffectiveDate関数を呼び出すと、有効日を必要に応じて更新する作業がアプリケーションの役割になります。ルール・エンジンでは、有効日が暗黙的に管理されなくなります。
この状態は、reset関数を起動するまで存続します。
これは、デバッグや特定時点でのルール評価の実行、または有効日をアプリケーションで制御する必要があるその他のユースケースで役立ちます。
3.12.34 setErrorInRuleConditionSuppressed
エラーの抑制は、ルール条件の各テストで発生します。各テストは個別に評価されます。評価中にエラーが発生したときにエラーの抑制を有効にした場合は、エラーが抑制されます。テストの評価中にエラーが発生したということは、テストの結果が不明であることを意味します。内部的には、この状態(true/false/unknown、http://en.wikipedia.org/wiki/Three-valued_logicを参照)を表すために、ルール・エンジンで3値ロジックが使用されます。true/falseの値が必要な場合、unknown値がfalseにマッピングされます。
テスト中のエラーは、RLドメイン(エンジンで検出される)またはJavaドメイン(テストで呼び出したJavaメソッドによってスローされる)のいずれかで発生します。RLドメインでは、RL式でnullオブジェクト参照を逆参照しようとすることにより発生する、RLNullPointerException
が最も一般的なエラーです。RLArithmeticException
(整数のゼロによる除算)とRLIllegalArgumentExceptionは、ほとんど発生しません。RLArrayIndexOutOfBoundsException、RLClassCastException
およびRLCloneNotSupportedException
は、ごくまれに発生します。
Javaドメインの例外は、ルール条件から呼び出したJavaメソッドによってスローされる例外です。これらの例外は、RL例外JavaException
でラップされ、getCause()で取得できるメソッドでスローされます。Javaメソッドによってスローされた例外は、エンジンでさらに判別できません。たとえば、null値が渡されたことにより、メソッドで例外がスローされた可能性がある場合でも、ルール・エンジンには、nullが原因であるかどうかを知る方法がありません。
エラーの抑制は、組込み関数を呼び出すことで制御できます。一般的な呼出し元は、デシジョン関数の初期アクションです。
書式
setErrorInRuleConditionSuppressed(boolean bv) returns boolean
使用上の注意
RLのシグネチャ: setErrorInRuleConditionSuppressed(boolean bv) returns boolean
true値を渡すと、エラーの抑制が有効になります。戻り値は以前の設定です。
現在の設定は、isErrorInRuleConditionSuppressed組込み関数で問合せ可能です。
3.12.35 setRulesetStack
ルールセット・スタックをルールセット名の特定の配列に設定します。
スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。
書式
function setRulesetStack(String[] rulesetStack
3.12.36 setRulesetsOnStack
true値を設定したこの関数の呼出しは、スタックにプッシュされるルールセットが、ルールの実行中に一度しかスタックにプッシュされないことを示します。前の値は返されます。デフォルト値はfalseです。
書式
function setRulesetsOnStackOnce(boolean bv) returns boolean
関連項目
isRulesetsOnStackOnce
3.12.37 setStrategy
戦略では、同じルールセット内の優先度が同じアクティブ化の実行順序が指定されます。表3-7は、有効な戦略の値を示しています。
表3-7 setStrategyおよびgetStrategy関数の戦略の値
戦略 | 説明 |
---|---|
キュー |
アクティブ化は、古い方から順に起動されます。 |
stack |
アクティブ化は、新しい方から順に起動されます。 |
書式
function setStrategy(String strategy);
3.12.38 showActivations
show関数では、ルール・セッションの状態が出力ライターに出力されます。表示可能な状態は、アジェンダ上のすべてのアクティブ化です。
書式
function showActivations();
3.12.39 showFacts
show関数では、ルール・セッションの状態が出力ライターに出力されます。表示可能な状態は、作業メモリー内のすべてのファクトです。
書式
function showFacts();
3.12.40 step
アジェンダに存在するルール・アクティブ化を、次の条件に該当するまで起動します。
-
指定した数のルール・アクティブ化numRulesToFireが起動されるまで。
-
ルール・アクションでhaltが直接または間接的にコールされるまで。たとえば、ルール・アクションによってコールされた関数でコールされる場合です。
-
アジェンダが空になるまで。
-
ルールセット・スタックが空になるまで。
書式
function step(int numRulesToFire) returns int;
function step(int numRulesToFire, String rulesetName) returns int;
function step(int numRulesToFire, boolean errorIfLimitHit) returns int;
function step(int numRulesToFire, String rulesetName, boolean errorIfLimitHit) returns int;
使用上の注意
ルールセット名が指定されず、main
ルールセットがルールセット・スタック上に存在しない場合は、ルールの起動前に、main
ルールセットがルールセット・スタックの最下位に配置されます。
rulesetNameというルールセットが指定された場合は、ルールの起動前に、指定されたルールセットがルールセット・スタックの最上位に追加されます。nullのルールセット名が指定された場合、ルールセット・スタックはルールの起動前に変更されません。
戻り値: 起動されたルールの数。
コール元は最後の2つのシグネチャを使用することにより、起動の制限(numRulesToFire)に達したことをエラー条件として扱うかどうかを指定できます。デフォルトはfalseです。つまり、この制限に達することはエラー条件に適合しません。
errorIfLimitHit引数をtrue値に設定したstep関数の呼出しを使用することにより、記述したルールの不具合が原因で発生する可能性のある、ルール起動の無限ループを捕捉できます。
関連項目
3.12.41 watchRules、watchActivations、watchFacts、watchFocus、watchCompilations
watch関数は、重要なルール・セッション・イベントに関する情報の出力を有効にします。情報は、イベントが発生するたびに出力ライターに出力されます。出力を無効にするには、clearWatch関数を使用します。
表3-8で、使用可能なデバッグ情報について説明します。
表3-8 watch関数のイベントの説明
デバッグwatch | ルール・セッション・イベントの説明 |
---|---|
watch |
ルール・セッション・イベントの説明 |
ルール |
ルールの起動(アクティブ化の実行)に関する情報 |
アクティブ化 |
アジェンダに対するアクティブ化の追加または削除 |
ファクト |
作業メモリー内のファクトのアサート、取消しまたは変更 |
フォーカス |
ルールセット・スタックに対するルールセットの追加または削除。ルールセット・スタックの最上位は、フォーカス・ルールセットと呼ばれています。フォーカス・ルールセットのアジェンダにあるアクティブ化はすべて、フォーカスが削除される前に起動され、スタックの次のルールセットがフォーカスになります。 |
Compilations |
ルールの条件がReteネットワークに追加されると、既存のルールとの条件パーツの共有方法に関する情報が出力されます。"="は共有を示します。ルールの定義順序が共有に影響を与える場合があるため、パフォーマンスにも影響を与える可能性があります。 |
すべて |
watch Rules、watch Activations、watch Facts、watch Compilationsおよびwatch Focusで示される情報が含まれます。 |
書式
function watchRules();
function watchActivations();
function watchFacts();
function watchFocus();
function watchCompilations();
function watchAll();