この章には、Oracle Business Rules RL Language(RL Language)の構文、セマンティクスおよび組込み関数の完全なリファレンスが含まれています。
文法ルールでRL Languageが定義されています。各文法ルールでは、::=
記号の左側に記述された非終端記号が、::=
記号の右側に記述された1つ以上の非終端記号および終端記号に関して定義されています。
予約語
autofocus、boolean、break、catch、char、class、constant、continue、double、else、exists、extends、fact、false、final、finally、float、for、function、if、import、include、instanceof、int、logical、long、new、null、priority、property、public、query、return、returns、rule、ruleset、short、synchronized、throw、true、try、while、var
注意: 太字で記述されていない予約語(break、continueおよびqueryが該当)は、RL Languageの今後のリリースで使用される予定です。 |
ルールセットでは一連の定義がグループ化されます。ルールセットは、すべて同時に評価されることを意図したルールとその他の定義の集まりです。また、実行可能なアクションおよびその他のルールセットを含めたり、Javaのクラスやパッケージをインポートすることもできます。
書式
ruleset ::= named-ruleset | unnamed-ruleset
named-ruleset ::= ruleset ruleset-name { unnamed-ruleset }
unnamed-ruleset ::= ( import | include | named-ruleset | definition | action | fact-class )*
ruleset-name ::= identifier
使用上の注意
named-rulesetでは、ruleset-nameという名前の指定したルールセットに定義が作成されるか、または定義が追加されます。
unnamed-rulesetでは、main
という名前のデフォルトのルールセットに定義が追加されます。
ルールセットはネストされる場合があります。つまり、他のルールセットが含まれている場合があります。ネストはルールセットのネーミングには影響を与えませんが、Javaのインポートがパッケージの参照可能性に影響を与えるのと同様に、ルールセットの参照可能性には影響を与えます。
ルールセットは、RL LanguageコマンドラインまたはJava RuleSession APIを使用して実行できます。
named-ruleset ruleset-nameは、RuleSession
内で一意であることが必要です。
例
例2-1には、2つの定義enterRoom
およびsayHello
と2つのアクション(assertおよびrun)が含まれています。
例2-1で示されているルールは、次の条件が満たされるまで起動されません。
enterRoom
ファクトがアサートされる。
run関数が実行される。つまり、ルールの包含ルールセットであるhello
がルールセット・スタックに追加される。
例2-1 名前付きルールセットの使用
ruleset hello { class enterRoom { String who; } rule sayHello { if (fact enterRoom) { println("Hello " + enterRoom.who); } } assert(new enterRoom(who: "Bob")); run("hello"); }
例2-2で、ルールセットR2がルールセットR1内にネストされている場合、名前R2はルール・セッション内で一意であることが必要です。R2の名前は、R1との相関で設定されているわけではありません。たとえば、R2で定義されるクラスC2のグローバル名はR2.C2であり、R1.R2.C2ではありません。R2がR1内にネストされている場合、R1で定義されているパブリック・クラスC1は、完全名R1.C1または短縮名C1(R2でC1が定義されていないと仮定した場合)を使用してR2で参照できます。
例2-2 ネストされたルールセットの使用
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 }
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
表2-1は、様々な型の暗黙的変換の要約です。各行は、「変換元」列の型が、「変換先」列の型リストに示されているように暗黙的に変換される可能性があることを示しています。
表2-1 暗黙的な型変換
変換元 | 変換先 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注意: オブジェクトはJavaまたはRL Languageのクラスまたは配列のインスタンスです。型変換が可能であるのは、クラスが継承(実装または拡張)で関連付けられている場合のみです。 |
表2-2は、様々な型について許可されているキャスト変換の要約です。キャストを使用すると、ビット数の多いプリミティブ型をビット数の少ないプリミティブ型に、例外をスローすることなく変換できます。
表2-2に示されている型変換には、明示的なキャスト演算子が必要です。例:
int i = 1; short s = (short)i;
注意: 表2-2に示されているような数値型を含む型変換では、上位ビットが失われる可能性があり、オブジェクトが関係するこのような変換では、RLClassCastExeption がスローされる場合があります。 |
表2-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
。
オブジェクト型
JavaのObject
。そのクラスの修飾名qnameで識別されます。例: java.lang.String
RL LanguageのObject
。そのクラスの修飾名qnameで識別されます。例: ruleset1.Class1
文字列型
RL LanguageではJava文字列が使用されます。この場合は次のように処理されます。
文字列はクラスjava.lang.String
のインスタンスです。
文字列リテラルは二重引用符で区切られます("string")。
文字列内に二重引用符を含める場合は\"を使用します。
文字列は、+
演算子を使用して次のように連結されます。
+
演算子のオペランドが文字列の場合は、残りのオペランドが文字列に変換され、各オペランドが連結されます。
オブジェクトは、そのtoString
メソッドを使用して文字列に変換されます。
RL Languageクラスのインスタンスは、組込み変換を使用して文字列に変換されます。
配列型
大カッコ([
]
)は配列を示します。RL Languageの配列の構文およびセマンティクスは、Javaの1次元配列と同じです。
注意: RL Languageではマルチディメンション配列はサポートされていません。 |
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バリアントを使用するには、例2-3で示すように、識別子を逆引用符で囲みます。
逆引用符の表記法は、RL Languageで識別子またはパッケージ名が有効であるすべての場所で使用できます。assertXPathのString
引数で識別子のXMLバリアントを使用する場合、逆引用符は必要ありません。例2-4と例2-5は同等です。
例2-3 逆引用符を使用したXML識別子のマッピングの例
`http://www.mycompany.com/po.xsd` -> com.mycompany.po `my-attribute` -> myAttribute `Items/item` -> Items$ItemType
例2-4 assertXPathで文字列にXML識別子を使用する例
import `http://www.mycompany.com/po.xsd`.*; fact class `purchaseOrder` supports xpath; fact class `Items/item` supports xpath; assertXPath("http://www.mycompany.com/po.xsd", root, ".//item[ship-date > 20-jul-2004]"); rule r { if (fact `a-global-element-name`(`my-attribute`: 0)) { println("my-attribute is zero"); } }
例2-5 assertXPathでJava識別子を使用する例
import com.mycompany.po.*; fact class PurchaseOrder supports xpath; fact class Items$ItemType supports xpath; assertXPath("com.mycompany.po", root, ".//item[shipDate > 20-jul-2004]"); rule r { if (fact AGlobalElementName (myAttribute: 0)) { println("my-attribute is zero"); } }
表2-3は、RL Languageのリテラルの要約です。リテラルはJavaリテラルと同じです。
表2-3 RL Languageのリテラル
リテラル | 割当て可能な変数の型 |
---|---|
範囲0〜127の整数、または範囲0〜127のUCS2エンコーディングの |
|
範囲0〜65535の整数または |
|
範囲-128〜127の整数 |
|
範囲-32768〜32767の整数 |
|
整数 |
|
末尾が |
|
浮動小数点定数 |
|
末尾が |
|
""で囲まれた文字列 |
|
ルールセット内の定義が実行されると、誤りがないかチェックされ、ルール・セッションで後で使用するために保存されます。
書式
definition ::= variable | rule | rl-class-definition | function
name ::= identifier
qname ::= [ ruleset-or-packagename.]name
ruleset-or-packagename ::= qname
使用上の注意
各定義の名前は包含ルールセット内で一意であるため、修飾名qnameはルール・セッション内で一意です。
ルールセット・レベルで定義された変数はグローバルです。グローバル変数は、ルールセットに含まれているすべての式で変数名を使用して参照可能であり、他のルールセット内の式では変数のqnameを使用して参照可能です。関数およびパブリック・クラスも、それぞれのqnameを使用して他のルールセットから参照できます。
Javaクラスとそのメソッドおよびプロパティにもqnameがあります。
例
例2-6のクラス定義のqnameはhello.enterRoom
です。
例2-6 名前付きルールセット内のクラス定義
ruleset hello { class enterRoom { String who; } rule sayHello { if (fact enterRoom) { println("Hello " + enterRoom.who); } } assert(new enterRoom(who: "Bob")); run("hello"); }
変数は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に初期化できます。
変数はスコープ内でローカルまたはグローバルです。初期化式が必要です。ローカル変数はファイナルにはできません。
ルールセットの直後に囲まれている(つまり定義内の)変数は、スコープ内のルール・セッションに対してグローバルです。ファイナル・グローバル変数の初期化式は、グローバル変数の定義時に実行されます。
非ファイナル・グローバル変数の初期化式は次の両方の場合に実行されます。
グローバル変数の定義時
reset
関数の毎コール時
ファイナルとして宣言されたグローバル変数は、初期化後変更できません。
ルール条件(fact-set-condition)で参照されるグローバル変数はファイナルであることが必要です。
例
例2-7は、reset関数によって非ファイナル・グローバル変数i
の初期化が実行されることを示しています。したがって、この例では1ではなく0(ゼロ)が出力されます。
二次的作用のある関数でグローバル変数を初期化する場合には注意が必要です。resetのコール時に二次的作用が繰り返されないようにする場合は、変数をfinal
として宣言する必要があります。たとえば、例2-8では"once"は2回出力され、例2-9では"once"は1回出力されます。
例2-8 resetの二次的作用を受けるグローバル変数の初期化
RL> clear; RL> function once() returns int { println("once"); return 1; } RL> int i = once(); once RL> reset(); once RL>
例2-9 resetの二次的作用を回避するファイナル・グローバル変数の初期化
RL> clear; RL> function once() returns int { println("once"); return 1; } RL> final int i = once(); once RL> reset(); RL>
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
priority ::= priority = numeric-expression
autofocus ::= autofocus = boolean-literal
logical ::= logical = ( boolean-literal | positive-integer-literal )
内容は次のとおりです。
positive-integer-literal: 0(ゼロ)より大きい整数リテラル
使用上の注意
priorityプロパティでは、ルールの優先度が指定されます。同じルールセットのルールのアクティブ化セット内では、アクティブ化は優先度順に実行されます(「ルール起動の順序付け」を参照)。ルールの優先度が異なる場合、優先度の高いルールが優先度の低いルールより先にアクティブ化されます。デフォルトの優先度は0(ゼロ)です。同じ優先度のルールのアクティブ化セット内では、最後に追加されたアクティブ化が最初に実行されますが、この動作は変更できます(getStrategy関数およびsetStrategy関数を参照)。
autofocusプロパティがtrue
のルールでは、ルールがアクティブ化されたときに包含ルールセットがルールセット・スタックに自動的に追加されます。
logicalプロパティが使用されているルールは、ルールのアクション・ブロックでアサートされたすべてのファクトが、ルールの条件によって照合された一部のファクトまたはすべてのファクトに依存するようにします。logicalプロパティに整数値nを指定すると、ルール条件内にある最初のn個の上位&&
edファクト・セット式に対する依存性が作成されます。logicalプロパティにブール値true
を指定すると、条件のファクト・セット式に対する依存性が作成されます。ファクト・セットの行内で参照されるファクトが、ルールの論理条件に該当しなくなるように変更された場合はいつでも、そのファクト・セット行に関連付けられているアクティブ化によってアサートされたファクトは自動的に取り消されます。
例
例2-10は、推論(ソクラテスは人間である。これはソクラテスは男性であるというファクトに依存する)のあるルールを示しています。
例2-10 ルール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()
例2-11は、同じファクトを複数のルールでアサートすること、または最上位のルールセット・アクションまたは関数でアサートすることが可能であることを示しています。このようなファクトは、すべてのアサータに自動取消をコールする論理句がないかぎり、自動的に取り消されません。最上位のアクションまたは関数でアサートされているファクトは、自動的に取り消されることはありません。
ソクラテスが人間であるというファクトは取り消されないことに注意してください。これは、ソクラテスが男性であるというファクトに依存していない最上位のアクションでアサートされているためです。
例2-11 ファクトの無条件アサート
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")
参照クラスはすべて、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では、プロパティのタイプは包含クラス定義の名前の場合があります(例2-12を参照)。RL Languageでは、Javaとは異なり、クラス定義の前方参照はサポートされていません(例2-13を参照)。
RL LanguageクラスとJavaクラスの両方でxpathがサポートされています。XML識別子は、xpath内では逆引用符で囲む必要はありません。
組込みのassertXPath関数では、オブジェクトのツリーをファクトとしてアサートするための簡単なxpathに似た構文がサポートされます。ツリーのノードは、xpathをサポートする同じパッケージまたはルールセット内のクラスのオブジェクトです。親ノードと子ノードの間のリンクはXLink
クラスのインスタンスです。xpathをサポートするクラス内のすべてのプロパティを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では引用できません。
例
表2-4は、組込みのassertXPath関数で使用するxpath選択オプションを示しています。この説明部分で、選択とは、要素がファクトとしてアサートされ、アサート要素を表す要素プロパティがあるXLinkの選択プロパティがtrue
であることを意味します。選択した要素の祖先は、ルート要素まで含めて常にアサートされますが、必ずしも選択されるわけではありません。
表2-4 xpath選択文字列
xpath選択文字列 | 選択の説明 |
---|---|
//* |
ルートを含めてすべての要素を選択 |
.//* |
ルート以外のすべての要素を選択 |
. |
ルートのみを選択 |
//foo |
fooという名前のプロパティの値であるすべてのオブジェクトを選択 |
.[x==1]/y |
ルートに、名前がxで1と等しい子要素または属性がある場合にのみ、ルートの子または属性で名前がyであるものを選択 |
例2-14では、PersonというRL Languageクラスがインスタンス化され、次のようなファミリ・ツリーが作成されます。
First Generation Second Generation Third Generation Ida Mary Fred John Rachel Sally Evan
例2-14では、2つのxpathでassertXPath関数が2回使用されています。
//kids[male==true] //kids[male==false]
例2-14では、次の2つのルールが定義されます。
sibling
: 兄弟姉妹関係のすべてのペアを出力
brotherSister
: 兄弟のすべてのペアおよび姉妹のすべてのペアを出力
例2-14 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"); }
例2-15 ファミリ・ツリーの例の実行結果
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
例2-16は、assertXPath
でアサートされた要素を取り消すと、そのすべての子孫も取り消されることを示しています。
結果は次のようになります。
f-0 initial-fact()
合計1ファクトの場合。
例2-17では、祖先のすべてのペアが出力されます。最初に、ファミリ・ツリーがアサートされます。例2-18は、例2-17のコードの実行結果を示しています。
例2-17 クラス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();
例2-18 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
書式
function ::= function name parameters [ returns type ] action-block
parameters ::= ( [ type identifier ( , type identifier )* ] )
使用上の注意
action-blockによって、定義されている関数を起動できます。ただし、action-blockには、まだ定義されていない関数の前方参照を含めることはできません(例2-19および例2-20を参照)。
関数はオーバーロード可能です。たとえば、組込みのprintln関数はオーバーロードされています。
例
すべての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
があるとします。例2-21で示されるルールmatchVehicle
では、FactClassException
をラップするTypeCheckException
が生成されます。これは、スーパークラスの前にサブクラスが参照されるためです。ラップは、FactClassException
とMultipleInheritanceException
の両方に対するサブクラス化のかわりに使用されます。これは、ファクト・コンテキストによっては、これらの例外が実行時までスローされず、RLRuntimeException
でラップされるためです。
例2-21 スーパークラスの前に参照されるサブクラスがある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
例2-22では、matchVehicle
ルールがスーパークラスに対する最初の参照であるため、例外はスローされません。
例2-22 最初にスーパークラスの参照がある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"
例2-23では、ファクト・クラス宣言がスーパークラスに対する最初の参照であるため、例外はスローされません。
例2-23 最初にスーパークラスの参照があるファクト・クラス宣言を含む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"
ファクトでは多重継承はサポートされません。例2-24に示されたJavaクラスとインタフェースについて考えてみます。
例2-24 Javaクラスと多重継承の例
package example; public class Car {} public interface Sporty {} public class SportsCar extends Car implements Sporty {}
コマンドラインで入力された例2-25の結果、MultipleInheritanceException
をラップするTypeCheckException
がスローされます。TypeCheckException
でgetCause
メソッドを使用すると、ラップされたMultipleInheritanceException
例外を取得できます。
例2-25 ファクトに対するMultipleInheritance例外
import example.*; fact class Sporty; fact class Car; fact class SportsCar; // throws TypeCheckException wrapping a MultipleInheritanceException
例2-26は、Oracle Rules Engineでrx8
オブジェクトをアサートしようとしたときに、その実際の型がObject
ではなくSportsCar
であることが検出された場合に、実行時に発生する例外を示しています。MultipleInheritanceException
を回避するには、ファクト・クラス・コンテキストでSporty
を使用するかまたはCar
を使用するかを選択する必要があります。両方を使用することはできません。
例2-26 MultipleInheritanceExceptionをラップするRLRuntimeException
import example.*; fact class Sporty; fact class Car; Object rx8 = new SportsCar(); assert(rx8); // throws RLRuntimeException wrapping a MultipleInheritanceException
例2-27 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;
を明示的に発行することです。
import文では、Javaクラスの参照時にパッケージ名修飾を省略できます。
書式
import ::= import ( Java-class-name | Java-package-name.* ) ;
Java-package-name ::= qname
使用上の注意
インポート・コマンドはルールセット内に配置でき、インポートのスコープがそのルールセットであることを暗黙的に示しますが、実際にはグローバルに適用されます。次のコードでこの動作の例を示します。インポートのスコープが限定されているとすると、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; } }}
書式
内容は次のとおりです。
URL: 有効なUniform Resource Locator。
使用上の注意
file:
およびhttp:
スキームがサポートされています。
例
include file:example.rl;
RL Languageの式では、一般的なJava構文が使用されます(これから説明するような多少の違いはあります)。例
(a + 1) * (b - 2)
式は条件またはアクションで使用しますが、いくつか制限事項があります。式は厳密に型指定されます。
書式
expression ::= boolean-expression
| fact-set-expression | object-expression
書式
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
type-name ::= qname
使用上の注意
文字列に対して、<
はUnicode UCS2コード・ポイントの順序です。
オブジェクトに対して!=
を使用すると、オブジェクト参照が等価でないことはテストされず、equalsメソッドの否定になります。
次の文について考えてみます。
if (object1 != object2){}
これは、次の文と同じです。
if (! (object1.equals(object2)){}
Javaとは異なり、RL Languageはオブジェクト参照が等価であることのテストをサポートしていません。
例
例2-28に、RL Languageでのブール式の使用方法を示します。
例2-28 RLブール式
if ( (true ? "a" < "b" : false) && (1 == 0 || 1.0 > 0) && "x" instanceof Object ) { println("all true"); };
数式では、Javaと同じく、他のオペランドが浮動小数点の場合、整数オペランドは浮動小数点に暗黙的に変換されます。表2-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
使用上の注意
表2-5は、numeric-expressionの優先順位を降順に示しています。
表2-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 |
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
例
例2-29に、RL Languageでの文字列式の使用方法を示します。この例では、"1 2.0 true {1,2}"と出力されます。
例2-29 RL文字列式
int i = 1; double f = 2.0; boolean b = true; int[] v = new int[]{i, 2}; println(i + " " + f + " " + b + " " + v);
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の型は配列型であることが必要です。
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
fact-set-pattern ::= fact fsp-class [ ( property-pattern ( , property-pattern )* ) ]
[ var ] local-object-variable
fsp-class ::= qname
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
| numeric literal
constraint ::= simple-expression
property-name ::= name
使用上の注意
fact-set-expressionでは、戻すファクトを制限できます。この制限には、制約としてfact-set-patternでsimple-expressionを使用するか、またはfact-set-expressionでサポートされている演算子を使用します。
fact-set-expressionには次のものを含めることはできません。
new
非ファイナル・グローバル変数の参照
演算子の優先順位はJavaと同様です。優先順位を指定するにはカッコを使用します。例:
fact person var p && (p.age < 21 || p.age > 65)
カッコがない場合は、p.age
のp
は未定義です(演算子の優先順位の詳細は表2-5を参照)。
local-object-variableまたはlocal-property-variableは、パターンに続いていて、&&
演算子で連結されるパターンに続くすべての式に対するスコープ内にあります。 パターンがexists
, ||
または!
式に含まれていない場合は、変数もルールのaction-blockのスコープ内にあります。&&
'ed式では、戻されるファクトをフィルタ処理して、フィルタで除外されなかったファクトのみを戻すことができます。
ファクト・セット・パターン - 作業メモリーからのフェッチ
最も基本的なfact-set-expressionは、作業メモリーにアサートされている特定クラスのファクトの一部またはすべてを戻すfact-set-patternです。fact-set-patternでは、作業メモリーが検索され、特定クラスのファクト、およびプロパティ値にオプションのconstraintがあるファクトが検出されます。戻されるファクト・セットには、各一致ファクトに対する行が含まれます。各行を表すようにローカル行変数を定義するか、または行内のフィールドを表すようにローカル・フィールド変数を定義できます。ローカル行変数が指定されない場合は、各行を表すためにクラスのqnameの名前部分を使用できます(例2-33を参照)。
結合演算子
&&
演算子では、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) {}
|
空演算子
!
演算子では、fact-set-expressionが空であるかどうかがテストされます。 !
をfact-set-expressionに適用するときは、次の点に注意してください。
式のvar
は、包含!
式の外部で参照できません。
!
演算子では、fact-set-expressionが空である場合は単一の行が戻され、空でない場合は空のファクト・セットが戻されます。
存在(非空)演算子
exists
演算子では、fact-set-expressionが空でないかどうかがテストされます。
exists
演算子をfact-set-expressionに適用するときは、次の点に注意してください。
式のvar
は、包含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); }
例
例2-30は、値が1のすべてのCounter
ファクトに対してアクションがアジェンダに配置されることを示しています。
例2-30 Counter.valueに対するファクト・セットの表現
class Counter { int id; int value; } rule ex1a { if (fact Counter c && c.value == 1) { println("counter id " + c.id + " is 1"); } }
例2-31は、constraintを使用して例2-30のルールを表す同等の方法を示しています。
例2-31 ファクト・セット制約の使用
rule ex1b { if (fact Counter(value: 1) c) { println("counter id " + c.id + " is 1"); } } assert(new Counter(id: 99, value: 1)); run(); // prints twice, once for each rule
例2-32は、ファクト・セットの無効な使用方法を示しています。これは、c
が定義前に使用されているためです。
例2-32 ファクト・セットの無効な使用方法
rule ex2 { if (c.value == 1 && fact Counter c) { println("counter id " + c.id + " is 1"); } }
例2-33は、プロパティa2==0
で、相当する最初の要素であるCounterと一致しないすべてのAttFacts
に対してアクションがアジェンダに配置されることを示しています。
例2-33 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
例2-34は、条件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)}
を含んだファクト・セットが戻されます。
例2-34 &&演算子を使用したファクト・セットの使用
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
書式
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
1次式には、変数、プロパティ、配列要素、クラス・メンバー、およびその他の密バインディングの式構文(リテラル、メソッドや関数のコール、オブジェクトやファクトの構成など)の代入ターゲットが含まれます。構文は、記述されている場合を除いてJavaとほぼ同じです。
書式
primary-expression ::= array-primary-expression
| (配列を戻す)function-call
| (1次元のJava配列を戻す)method-call*
| ( array-expression )
simple-type [ numeric-expression integer ]
| numeric [ ] { numeric-expression ( , numeric-expression )* }(数式は暗黙的にベースに変換可能であることが必要)
| boolean [ ] { boolean-expression ( , boolean-expression )* }
| object-type [ ] { object-expression ( , object-expression )* }
)
qname(配列型の変数)
| (配列型の)member
| array-primary-expression(ベース型はObject)[ numeric-expression int ]
文字列リテラル (「リテラル」を参照)
| 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 )
qname(数値型の変数)
| (数値型の)member
| array-primary-expression(ベース型は数値) [ numeric-expression ]
boolean-primary-expression ::=
| (ブールを戻す)function-call
| (ブールを戻す)method-call
| ( boolean-expression )
boolean-literal ::= true | false
qname(ブール型の変数)
| (ブール型の)member
| array-primary-expression(ベース型はブール)[ numeric-expression int ]
new class-definition-name ( [ expression ( , expression )* ] 引数リスト )
| new class-definition-name ( [ property-pattern ( , property-pattern )* ] プロパティと値のペア )
| (Javaオブジェクトを戻す)function-call
| (Javaオブジェクトを戻す)method-call
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 メンバー名
例
例2-35は、RL Languageリテラル構文(Javaと同じです)を示しています。
メソッドおよび関数はオーバーロードできます。ただし、Javaとは異なり、RL Languageでは、実際の引数リストとオーバーロード関数の照合に前詰め法が使用されます。
例2-36にオーバーロードの例を示します。
例2-36 オーバーロード
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
RL Languageクラスにはユーザー定義コンストラクタはありません。デフォルト・コンストラクタによって、プロパティはデフォルト値に初期化されます。RL Languageのnew
演算子では、一部のプロパティ値を指定できます(Java Beanのプロパティに対しても動作します)。
Java Beanのプロパティにはgetterはありsetterがない場合があります。このようなプロパティは変更できません。
例
Javaと異なり、RL Languageにはアクション・ブロックが必要であり、単一のセミコロンの終了アクションは許可されていません。
書式
action ::= action-block | if | while | for | try | synchronized | return | throw
| assign | incr-decr-expression | primary-action
action-block ::= { ( variable | action )* }
使用上の注意
アクション・ブロックは、任意の数のローカル変数宣言とアクションです。変数は、同じアクション・ブロック内の後続の変数初期化式およびアクションで参照可能です。
RL Languageでは、Javaとは異なり、すべてのローカル変数が宣言時に初期化される必要があります。ローカル変数はファイナルにはできません。
終了するには、アクション内からSystem.exit(int)メソッドを起動できます。
例
if elseアクションを使用すると、テストがtrue
の場合は最初のアクション・ブロックが実行され、テストがfalse
の場合はオプションのelse部分(別のifアクションまたはアクション・ブロックの場合があります)が実行されます。
Javaと異なり、RL Languageにはアクション・ブロックが必要であり、単一のセミコロンの終了アクションは許可されていません。
書式
if ::= if if-test action-block [ else if | action-block ]
if-test ::= boolean-expression
例
例2-39は、RL Languageのif elseアクション・ブロックを示しています。例2-40は、アクション・ブロックが必要であることを示しています。
例2-39 if elseアクションの例
String s = "b"; if (s=="a") { println("no"); } else if (s=="b") { println("yes");} else { println("no"); }
テストがtrue
の間はアクション・ブロックが実行されます。return、throwまたはhaltでアクション・ブロックを終了できます。
書式
while ::= while while-test action-block
while-test ::= boolean-expression
使用上の注意
Javaと異なり、RL Languageにはアクション・ブロックが必要であり、単一のセミコロンの終了アクションは許可されていません。
例
例2-41では"bye"が2回出力されます。
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では使用できます)。
例
例2-43は、int[]
をdouble[]
に変換するRL Languageコードを示しています。
例2-43 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);
最初のアクション・ブロックが実行されます。実行時にスローされた、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関数のコール元で処理される必要があります。
例
例2-44は、try catchおよびfinallyアクションを示しています。この例の実行結果は次のとおりです。
exception in invoked Java method this is really bad! but at least it's over!
例2-44 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!"); }
RL Languageでは、明示的にスローされたException ("this is really bad!")
は、起動されたJavaメソッドの例外として処理され、Exception
はJavaException
にラップされます。明示的にスローされたException
は、JavaException
の原因として使用できます。
Javaと同様に、synchronizedアクションは、複数スレッドのアクションの同期化に役立ちます。synchronizedアクション・ブロックを使用すると、指定したオブジェクトのロックを取得してからaction-blockを実行し、実行後にロックを解放できます。
書式
synchronized ::= synchronized object-primary-expression action-block
例
例2-45は、Person
オブジェクトの名前を変更し、旧姓をニックネームに追加し、Javaオブジェクトの同時読取りユーザー(同時に同期化中)がPerson
の一貫したビューを参照するように同期化します(Person
Beanの詳細は例2-14を参照)。
例2-45 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());
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は指定しないでください。
例外がスローされます。例外は、java.lang.Throwable
を実装するJavaオブジェクトであることが必要です。スローされた例外は、tryアクション・ブロック内のcatch
で捕捉できます。
書式
throw ::= throw throwable ;
throwable ::= object-primary-expression
RL Languageの代入は、Javaと同様に、アクションとして出現可能な式です。
書式
assign ::= assignment-expression ;
assignment-expression ::= boolean-assignment
例
例2-46は、RL Languageの代入式の使用方法を示しています。この例では"6 5
"と出力されます。
RL Languageのインクリメントまたはデクリメントは、Javaと同様に、アクションとして出現可能な式です。
書式
incr-decr ::= incr-decr-expression ;
incr-decr-expression ::= ( ++ | -- ) numeric-target-expression | numeric-target-expression ( ++ | -- )
例
例2-47は、RL Languageのデクリメント・アクションの使用方法を示しています。この例では"0
"と出力されます。
基本アクションは、関数コール、assertまたはJavaメソッド・コールなど、その二次的作用のために実行される基本的な式です。たとえば、println
関数は基本アクションとしてよく使用されます。
書式
primary-action ::= primary-expression ;
この項では、次のRL Language組込み関数について説明します。
assert、assertXPath、clearRule、clearRulesetStack、clearWatchRules、clearWatchActivations、clearWatchFacts、clearWatchFocus、clearWatchCompilations、clearWatchAll、getRulesetStack、getRuleSession、getStrategy、halt、id、object、println、popRuleset、pushRuleset、retract、reset、run、runUntilHalt、setRulesetStack、setStrategy、showActivations、showFacts、step、watchRules、watchActivations、watchFacts、watchFocus、watchCompilations
提供オブジェクト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プロパティの値である場合を除きます。
例
例2-48では"Pavi has highest salary 65000.0"と出力され、例2-49では"dept 10 has no employees!"と出力されます。
例2-48 highestSalaryルールでのアサート関数の使用
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();
例2-49 emptyDeptルールでのアサート関数の使用
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();
関連項目
指定した要素をルートとして使用してファクトのツリーを作業メモリーに追加し、XMLのxpathに似た式でツリー内のオブジェクトを定義します。pkgは、ツリー内のオブジェクトのクラスが含まれるJavaパッケージまたはRL Languageルールセットです。ツリー内のすべてのオブジェクトが同じパッケージまたはルールセット内に存在する必要があります。
要素および選択した子をアサートする以外に、親オブジェクトと子オブジェクトをリンクするXLinkファクトがアサートされます。ツリー内のすべてのオブジェクトのクラスで、RLクラス(rl-class-definition)またはfact-class宣言のsupports xpath(supports)句を使用する必要があります。
書式
function assertXPath(String pkg, Object 要素, String xpath);
関連項目
名前付きのルールをルール・セッションから消去します。ルールのアクティブ化はすべてアジェンダから削除されます。
書式
function clearRule(String 名前);
関連項目
書式
function clearRulesetStack();
関連項目
getRulesetStack、getStrategy、popRuleset、pushRuleset、run、setStrategy
clearWatch関数は、デバッグ情報の出力を停止します。
書式
function clearWatchRules();
function clearWatchActivations();
function clearWatchFacts();
function clearWatchFocus();
function clearWatchCompilations();
function clearWatchAll();
関連項目
watchRules、watchActivations、watchFacts、watchFocus、watchCompilations
ルールセット・スタックをルールセット名の配列として戻します。
書式
function getRulesetStack() returns String[];
使用上の注意
戻り値: ルールセット名の配列としてのルールセット・スタック
スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。
関連項目
clearRulesetStack、getStrategy、popRuleset、pushRuleset、setRulesetStack、setStrategy
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 && … { … } }"); } }
関連項目
現在の方針を戻します。表2-6に、使用可能な方針の値が示されています。
書式
function getStrategy() returns String;
関連項目
clearRulesetStack、getRulesetStack、popRuleset、pushRuleset、setStrategy
halt関数では、現在起動中のルールの実行が停止され、停止されたルールの実行元であるrun、runUntilHaltまたはstep関数に制御が戻されます。アジェンダはそのままであるため、後続のrun、runUntilHaltまたはstepを実行するとルールの起動を再開できます。
halt関数は、run、runUntilHaltまたはstep関数のコンテキスト外で起動された場合は効果がありません。
書式
function halt();
関連項目
オブジェクトobjに関連付けられているファクトIDを戻します。objがファクトに関連付けられていない場合は、-1が戻されます。
書式
function id(Object obj) returns int;
関連項目
特定のファクトIDに関連付けられているオブジェクトを戻します。ファクトIDがない場合は、nullが戻されます。
書式
function object(int factId) returns Object;
関連項目
書式
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);
スタックが空の場合、popRuleset
ではRLRuntimeException
がスローされます。スタックが空でない場合、popRuleset
ではスタックからフォーカスが削除され、戻されます。
すべてのエントリの位置が1つずつ下に移動します。新しいフォーカスは、スタックの新しい最上位であるエントリ0(ゼロ)です。
スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。
書式
function popRuleset() returns String;
関連項目
clearRulesetStack、getRulesetStack、getStrategy、pushRuleset、setStrategy
特定のルールセットをスタックに追加し、そのルールセットをフォーカスにします。すでにフォーカスであるルールセットを追加するとエラーが発生します(このエラーについてはRLIllegalArgumentException
がスローされます)。
スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。
書式
function pushRuleset(String focus);
例
例2-52は、pushRuleset
およびpopRuleset
関数を使用したRL Languageを示しています。
例2-51 pushRuleSetの使用 - RLIllegalArgumentExceptionのスロー
clearRulesetStack(); pushRuleset("main"); // focus is "main" pushRuleset("main"); // RLIllegalArgumentException
例2-52 pushRuleSetの使用 - RLIllegalArgumentExceptionのスロー
clearRulesetStack(); pushRuleset("main"); // focus is "main" pushRuleset("main"); // RLIllegalArgumentException
例2-53 popRuleSetの使用 - RLRuntimeExceptionのスロー
clearRulesetStack(); popRuleset(); // RLRuntimeException
関連項目
clearRulesetStack、getRulesetStack、getStrategy、popRuleset、setStrategy
オブジェクトobjに関連付けられているファクトを作業メモリーから削除します。
書式
function retract(Object obj);
使用上の注意
取消しはアジェンダに影響を与える可能性があります。取り消されたファクトに依存するアクティブ化はアジェンダから削除されます。
(!
を使用して)ファクトが存在しないことをテストする条件があるルールによって、アジェンダに新しいアクティブ化が配置される可能性があります。
関連項目
作業メモリーからすべてのファクトを消去し、アジェンダからすべてのアクティブ化を消去して、非ファイナル・グローバル変数の初期化式を再評価します。
書式
function reset();
関連項目
アジェンダに存在するルール・アクティブ化を、次の条件に該当するまで起動します。
ルール・アクションでhaltが直接または間接的にコールされるまで。たとえば、ルール・アクションによってコールされた関数でhaltがコールされる場合です。
アジェンダが空になるまで。
ルールセット・スタックが空になるまで。
書式
function run() returns int;
function run(String rulesetName) returns int;
使用上の注意
引数rulesetNameが指定された場合は、ルールの起動前に、名前付きルールセットがルールセット・スタックの最上位に追加されます。
nullのrulesetNameが指定された場合、ルールセット・スタックはルールの起動前に変更されません。
rulesetNameが指定されず、デフォルトのmain
ルールセットがルールセット・スタック上に存在しない場合は、ルールの起動前に、main
がルールセット・スタックの最下位に配置されます。
戻り値: int
。起動されたルールの数。
関連項目
この関数では、haltがコールされるまでルール・アクティブ化が起動されます。runおよびstepとは異なり、runUntilHaltは、アジェンダが空になっても戻りません。また、runUntilHaltでは、ルールセット・スタックから最下位のルールセット名は削除されません。かわりに、アジェンダにアクティブ化が格納されるのを待機します。
書式
function runUntilHalt() returns int;
使用上の注意
メインのRuleSessionスレッドがビジーであるときにアクティブ化をアジェンダに追加する唯一の方法であるrunUntilHaltの実行は、2番目のスレッドに対して行われ、次のいずれかが実行されます。
PropertyChangeListeners
を使用したJava Beanファクトの変更
assertまたはretract
関数の実行
runUntilHaltの使用時はルールを注意して設計する必要があります。たとえば、プロパティが最小値のファクトを検出しようとするルールは、ファクトの最初のインスタンスがアサートされたときに起動され、その後は、それより小さい値のプロパティが設定された別のインスタンスがアサートされるたびに起動されます。
関連項目
ルールセット・スタックをルールセット名の特定の配列に設定します。
スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。
書式
function setRulesetStack(String[] rulesetStack
関連項目
clearRulesetStack、getRulesetStack、getStrategy、popRuleset、pushRuleset、setStrategy
方針では、同じルールセット内の優先度が同じアクティブ化の実行順序が指定されます。表2-6は、有効な方針の値を示しています。
表2-6 setStrategyおよびgetStrategy関数の方針の値
方針 | 説明 |
---|---|
queue |
アクティブ化は、古い方から順に起動されます。 |
stack |
アクティブ化は、新しい方から順に起動されます。 |
書式
function setStrategy(String strategy);
関連項目
clearRulesetStack、getRulesetStack、getStrategy、popRuleset、pushRuleset
show関数では、ルール・セッションの状態が出力ライターに出力されます。表示可能な状態は、アジェンダ上のすべてのアクティブ化です。
書式
function showActivations();
関連項目
clearWatchRules、clearWatchActivations、clearWatchFacts、clearWatchFocus、clearWatchCompilations、clearWatchAll、showFacts、watchRules、watchActivations、watchFacts、watchFocus、watchCompilations
show関数では、ルール・セッションの状態が出力ライターに出力されます。表示可能な状態は、作業メモリー内のすべてのファクトです。
書式
function showFacts();
関連項目
clearWatchRules、clearWatchActivations、clearWatchFacts、clearWatchFocus、clearWatchCompilations、clearWatchAll、showActivations、watchRules、watchActivations、watchFacts、watchFocus、watchCompilations
アジェンダに存在するルール・アクティブ化を、次の条件に該当するまで起動します。
指定した数のルール・アクティブ化numRulesToFireが起動されるまで。
ルール・アクションでhaltが直接または間接的にコールされるまで。たとえば、ルール・アクションによってコールされた関数でコールされる場合です。
アジェンダが空になるまで。
ルールセット・スタックが空になるまで。
書式
function step(int numRulesToFire) returns int;
function step(int numRulesToFire, String rulesetName) returns int;
使用上の注意
ルールセット名が指定されず、main
ルールセットがルールセット・スタック上に存在しない場合は、ルールの起動前に、main
ルールセットがルールセット・スタックの最下位に配置されます。
rulesetNameというルールセットが指定された場合は、ルールの起動前に、指定されたルールセットがルールセット・スタックの最上位に追加されます。nullのルールセット名が指定された場合、ルールセット・スタックはルールの起動前に変更されません。
戻り値: 起動されたルールの数。
関連項目
watch関数は、重要なルール・セッション・イベントに関する情報の出力を有効にします。情報は、イベントが発生するたびに出力ライターに出力されます。出力を無効にするには、clearWatch関数を使用します。
表2-7で、使用可能なデバッグ情報について説明します。
表2-7 watch関数のイベントの説明
デバッグwatch | ルール・セッション・イベントの説明 |
---|---|
Rules |
ルールの起動(アクティブ化の実行)に関する情報 |
Activations |
アジェンダに対するアクティブ化の追加または削除 |
Facts |
作業メモリー内のファクトのアサート、取消しまたは変更 |
Focus |
ルールセット・スタックに対するルールセットの追加または削除。ルールセット・スタックの最上位はフォーカス・ルールセットと呼ばれます。フォーカス・ルールセットのアジェンダに存在するすべてのアクティブ化が起動された後、フォーカスが削除され、スタック上の次のルールセットがフォーカスになります。 |
Compilations |
ルールの条件がReteネットワークに追加されると、条件の一部が既存のルールとどのように共有されるかに関する情報が出力されます。"="は共有を示します。ルールの定義順序が共有に影響を与える場合があるため、パフォーマンスにも影響を与える可能性があります。 |
All |
watch Rules、watch Activations、watch Facts、watch Compilationsおよびwatch Focusで示される情報が含まれます。 |
書式
function watchRules();
function watchActivations();
function watchFacts();
function watchFocus();
function watchCompilations();
function watchAll();
関連項目
clearWatchRules、clearWatchActivations、clearWatchFacts、clearWatchFocus、clearWatchCompilations、clearWatchAll、showActivations、showFacts