Oracle Fusion Middleware Oracle Business Rulesランゲージ・リファレンス・ガイド 11g リリース1(11.1.1) B56239-01 |
|
戻る |
次へ |
この章の内容は次のとおりです。
この項では、ルール対応アプリケーションを作成する手順を示し、RuleSession
オブジェクトの使用方法について説明します。RuleSession
オブジェクトはパッケージoracle.rules.rlに含まれています。
RuleSession
コンストラクタは、引数がない場合、デフォルトのロケールおよびロギング・オプションが設定されたRuleSession
を戻します。
表4-1に、RuleSession
コンストラクタのプロパティを示します。
outputWriter
プロパティは、println
、watch
およびshow
の出力先を決定します。
rulesetNameプロパティは、明示的にルールセット名を指定せずに、RL文が実行されるイベント内にルールセットを設定します。デフォルトのrulesetNameはmain
です。
executeRulesetメソッドは、指定のルールセット・テキスト(Stringまたはjava.io.Readerとして指定)を解析して実行します。
callFunctionメソッドは、名前付きRL関数(組込みRL関数または以前にexecuteRulesetメソッドの1つを使用してパラメータなしで定義した関数)を起動し、その結果を戻します。単一の引数を取る関数は、callFunctionWithArgumentメソッドを使用して起動できます。任意の数の引数を取る関数は、callFunctionWithArgumentList
またはcallFunctionWithArgumentArray
メソッドを使用してコールできます。引数のリストまたは配列には、各RL関数パラメータのJavaオブジェクトが記載されている必要があります。
表4-2に、引数をRL関数に渡すためにJavaオブジェクト型をRL型に変換する方法、およびRL関数の戻り値をJavaに渡すためにRL型をJava型に変換する方法を示します。
表4-2 RLからJavaオブジェクトへの変換
Javaクラス | RL型 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RuleSessionメソッドの起動でParseException
またはTypeCheckException
がスローされても、RuleSessionの状態には影響を与えません。Javaアプリケーション(たとえば、対話型のコマンドライン)では、これらの例外を検出し、RuleSessionの使用を続行できます。
RuleSessionメソッドの起動でRLRuntimeException
がスローされた場合は、RuleSessionの状態に影響を与える可能性があり、アプリケーションでRuleSessionを処理できない状態になる場合があります。堅牢なアプリケーションの場合は、RLでRLRuntimeException
を検出し、例外がスローされた近辺でリカバリするように試みます。
その他の例外は、多くの場合、アプリケーションで処理できない重大な問題を示します。
RLクラスは、Javaクラスと同様にRLプログラムで使用できます。new
、instanceof
およびcast
の演算子は、両方のクラスで使用できます。ただし、Javaプログラムに渡されたRLクラスのインスタンスは、実際にはoracle.rules.rl.RLObject
のインスタンスです。Javaプログラムでは、RLObject
を調べるためにRLClass
、RLProperty
およびRLArray
クラスを使用できます。使用方法は、java.lang.Class
、java.lang.reflect.Field
およびjava.lang.Array
クラスを使用してjava.lang.Object
を反映する場合と同じです。RLCLass
、RLProperty
およびRLArray
は、パッケージoracle.rules.rl
に含まれます。
XLinkオブジェクトは、assertTree関数によって作成され、ファクトとしてアサートされます。RLルールでは、XLinkを使用して、assertTreeによってアサートされた要素の階層を推論できます。
Oracle Business Rulesを使用してルール対応プログラムを作成したときの一般的な疑問は、「評価の結果を取得する方法は?」です。
この項では、ルール・エンジンからルール評価の結果を抽出または表示する方法について説明します。
内容は次のとおりです。
関連項目: 『Oracle Business Rulesユーザーズ・ガイド』のルールの起動に関する項 |
この項で使用する例は、高速道路の事故通知システムを示しています。それぞれの例は、ルール・エンジンの評価結果にアクセスするための異なる方法を示しています。これらの例では、2つのJavaクラスtraffic.TrafficIncident
およびtraffic.IncidentSubscription
を使用します。
注意: サンプルのtraffic.* クラスは、Oracle Business Rulesに同梱されていません。 |
TrafficIncident
クラスは、交通状況に影響を与える事故の情報を表し、次のプロパティが含まれています。
どの高速道路か
上りか下りか
事故の種類
事故発生時刻
渋滞の見積時間(分単位)
IncidentSubscription
クラスは、特定の高速道路における事故の通知へのサブスクリプションを記述し、次のプロパティが含まれています。
サブスクライバ: サブスクライバの名前
該当する高速道路
上りか下りか
この例では、高速道路で交通状況に影響を与える事故が発生したとき、これらのクラスを使用してTrafficIncident
オブジェクトをアサートし、ルール評価によって通知の受信者を判断します。
例に示すsess
オブジェクトはRuleSession
で、事故通知の多数のサブスクリプションがアサートされます。単純化するために、TrafficIncident
オブジェクトは永続的でないことを前提にしています。実際には、このオブジェクトはアサート対象イベントを表し、その時点で登録されているサブスクライバにのみ通知が送信されます。
この例で使用するクラスはすべてJavaクラスです。ただし、RLクラスの反映を使用して、JavaでRLクラスのインスタンスを操作することもできます。
関連項目: ドキュメントについては、oracle.rules.rl パッケージにあるRLClass、RLObject、RLPropertyおよびRLArrayクラスに関するJavadocを参照してください。RLオブジェクト、つまりRLクラスのインスタンスを使用すると、Javaオブジェクトと同様に、ルール・エンジンの結果を保持できます。 |
この方法は、結果用のコンテナをアサートする方法と同じです。ただし、コンテナではなくオブジェクトを使用して、ルール・エンジンの外部にあるリソースに作用します。たとえば、予定の作業をキューに挿入したりスケジュールする場合、データベースを更新する場合、メッセージを送信する場合が該当します。結果を導出するには、アクションでアクセス可能な任意のJavaメソッドを起動できます。 コンテナを使用する場合と同様に、外部リソースにアクセスするためにこの例で使用されているオブジェクトは、その内容が推論の対象ではないため、再度アサートされることはありません。
例4-1に示すIncidentDispatcher
オブジェクトは、アサートされて通知の配信に使用されます。
例4-1 外部リソースを使用した結果の取得
rule incidentAlert { if (fact TrafficIncident ti && fact IncidentSubscription s && s.highway == ti.highway && s.direction == ti.direction && fact IncidentDispatcher dispatcher) { dispatcher.dispatch(s.subscriber, ti); } }
例4-2に示すJavaコードは、IncidentDispatcher
およびTrafficIncident
をアサートし、ルール・エンジンを起動します。これは、推論の対象となるオブジェクトを使用しても実行できます。ただし、この場合は、ルール起動の無限ループを回避するために、ルール条件のテストが必要になります。
例4-2 外部リソースを使用した結果の例
sess.callFunctionWithArgument("assert", new IncidentDispatcher()); // An accident has happened TrafficIncident ti = new TrafficIncident(); ti.setHighway("I5"); ti.setDirection("south"); ti.setIncident("accident"); ti.setWhen(new GregorianCalendar(2005, 1, 25, 5, 4)); ti.setDelay(45); sess.callFunctionWithArgument("assert", ti); sess.callFunction("run");
ランタイムでは、RLスタック・トレースに詳細なデバッグ情報が提供されます。エラーが発生した場合は、可能なかぎり、問題箇所の識別に役立つ特別なコンテキストが提供されます。この特別なコンテキストは、ルールSDKとルール・デザイナを併用している場合に有効です。
スタック・トレースには、ルール条件、ルール・アクション、関数、変数およびRLクラス定義に関する情報を示す特別なコンテキストが含まれています。XPath形式のフォーマットは、RL構成とそれに続くカッコで囲まれた名前(名前が指定されている場合)で構成されます。構成の後に大カッコで囲まれた番号n
が表示される場合は、前の構成に続いてn
番目の項目を示します。ルールSDKと併用している場合、ルール・デザイナでは、RL生成によってエラーの場所を非常に特定しやすくなります。
たとえば、例4-3に示されたルールセットについて考えてみます。このルールセットを実行すると、次のレポートが提供されます。
RLNullPointerException: object cannot be null at line 12 column 13 in stackTraceContext /Rule(porsche)/Pattern(car)/Test[1] at line 17 column 5 in stackTraceContext
例4-3 テスト・ルールセット
ruleset stackTraceContext { class Car { String make; String model; } rule porsche { if (fact Car car && car.make.startsWith("Porsche")) { println(car.make + " " + car.model); } } assert(new Car()); }
ruleset stackTraceContext
{
class Car
{
String make;
String model;
}
rule porsche
{
if (fact Car car &&
car.make.startsWith("Porsche"))
{
println(car.make + " " + car.model);
}
}
assert(new Car());
ルールを使用する典型的なアプリケーションでは、個々のリクエストに対応する異なるファクトを使用して、同じルールを何回も評価します。RuleSessionの初期化に要する時間は、含まれているルールの数によって異なりますが、通常は数秒です。これに対し、ルールの実行に必要なのは、初期化よりはるかに短い時間です。したがって、RuleSessionを1回初期化し、新規の各リクエストに対して再利用することで、パフォーマンスを向上させることができます。RuleSessionプールを使用すると、RuleSessionインスタンスのプールを作成できるため、ルールを使用するアプリケーションのパフォーマンスとスケーラビリティが向上します。
負荷の増加に対応したパフォーマンスを実現するには、複数のRuleSessionが必要です。RuleSessionインスタンスのプールを使用すると、ルールを使用するアプリケーションのパフォーマンスとスケーラビリティが向上します。プールは、RLコードのリストを使用してインスタンス化されます。RLコードは、プールで作成された各RuleSessionを初期化するために使用されます。RLコードは、リストに記載されている順に実行されます。当初に作成するRuleSessionインスタンスの数を指定できます。通常、小さい値を指定しますが、ほとんどの場合、このデフォルト値で十分です。
RLコードは通常、ルールSDKで作成されたRuleDictionaryから生成されます。例4-4は、RuleDictionaryから生成されたRLコードでRuleSessionPoolを作成および使用する方法を示しています。
例4-4 RuleSessionプールの作成方法
RuleDictionary rd; // Code to load rule dictionary not shown List rlList = new ArrayList(); rlList.add(rd.dataModelRL()); List rulesetAliases = rd.getRuleSetAliases(true); for (String alias : rulesetAliases) { rlList.add(rd.ruleSetRL(alias)); } RuleSessionPool pool = new RuleSessionPool(rlList);
アプリケーションで使用中のルールが更新された場合は、後続のルール実行で新しいルールが使用されるように、アプリケーションは新しいルールをロードする必要があります。これをプールでサポートするには、refreshPoolメソッドを起動して新しいRLのリストを渡します。プールが更新されると、getPoolableRuleSessionで戻されるRuleSessionは、新しいRLコードで初期化されています。更新前に取得されたRuleSessionがreturnPoolableRuleSessionを使用して戻された場合、そのRuleSessionはプールに戻されません。更新後のプールに保存されるのは、新しいRLコードで初期化されたRuleSessionのみです。
RuleSessionを使用してルールを実行する場合は、プールからRuleSessionを取得し、実行後にプールに戻します。プール可能なRuleSessionを取得するには、getPoolableRuleSessionメソッドを起動します。プールでは、必要に応じて新しいRuleSessionが作成されます。getPoolableRuleSessionの起動は、空きRuleSessionの待機を妨げることはありません。
ルール実行の完了後、プール可能なRuleSessionをプールに戻すには、returnPoolableRuleSessionメソッドを起動します。プールに戻されたRuleSessionをプールでリセットするには、組込みRL関数のreset()を起動します。これによって、作業メモリーからすべてのファクトが削除され、そのRuleSessionは次の実行のために準備されます。プールから取得したすべてのRuleSessionは、プールに戻す必要があります。ルールの実行中に発生したエラーが原因で今後の使用に適さなくなったRuleSessionは、プールで検出されて廃棄されます。
reset()関数は、作業メモリーの消去に加えて、非ファイナル・グローバル変数のイニシャライザを再実行します。非ファイナル・グローバル変数のイニシャライザを使用すると、必要な場合は、リセット時に他の初期化を実行できます。
例4-5は、プールからRuleSessionを使用する方法を示しています。
例4-5 RuleSessionプールの使用方法
PoolableObject po = pool.getPoolableRuleSession(); RuleSession engine = po.getPooledObject(); // use the RuleSession to execute rules as required here pool.returnPoolableRuleSession(po);
プールのサイズに対するソフト上限を指定できます。この指定によって、一時的な需要の増加に対応するためにプールを拡大する一方、需要の減少時には、プールをソフト上限まで縮小できます。
getPoolableRuleSessionが起動されてプールが空の場合には、RuleSessionプールの実装を使用してRuleSessionインスタンスを作成します。負荷が非常に大きい場合は、ソフト制限を超えるインスタンス件数になります。
負荷の減少に従って、プール内のRuleSesionインスタンスの数は、ソフト制限まで自動的に減少します。