Oracle® Fusion Middleware

Oracle Business Process Managementルール言語リファレンス

12c (12.1.3)

E57536-03(原本部品番号:E40589-04)

2016年11月

Oracleルール言語リファレンスには、Oracle Business Rules RL言語の構文、セマンティクスおよび組込み関数の完全なリファレンスが含まれています。Oracleルール言語は直接作成および編集できますが、通常この言語は高レベルのツールにより生成されます。

Oracle Fusion Middleware Oracle Business Process Managementルール言語リファレンス, 12c (12.1.3)

E57536-03

Copyright © 2005, 2016, Oracle and/or its affiliates All rights reserved.

原本著者: Oracle Corporation

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

このソフトウェアもしくはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアもしくはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

目次

表一覧

タイトルおよび著作権情報

はじめに

- 対象読者

- 関連ドキュメント

- 表記規則

- 本文の表記規則

- RL LanguageのBackus-Naur Form文法ルール

このガイドで説明する新機能

- 12c (12.1.3)での新機能と変更された機能

1 ルール・プログラミングの概念

- 1.1 Oracle Business Rules RL Languageコマンドラインの開始

- 1.2 ルールおよびルールセットの概要

- 1.2.1 ルール条件

- 1.2.2 ルール・アクション

- 1.3 ファクトおよびRL Languageクラスの概要

- 1.3.1 ファクトとは

- 1.3.2 ファクトをアサートして作業メモリーに追加

- 1.3.3 RL Languageクラスをファクトとして使用

- 1.3.4 Javaクラスをファクトとして使用

- 1.4 ルール起動の理解と制御

- 1.4.1 ルールのアクティブ化とアジェンダ

- 1.4.2 ファクト、ルールおよびルールのアクティブ化の監視

- 1.4.2.1 作業メモリー内のファクトの監視と表示

- 1.4.2.2 アクティブ化およびルール起動の監視

- 1.4.3 ルール起動の順序付け

- 1.4.3.1 ルール起動の順序付け

- 1.5 有効日の使用

- 1.6 RL LanguageプログラムとJavaプログラムの統合

- 1.6.1 アサートされたJava Beanをファクトとして使用

- 1.6.1.1 サンプルRL言語プログラム

- 1.6.1.2 Java Beansのファクトとしての使用

- 1.6.2 RuleSessionオブジェクトのJavaアプリケーションでの使用

- 1.7 硬貨カウンタ・ルール・プログラムの作成

2 ルール・エンジンのアルゴリズム

- 2.1 概要

- 2.1.1 ReteアルゴリズムとNREアルゴリズムの違い

- 2.2 Non-Reteアルゴリズムの構成

3 ルール言語リファレンス

- 3.1 ルールセット

- 3.2 型

- 3.3 識別子

- 3.4 リテラル

- 3.5 定義

- 3.5.1 変数定義

- 3.5.1.1 グローバル変数

- 3.5.2 ルール定義

- 3.5.3 クラス定義

- 3.5.3.1 xpathサポート

- 3.5.4 関数定義

- 3.6 ファクト・クラス宣言

- 3.7 import文

- 3.8 include文

- 3.9 式の使用

- 3.9.1 ブール式

- 3.9.2 数式

- 3.9.3 文字列式

- 3.9.4 配列式

- 3.9.5 ファクト・セット式

- 3.9.6 比較式

- 3.9.7 オブジェクト式

- 3.9.8 1次式

- 3.9.8.1 新規

- 3.10 アクションおよびアクション・ブロック

- 3.10.1 if elseアクション・ブロック

- 3.10.2 whileアクション・ブロック

- 3.10.3 forアクション・ブロック

- 3.10.4 try catch finallyアクション・ブロック

- 3.10.5 synchronizedアクション・ブロック

- 3.10.6 modifyアクション

- 3.10.7 returnアクション

- 3.10.8 throwアクション

- 3.10.9 assignアクション

- 3.10.10 インクリメントまたはデクリメント式

- 3.10.11 基本アクション

- 3.11 ルールグループ

- 3.12 組込み関数

- 3.12.1 assert

- 3.12.2 assertTree

- 3.12.3 assertXPath

- 3.12.4 clearRule

- 3.12.5 clearRulesetStack

- 3.12.6 clearWatchRules、clearWatchActivations、clearWatchFacts、clearWatchFocus、clearWatchCompilations、clearWatchAll

- 3.12.7 contains

- 3.12.8 getCurrentDate

- 3.12.9 getDecisionTrace

- 3.12.10 getDecisionTraceLevel

- 3.12.11 getDecisionTraceLimit

- 3.12.12 getEffectiveDate

- 3.12.13 getFactByType

- 3.12.14 getFactsByType

- 3.12.15 getRulesetStack

- 3.12.16 getRuleSession

- 3.12.17 getStrategy

- 3.12.18 halt

- 3.12.19 id

- 3.12.20 isErrorInRuleConditionSuppressed

- 3.12.21 isRulesetsOnStackOnce

- 3.12.22 object

- 3.12.23 println

- 3.12.24 popRuleset

- 3.12.25 pushRuleset

- 3.12.26 retract

- 3.12.27 reset

- 3.12.28 run

- 3.12.29 runUntilHalt

- 3.12.30 setCurrentDate

- 3.12.31 setDecisionTraceLevel

- 3.12.32 setDecisionTraceLimit

- 3.12.33 setEffectiveDate

- 3.12.34 setErrorInRuleConditionSuppressed

- 3.12.35 setRulesetStack

- 3.12.36 setRulesetsOnStack

- 3.12.37 setStrategy

- 3.12.38 showActivations

- 3.12.39 showFacts

- 3.12.40 step

- 3.12.41 watchRules、watchActivations、watchFacts、watchFocus、watchCompilations

4 コマンドライン・インタフェースの使用

- 4.1 コマンドライン・インタフェースの開始と使用

- 4.1.1 コマンドライン入力処理の使用

- 4.2 RLコマンド行のオプション

- 4.3 RLコマンドラインの組込みコマンド

- 4.3.1 clearコマンド

- 4.3.2 exitコマンド

5 RuleSessionの使用

- 5.1 RuleSessionコンストラクタのプロパティ

- 5.2 RuleSessionのメソッド

- 5.3 RL型からJava型への変換

- 5.4 エラー処理

- 5.5 RLクラスの反映

- 5.6 ルール対応プログラムからの結果の取得

- 5.6.1 結果の例の概要

- 5.6.2 外部リソースを使用した結果の取得

- 5.7 RLスタック・トレースのデバッグ

- 5.8 RuleSessionプールの使用

- 5.8.1 RuleSessionプールの作成方法

- 5.8.2 RuleSessionプールの使用方法

- 5.9 RuleSessionオプションの使用

- 5.9.1 CFG_LOGGINGシステム・プロパティの使用

- 5.9.2 CFG_DECISION_TRACE_LEVELオプションの使用

- 5.9.3 CFG_DECISION_TRACE_LIMITオプションの使用

- 5.10 デシジョン・トレースの使用

- 5.10.1 ルール・エンジン・レベルのデシジョン・トレースの概要

- 5.10.2 ルール・エンジン・レベルのデシジョン・トレースの使用

- 5.10.2.1 デシジョン・トレース・レベルの設定

- 5.10.3 本番レベルおよび開発レベルのトレース用のデシジョン・トレースのサンプル

- 5.10.4 開発レベルのデシジョン・トレースのサンプル

A JavaとRLの相違点のサマリー

- A.1 RLがJavaと異なる点

表一覧

- 3-1 暗黙的な型変換

- 3-2 明示的な型変換

- 3-3 RL Languageのリテラル

- 3-4 xpath選択文字列

- 3-5 式演算子の優先順位

- 3-6 集約関数

- 3-7 setStrategyおよびgetStrategy関数の方針の値

- 3-8 watch関数のイベントの説明

- 4-1 RLコマンドラインのオプション

- 5-1 RuleSessionコンストラクタの構成パラメータ

- 5-2 RLからJavaオブジェクトへの変換

- 5-3 RLデシジョン・トレース関数

はじめに

このガイドでは、Oracle Business Rules RL言語について説明します。

対象者

『Oracle Business Process Managementルール言語リファレンス』は、次のタスクを実行するアプリケーション開発者およびOracle Application Server管理者を対象としています。

- ルール対応アプリケーションの開発

- ルール対応アプリケーションのデバッグ

- ルール対応アプリケーションのデプロイおよび管理

- ルール作成の際にOracle Business Rulesグラフィカル環境ではなく技術的な言語環境を好むユーザー向けのルールセットの開発

- Oracle Business Rules環境では使用できないOracle Business Rules RL Languageの高度な機能の使用が必要

このドキュメントを使用するには、Javaプログラミング言語についての知識が必要です。

関連ドキュメント

詳細は、次のOracleドキュメントを参照してください。

- Oracle Business Process Managementを使用したビジネス・ルールの設計

- Oracle Business Process Managementを使用したプロセスの管理とモニタリング

- 『Oracle SOAスイートでのSOAアプリケーションの開発』

表記規則

このセクションでは、このマニュアルの本文およびコード例で使用される表記規則について説明します。この項の内容は次のとおりです。

- 本文の表記規則

- RL LanguageのBackus-Naur Form文法ルール

本文の表記規則

表記規則

意味

太字

太字は、操作に関連するGraphical User Interface要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

イタリック

イタリックは、ユーザーが特定の値を指定するプレースホルダ変数を示します。

固定幅フォント

固定幅フォントは、段落内のコマンド、URL、サンプル内のコード、画面に表示されるテキスト、または入力するテキストを示します。

RL LanguageのBackus-Naur Form文法ルール

このガイドの各RL Languageコマンドは、Backus-Naur Form (BNF)のバリアントで構成される書式で記述されています。BNFには、次の表に示す記号および表記規則が含まれています。

記号または表記規則

意味

[ ]

大カッコは、カッコ内の項目を任意に選択することを表します。

{ }

中カッコは、カッコ内の項目のうち、1つが必須であることを表します。

|

縦線は、大カッコまたは中カッコ内の選択項目を区切ります。

*

アスタリスクは、要素が繰返し可能であることを示します。

デリミタ

大カッコ、中カッコ、縦線、アスタリスクおよび省略記号以外のデリミタは、記載されているとおり入力する必要があります。

太字

太字で示されている単語はキーワードです。キーワードは、表示されているとおり入力する必要があります。

(オペレーティング・システムによっては、キーワードは大文字と小文字が区別されます。)

太字以外の単語は、プレースホルダであり、名前または値を代入する必要があります。

下線

生成規則( ::= )の左側にある場合は、非終端記号の定義を示します。

下線

生成規則(::= )の右側にある場合は、非終端記号のリンクを示し、その非終端記号の定義にリンクします。

イタリックのテキスト

非終端記号に関するセマンティクス情報(式に必要なデータ型または次の説明で使用される記述タグなど)は、イタリックで表記されます。

このガイドで説明する新機能

この項では、Oracle Fusion Middlewareリリース12c (12.1.3)におけるOracleルール言語の新機能と製品の重要な変更点の概要を示します。

使用しているスキンによっては、このガイドで示される画面は実装状態と異なる場合があります。相違点は軽微なものです。

機能とその使用方法の詳細は、このガイドの参照先を確認してください。このドキュメントは、以前の『Oracle Fusion Middleware Oracle Business Rulesランゲージ・リファレンス・ガイド』の新版です。

既知の問題のリスト(リリース・ノート)については、http://www.oracle.com/technetwork/middleware/soasuite/documentation/releasenotes121300-2124738.htmlを参照してください

12c (12.1.3)での新機能と変更された機能

Oracle Rules Languageリリース12c (12.1.3)には、次の新機能と変更された機能が含まれています。

- 新しい非Reteビジネス・ルール・アルゴリズムのサポート。「ルール・エンジンのアルゴリズム」を参照してください。

- 新しい組込み関数のサポート。「組込み関数」を参照してください。

- isErrorInRuleConditionSuppressed

- setErrorInRuleConditionSuppressed

- getFactByType

- isRulesetsOnStackOnce

- setRulesetsOnStackOnce

- Step関数用の2つの新しいシグネチャのサポート。「組込み関数」を参照してください。

- RuleSessionコンストラクタに渡すマップで設定可能な構成パラメータのサポート。「RuleSessionの使用」を参照してください。

1 ルール・プログラミングの概念

この章では、Oracle Business Rules RL Language (RL Language)の概念について説明します。

この章の内容は次のとおりです。

- Oracle Business Rules RL Languageコマンドラインの開始

- ルールおよびルールセットの概要

- ファクトおよびRL Languageクラスの概要

- ルール起動の理解と制御

- 有効日の使用

- RL LanguageプログラムとJavaプログラムの統合

- 硬貨カウンタ・ルール・プログラムの作成

1.1 Oracle Business Rules RL Languageコマンドラインの開始

Oracle Business Rules環境は、rl.jarで提供されるクラスによってJVMコンテナまたはJ2EEコンテナに実装されます。

コマンドライン・インタフェース使用のRL Languageは、次のコマンドを使用して開始します。

java -jar $SOA_ORACLE_HOME/soa/modules/oracle.rules_11.1.1/rl.jar -p "RL> "

ここで、ORACLE_HOMEは、SOAモジュールがインストールされる場所です(例: c:/Oracle/Middleware)。-pオプションはプロンプトを指定します。

RL Languageコマンドライン・インタフェースにより、Oracle Business Rules RuleSessionにアクセスできます。このRuleSessionは、JavaプログラマがJavaアプリケーションでRL LanguageにアクセスするためのAPIです(コマンドライン・インタフェースでは、RuleSessionを内部的に使用します)。

コマンドライン・オプションの詳細は、「コマンド・ライン・インタフェースの使用」を参照してください。Oracle Business Rules RuleSession APIの詳細については、「RuleSessionの使用」を参照してください。

例1-1に示すように、RL>プロンプトにテキストを入力し、コマンドライン・インタフェースを使用してプログラムを実行できます。

例1-1 コマンドライン・インタフェースの使用

RL> println(1 + 2);
3
RL> final int low = -10;
RL> final int high = 10;
RL> println(low + high * high);
90
RL> exit;

1.2 ルールおよびルールセットの概要

RL Languageのルールセットでは、Javaパッケージと同様に、RLクラス、関数およびルール用の名前空間が提供されます。さらに、ルールセットを使用すると、ルールの起動順序を部分的に指定できます。ルールセットには、実行可能なアクションおよびその他のルールセットを含めたり、Javaのクラスやパッケージをインポートすることもできます。

RL Languageのルールは、ルール条件(fact-set-conditionとも呼ばれます)とaction-block(アクションのリスト)で構成されています。ルールは、ルール条件に続いてルール・アクションがあるif-then構造に従っています。

例1-2に、「Hello World」と出力するプログラムを示します。この例は、デフォルト・ルールセット(main)に1つの最上位のアクションがあるプログラムを示しています。例1-2には1つのアクションのみが含まれ、ルールは定義されていないため、アクションはコマンドラインで即時に実行されます。

例1-2 「Hello World」プログラミング例

RL> println("Hello World");Hello World
RL>

1.2.1 ルール条件

ルール条件はルールの1コンポーネントで、ファクトを参照する複数の条件式で構成されています。

次の例では、条件式がファクト(Driverインスタンスのd1)を参照し、次に、そのファクトのデータ・メンバーageが16未満であることをテストします。

if (fact Driver d1 && d1.age < 16)

例1-3に、RL Languageで記述された完全なルールを示します(このルールには、1つのルール条件と1つのルール・アクションが含まれています)。

Oracle Rules Engineは、条件式がtrueになるようなファクトの組合せがあるたびにルールをアクティブにします。ルール条件はOracle Rules Engine内の使用可能なファクト全体に対する問合せのようなもので、問合せから戻される行のそれぞれに対してルールがアクティブになります。

注意:

ルールのアクティブ化とルールの起動は異なります。詳細は、「ルール起動の理解と制御」を参照してください。

例1-3 運転者の年齢ルールの定義

RL> rule driverAge{
if (fact Driver d1 && d1.age < 16)
{
println("Invalid Driver");
}
}

1.2.2 ルールのアクション

ルール・アクションは、すべてのルール条件が満たされた場合にアクティブ化されます。ルールのaction-blockで実行されるアクションには、いくつかの種類があります。たとえば、ルールのaction-block内のアクションでは、assert関数をコールして新規ファクトを追加したり、retract関数をコールしてファクトを削除できます。また、アクションでJavaメソッドやRL Language関数を実行することもできます(例1-3ではprintln関数が使用されています)。アクションを使用すると、パターン一致に関連した任意のタスクを実行する関数をコールできます。

1.3 ファクトおよびRL Languageクラスの概要

この項では、Oracle Business Rulesファクトについて説明します。

次の項が含まれます:

- ファクトとは

- ファクトをアサートして作業メモリーに追加

- RL Languageクラスをファクトとして使用

- Javaクラスをファクトとして使用

1.3.1 ファクトとは

Oracle Business Rulesのファクトは、アサートされたオブジェクトです。Javaオブジェクトの場合、ファクトはオブジェクトのシャロー・コピーです。これは、可能な場合は各プロパティがクローニングされ、それが可能でない場合はファクトがJavaオブジェクト参照のコピーになることを意味します。

RL Languageでは、JavaオブジェクトはJavaクラスのインスタンスであり、RLオブジェクトはRL Languageクラスのインスタンスです。Javaクラスをクラスパスで使用したり、RL Languageクラスを定義してルールセットで使用できます。また、ファクト・クラス宣言を使用して、Javaクラスの既存のプロパティまたはメソッドに関連付けられている追加プロパティを宣言することもできます。さらに、ファクト・クラス宣言を使用して、ファクトで不要なJavaクラスのプロパティを非表示にできます。

RL Languageクラスは、メソッドを除いたJava Beanに類似しています。RLクラスには、複数の名前付きプロパティが含まれます。各プロパティのタイプは、RLクラス、Javaオブジェクトまたはプリミティブ型のいずれかになります。

Oracle Business Rulesを使用する際は、通常、Javaクラス(XMLの使用をサポートしているJAXB生成クラスを含む)を使用して、ルール対応アプリケーションにビジネス・オブジェクトを調べるルールを作成したり、その結果をアプリケーションに戻します。Oracle Rules Engineで他のルールをトリガーできる中間ファクトを作成するには、通常、RLクラスを使用します。

1.3.2 ファクトをアサートして作業メモリーに追加

Oracle Business Rulesでは、作業メモリーを使用してファクトを追加します(ファクトは作業メモリー以外には存在しません)。作業メモリーはRuleSessionに含まれます。

RL Languageのファクトは、クラスのアサートされたインスタンスです。例1-4に、RLクラスenterRoomのインスタンスをファクトとして作業メモリーに追加するassert関数を示します。アサートされたファクトの基礎となるクラスは、JavaまたはRL Languageで定義できます。

例1-4では、sayHelloルールがタイプenterRoomのファクトに一致すると、一致したファクトごとにメッセージが出力されます。assert関数内のアクションnewは、enterRoomクラスのインスタンスを作成します。

例1-4では、run関数によってsayHelloルールが起動します。

注意:

RL LanguageのnewキーワードはJavaのnew機能の拡張で、プロパティに対して初期値を指定できます。

例1-4 RL Languageクラスによる定義したファクトの照合

RL> class enterRoom { String who; }
RL> assert(new enterRoom(who: "Bob"));
RL> rule sayHello {
if ( fact enterRoom ) {
println("Hello " + enterRoom.who);
}
}
RL> run();
Hello Bob
RL>

1.3.3 RL Languageクラスをファクトとして使用

RL Languageクラスをルール・プログラムで使用すると、Javaオブジェクトを提供するJavaアプリケーションのアプリケーション・コードを変更せずに、Javaアプリケーションのオブジェクト・モデルを補完できます。

詳細は、「ファクトをアサートして作業メモリーに追加」を参照してください。

例1-5に、顧客データcustを含むJavaクラスを使用するgoldCustルールを示します。このルールのアクションは、GoldCustomer RLクラスのインスタンスをアサートし、3か月間の支払が500ドルを超える顧客を示します。Java CustomerクラスにはメソッドSpentInLastMonthsが含まれています。このメソッドには、追加する顧客データの月数を示す整数を指定します。

例1-5 goldCustルール

rule goldCust {
if (fact Customer cust && cust.SpentInLastMonths(3) > 500 ){
assert (new GoldCustomer(cust: cust));
}
}

例1-6に示すgoldDiscountルールは、RLファクトGoldCustomerを使用して、過去3か月間に$500の支払があった顧客には10%割引の資格があることを示しています。

例1-6 goldDiscountルール

rule goldDiscount {
if (fact Order ord & fact GoldCustomer(cust: ord.customer) )
{
ord.discount = 0.1;
assert(ord);
}
}

例1-7に、GoldCustomer RLクラスの宣言を示します(ここでは、Customerクラスがクラスパスで使用可能であることを前提にしています)。

例1-7 RL Languageクラスの宣言

class GoldCustomer {
Customer cust;
}

1.3.4 Javaクラスをファクトとして使用

アサートされたJavaオブジェクトは、ファクトとしてRL Languageプログラムで使用できます。Javaクラスを明示的に定義または宣言する必要はありません。ただし、プログラムを実行するときは、Javaクラスをクラスパスに含める必要があります。これによって、Javaクラスをルールで使用でき、ルール・プログラムは、Javaクラスに定義されているpublic属性、publicメソッドおよびBeanプロパティにアクセスして使用できます(一部のアプリケーションにはBeanプロパティが適切です。これは、JavaオブジェクトがPropertyChangeListenerをサポートしていることがOracle Rules Engineで検出される場合があるためです。この場合は、オブジェクトの変更時に通知するメカニズムが使用されます)。

さらに、ファクト・クラス宣言によって、プロパティをRLプログラムで使用できるように微調整できます。また、ファクト・クラス宣言は、継承が行われるいくつかの状況で必要になる場合があります。

Javaファクト・タイプにより、サイド・エフェクトありまたはサイド・エフェクトなしでメソッドをインポートできます。サイド・エフェクトとは、I/O、データベース問合せ、Webサービスなど、コストの高い運用を指します。Javaクラスをファクトとして使用する場合は、サイド・エフェクトの次の点に注意してください。

- ルールおよびデシジョン表の条件では、サイド・エフェクトのあるメソッドを使用しないでください。

- アクションでは、すべてのメソッドを使用できます。サイド・エフェクトはお薦めしませんが、許容はできます。

Javaクラスを使用すると、import文を使用してパッケージ名を省略できます(例1-8を参照)。

例1-8 import文を使用したJavaファクトの例

ruleset main
{
import example.Person;
import java.util.*;
rule hasNickNames
{
if (fact Person p && ! p.nicknames.isEmpty() )
{
// accessing properties as fields:
println(p.firstName + " " + p.lastName + " has nicknames:");
Iterator i = p.nicknames.iterator();
while (i.hasNext())
{
println(i.next());
}
}
}

1.4 ルール起動の理解と制御

この項の内容は次のとおりです。

- ルールのアクティブ化とアジェンダ

- ファクト、ルールおよびルールのアクティブ化の監視

- ルール起動の順序付け

1.4.1 ルールのアクティブ化とアジェンダ

Oracle Rules Engineは、作業メモリーの状態に変化があると、ファクトをすべてのルールのルール条件(fact-set-condition)と照合します。作業メモリー内に変更が生じた場合(通常はファクトがアサートまたは取り消された場合)、Oracle Rules Engineでは、ルール条件に一致するかどうかのみがチェックされます。特定のルール条件がtrueとなるファクトのグループをファクト・セット行と呼びます。ファクト・セットは、特定のルールに対するすべてのファクト・セット行のコレクションです。したがって、ファクト・セットは、1つのルールに含まれる複数のルール条件に一致するファクトで構成されます。ファクト・セット内のファクト・セット行ごとに、ファクト・セット行とルールへの参照で構成されたアクティブ化がアジェンダに追加されます(アジェンダには、アクティブ化の完全リストが含まれます)。

図1-1に示すRuleSessionには、作業メモリー内に、アクティブ化が含まれるアジェンダがあります。

図1-1 作業メモリーとアクティブ化が含まれるアジェンダがあるRuleSession

run、runUntilHaltおよびstepの各関数は、アジェンダにあるアクティブ化を実行します。つまり、これらのコマンドによってルールが起動します(指定した数のアクティブ化を起動するには、stepコマンドを使用してください)。

Oracle Rules Engineがアクティブ化を削除すると、アジェンダからアクティブ化を削除し、ルールのアクションを実行して、ルールが起動します。

Oracle Rules Engineでは、ルール条件が満たされなくなると、ルールを起動せずにアクティブ化を削除できます。たとえば、ファクトが変更された場合、またはルールが消去された場合は、ルールを起動せずにアクティブ化を削除できます。さらに、ファクト・セット行で参照されるファクトが変更された場合、またはファクトが取り消された場合はルール条件に一致しなくなるため、Oracle Rules Engineではアクティブ化がアジェンダから削除されます(新規ファクトがアサートされた場合、および!演算子が適用された場合も同様です)。

ルールのアクティブ化については、次の点に注意してください。

1. アクティブ化が作成されてルールが起動するのは、ファクトがアサート、変更または取り消された場合のみです(それ以外の場合、ルールは連続して起動します)。

2. ルール条件に記述されているファクトがルールによってアサートされた後も、ルール条件がtrueの場合は、新規のアクティブ化がアジェンダに追加され、ルールが再度起動します(この場合、ルールは連続して起動します)。多くの場合、この動作は不適切です。

3. ルール起動に関連したアクションによってファクトが変更、アサートまたは取り消されると、アジェンダにある一連のアクティブ化が変更される場合があり、これによって起動するルールの順序が変更される場合があります。

4. ルールは、同時ではなく順番に起動します。

関連項目:

ルール起動の順序付け

1.4.2 ファクト、ルールおよびルールのアクティブ化の監視

watchActivations、watchFacts、watchRulesおよびshowFactsの各関数は、RL Languageプログラムの記述とデバッグに有用です。

この項の内容は次のとおりです。

- 作業メモリー内のファクトの監視と表示

- アクティブ化およびルール起動の監視

1.4.2.1 作業メモリー内のファクトの監視と表示

次のコード例に、watchFacts関数を示します。この関数は、作業メモリーとの間で追加および削除されたファクトに関する情報を出力します。

次の例に示すように、このwatchFacts関数はファクトがアサートされると==>を出力します。各ファクトにはf-で始まる短い識別子が割り当てられるため、該当するファクトを参照できます。たとえば、アクティブ化にファクトへの参照を含めて、ルール・アクションに渡すことができます。

プログラムはデフォルトのルールセットmainを使用することに注意してください。このルールセットには、enterRoomクラスが含まれています。

RL> watchFacts();
RL>  class enterRoom {String who;}
RL> assert(new enterRoom(who: "Rahul"));
==> f-1 main.enterRoom(who : "Rahul")
RL> assert(new enterRoom(who: "Kathy"));
==> f-2 main.enterRoom(who : "Kathy")
RL> assert(new enterRoom(who: "Tom"));
==> f-3 main.enterRoom(who : "Tom")
RL>

showFactsを使用すると、作業メモリー内の現在のファクトを表示できます。次のサンプル・コード例に、Oracle Rules Engineによる初期ファクトf-0のアサートを示します(Oracle Rules Engineはこのファクトを内部的に使用します)。

RL> showFacts();
f-0   initial-fact()
f-1   main.enterRoom(who : "Rahul")
f-2   main.enterRoom(who : "Kathy")
f-3   main.enterRoom(who : "Tom")
For a total of 4 facts.

作業メモリーからファクトを削除するには、次の例に示すようにretractを使用します。watchFactsが有効な場合は、ファクトを取り消すと、Oracle Rules Engineは<==を出力します。

RL> watchFacts();
RL> retract(object(2));
<== f-2 main.enterRoom(who : "Kathy")
RL> showFacts();
f-0   initial-fact()
f-1   main.enterRoom(who : "Rahul")
f-3   main.enterRoom(who : "Tom")
For a total of 3 facts.

1.4.2.2 アクティブ化およびルール起動の監視

watchActivations関数はOracle Rules Engineを監視し、アジェンダとの間で追加および削除されたルールのアクティブ化に関する情報を出力します。watchRules関数は、ルール起動に関する情報を出力します。

例1-9に、run関数を使用してアクティブ化を起動する方法を示します。最初に入室したRahulへの応対が最後になっていることに注意してください(これは、起動順序のためです)。

注意:

アクティブ化は、関連するファクトが条件を満たさなくなった場合、起動する前にアジェンダから削除できます。

例1-9 WatchActivationsおよびWatchRulesの使用

RL> clear;
RL> class enterRoom {String who;}
RL> assert(new enterRoom(who: "Rahul"));
RL> assert(new enterRoom(who: "Kathy"));
RL> assert(new enterRoom(who: "Tom"));
RL> watchActivations();
RL> rule sayHello {
if (fact enterRoom) {
println("Hello " + enterRoom.who);
}
}
==> Activation: main.sayHello :  f-1
==> Activation: main.sayHello :  f-2
==> Activation: main.sayHello :  f-3
RL> watchRules();
RL> run();
Fire 1 main.sayHello f-3
Hello Tom
Fire 2 main.sayHello f-2
Hello Kathy
Fire 3 main.sayHello f-1
Hello Rahul
RL>

1.4.3 ルール起動の順序付け

アジェンダにあるルールのアクティブ化を起動する順序付けアルゴリズムを理解するために、ルールセット・スタックについて説明します。各RuleSessionには、1つのルールセット・スタックが含まれています。RuleSessionのルールセット・スタックには、フォーカス・ルールセットと呼ばれる最上位のスタックがあります。このルールセット・スタックには、フォーカス・ルールセット以外のルールセットも含まれます。ルールセット・スタックにルールセットを追加するには、pushRulesetまたはsetRulesetStack組込み関数のいずれかを使用します。ルールセット・スタックのルールセットを管理するには、clearRulesetStack、popRulesetおよびsetRulesetStack関数を使用できます。この場合、ルールセット・スタックのフォーカスは、ルールセット・スタック内の現行の最上位ルールセットになります。

RuleSet Stack

Focus Ruleset  -->     Top_Ruleset
Next_down_Ruleset
Lower_Ruleset
Bottom_Ruleset

アジェンダにアクティブ化がある場合、Oracle Rules Engineは、run、runUntilHaltまたはstepが実行されるとルールを起動します。Oracle Rules Engineは、次の順序付けアルゴリズムを使用して、アジェンダにあるすべてのアクティブ化からルールのアクティブ化を順に選択します。

1. Oracle Rules Engineは、フォーカス・ルールセット(つまり、ルールセット・スタックの最上位にあるルールセット)のすべてのルールのアクティブ化を選択します(pushRulesetおよびsetRulesetStack組込み関数を参照)。

2. フォーカス・ルールセットに関連付けられた複数のアクティブ化内では、ルールの優先度によって起動順序が指定されます。優先度の高いルールのアクティブ化が、優先度の低いルールのアクティブ化よりも先に選択されて起動します(デフォルトの優先度レベルは0です)。

3. フォーカス・ルールセット内で複数のルールのアクティブ化が同じ優先度の場合は、最後に追加されたルールのアクティブ化から起動します。ただし、複数のアクティブ化がアジェンダに同時に追加された場合、それらのアクティブ化の起動順序は定義されません。

4. 現行フォーカス・ルールセット内のルールのアクティブ化がすべて起動すると、Oracle Rules Engineはルールセット・スタックを削除し、プロセスは現行フォーカスで、ステップ1に戻ります。

R1という名前の一連のルールは、R2という名前の一連のルールよりも前にすべて起動する必要がある場合、次のいずれかの処理方法があります。

- 1つのルールセットを使用し、R1内のルールの優先度をR2内のルールの優先度よりも高く設定します。

- R1とR2の2つのルールセットを使用し、ルールセット・スタックにR2を追加してからR1を追加します。

一般的には、1つのルールセットを使用して優先度を設定するよりも、ルールセット・スタックで2つのルールセットを使用する方が柔軟にルールの起動順序を制御できます。たとえば、R1内のすべてのルールが起動する前に、R1内のルールRが、R2内のあるルールをトリガーする必要がある場合は、R内のreturnアクションによってルールセット・スタックが削除されるため、R2内のルールを起動できます。

ルールの2つのセット間で実行を交互に実行する必要がある場合(たとえば、ファクトを作成するルールとファクトを削除するルール)は、異なる2つの優先度を使用するよりも、2つのルールセットを使用する方がフローの流れが簡単になります。

次のコード例では、keepGaryOutルールの優先度がhighに設定されています。これはsayHelloルールの優先度よりも高くなっています(デフォルトの優先度は0です)。両方のルールのアクティブ化がアジェンダにある場合は、優先度の高いルールが先に起動します。runをコールする前に、sayHelloには2つのアクティブ化がアジェンダにあることに注意してください。keepGaryOutが最初に起動するため、enterRoom(who: "Gary")ファクトが取り消され、これによって対応するsayHelloアクティブ化が削除されます。その結果、1つのsayHelloのみが起動します。

次のコード例に示すルールでは、次の2つのRL Language機能が示されています。

1. fact演算子(ファクト・セット・パターンとも呼ばれます)は、オプションのvarキーワードを使用し、一致するファクトにバインドする変数(ここでは変数g)を定義します。

2. 作業メモリー内のファクトは、retract関数を使用して削除できます。

RL> final int low = -10;
RL> final int high = 10;
RL> rule keepGaryOut {
priority = high;
if (fact enterRoom(who: "Gary") var g) {
retract(g);
}
}
RL> assert(new enterRoom(who: "Gary"));
==> f-4 main.enterRoom(who: "Gary")
==> Activation: main.sayHello : f-4
==> Activation: main.keepGaryOut : f-4
RL> assert(new enterRoom(who: "Mary"));
==> f-5 main.enterRoom(who: "Mary")
==> Activation: main.sayHello : f-5
RL> run();
Fire 1 main.keepGaryOut f-4
<== f-4 main.enterRoom(who: "Gary")
<== Activation: main.sayHello : f-4
Fire 2 main.sayHello f-5
Hello Mary
RL>

例1-10に、アサートされたenterRoomファクトと一致する条件を含むsayHelloルールを示します。この一致によって、アクティブ化がアジェンダに追加されます。例1-10では、次のRL Languageプログラミング機能を示します。

1. Oracle Rules Engineは、作業メモリーの状態に変化があると、ファクトをすべてのルールのルール条件(fact-set-condition)と照合します。したがって、ファクトがアサートされるのがルールの定義前か後かは関係ありません。

2. run関数は、アジェンダにあるすべてのアクティブ化を処理します。runのコール前にアジェンダのアクティブ化が処理されることはありません。

例1-10 sayHelloルールを伴うenterRoomクラス

RL> class enterRoom { String who; }
RL> rule sayHello {
if ( fact enterRoom ) {
println("Hello " + enterRoom.who);
}
}
RL> assert(new enterRoom(who: "Bob"));
RL> run();
Hello Bob
RL>

1.4.3.1 ルール起動の順序付け

ルール起動の順序付けをする場合の重要な詳細に注意してください。

- returnアクションを使用すると、ルール起動の動作が変更されます。ルール内のreturnアクションでは、ルールセット・スタックからルールセットが削除されるため、実行は、現在ルールセット・スタックの最上位にあるルールセットからのアジェンダに存在するアクティブ化で続行されます。
ルールの実行がrunまたはstep関数で開始され、returnアクションによってルールセット・スタックから最後のルールセットが削除された場合、制御はrunまたはstep関数のコール元に戻されます。

ルールの実行がrunUntilHalt関数で開始された場合、returnアクションではルールセット・スタックから最後のルールセットは削除されません。最後のルールセットは、残っているアクティブ化がなくなったときにrunUntilHaltで削除されます。その後、Oracle Rules Engineは次のアクティブ化の出現を待機します。アクティブ化が出現すると、ルールセットの起動が再開される前に、ルールセット・スタックに最後のルールセットが配置されます。

- ルールの優先度は、指定したルールセット内のルールにのみ適用されます。したがって、別のルールセット内のルールの優先度とは比較できません。

1.5 有効日の使用

デフォルトでは、有効日の値は、ルール・エンジンによって暗黙的に管理されます。この場合、組込み関数のrunファミリが起動されると、有効日が現在のシステム日付に更新されます。これは、任意のルールが起動される前に実行されます。そのため、新しい有効日は、ルールの起動が開始される前に適用されます。runUntilHaltの場合は、アジェンダにあるルールが0個から1個以上に遷移するたびに、この更新が実行されます。

Oracle Business Rules RL Languageでは、有効開始日、有効終了日およびactiveプロパティのみがルールに適用されます(ルールセットには適用されません)。ルールの有効開始日および有効終了日のプロパティは、ルール内に指定できます。

次に例を示します。

rule myrule2 {
active = true;
effectiveDateForm = Rule.EDFORM_DATETIME:
effectiveStartDate = JavaDate.fromDateTimeString("2008-11-01");
effectiveEndDate = JavaDate.fromDateTimeString("2008-11-16");

if (fact Foo)
{
.
.
}

}

If you use the RuleSession Java API, you can access the effective start and end date.

RL Languageからプロパティを設定するには、長い式またはいくつかの文が必要です。

たとえば、次のようなルールセットがあるとします。

ruleset MyRules {
rule myRule { if fact foo { }}
}

activeプロパティを設定するには、次を使用します。

Rule r = getRuleSession().getRuleset("MyRules").getRule("myRule");

r.setActive(false);

1.6 RL LanguageプログラムとJavaプログラムの統合

この項では、RL LanguageプログラムとJavaプログラムの統合について説明します。

この項の内容は次のとおりです。

- アサートされたJava Beanをファクトとして使用

- RuleSessionオブジェクトのJavaアプリケーションでの使用

関連項目:

詳細は、『Oracle Business Process Managementによるビジネス・ルールの設計』の「スタンドアロン(非SOA/BPM)シナリオでのルールの使用」を参照してください

1.6.1 アサートされたJava Beanをファクトとして使用

例1-11に、単純なBeanのJavaソースを示します。例1-11に示したBean example.Personをjavacコマンドを使用してディレクトリ・ツリーにコンパイルします。

次に、このBeanにアクセスするためのRL Languageコマンドラインの開始方法を示します。

java -classpath $ORACLE_HOME/soa/modules/oracle.rules_11.1.1/rl.jar;BeanPath oracle.rules.rl.session.CommandLine -p "RL> "

BeanPathは提供されているJava Beanクラスへのクラスパス・コンポーネントです。

例1-11 Person BeanクラスのJavaソース

package example;
import java.util.*;
public class Person
{
private String firstName;
private String lastName;
private Set nicknames = new HashSet();

public Person(String first, String last, String[] nick) {
firstName = first; lastName = last;
for (int i = 0; i < nick.length; ++i)
nicknames.add(nick[i]);
}
public Person() {}
public String getFirstName() {return firstName;}
public void setFirstName(String first) {firstName = first;}
public String getLastName() {return lastName;}
public void setLastName(String last) {lastName = last;}
public Set getNicknames() {return nicknames;}
}

1.6.1.1 サンプルRL言語プログラム

例1-12に、example.Personを使用するRL LanguageプログラムをRL Languageコマンドラインで実行する方法を示します。Javaと同様に、import文を使用し、example.PersonのかわりにPersonを使用すると、Personクラスへの参照が可能になります。ルールは、Person Beanクラス、およびそのプロパティとメソッドを参照します。Personファクトを作成するためには、Java Person Beanをアサート(assert)する必要があります。

例1-12では、new演算子を使用して、peopleという名前のPersonオブジェクトの配列を作成します。people配列でfinalが宣言されているため、resetによるpeopleの追加作成はありません。numPeople変数ではfinalが宣言されていないため、resetによってassertPeople関数が再起動し、既存のPersonオブジェクトを使用してPersonファクトが再度アサートされます。

例1-12 Person Beanクラスを使用するルールセット

ruleset main
{
import example.Person;
import java.util.*;
rule hasNickNames
{
if (fact Person(nicknames: var nns) p && !nns.isEmpty())
{
// accessing properties as fields:
println(p.firstName + " " + p.lastName + " has nicknames:");
Iterator i = nns.iterator();
while (i.hasNext())
{
println(i.next());
}
}
}
rule noNickNames
{
if fact Person(nicknames: var nns) p && nns.isEmpty()
{
// accessing properties with getters:
println(p.getFirstName() + " " + p.getLastName() + " does not have nicknames");
}
}
final Person[] people = new Person[] {
new Person("Robert", "Smith", new String[] { "Bob", "Rob" }), // using constructor
new Person(firstName: "Joe", lastName: "Schmoe") // using attribute value pairs
};

function assertPeople(Person[] people) returns int
{
for (int i = 0; i < people.length; ++i) {
assert(people[i]);
}
return people.length;
}
int numPeople = assertPeople(people);
run();
}

1.6.1.2 Java Beansのファクトとしての使用

Java Beansをファクトとして使用する場合は、次の点に注意してください。

- fact演算子では、一致するパターンを含めたり、Beanプロパティを取得できます。プロパティは、Beanクラスのgetterおよびsetterメソッドによって定義されます。

- new演算子では、デフォルトの引数なしのコンストラクタを起動した後にプロパティ値を設定するパターンを含めたり、引数をユーザー定義コンストラクタに渡すことができます。

- factおよびnew演算子の外側では、getterおよびsetterメソッドを使用するか、あるいはフィールドのようにプロパティ名を使用して、Beanプロパティを参照または更新できます。

- Beanに同じ名前のプロパティとフィールドがある場合、そのフィールドはRL Languageでは参照できません。

例1-12を実行した後に、同じRuleSessionを使用して例1-13を実行した場合、出力は例1-12の結果と同じになります(両方のpersonファクトが再アサートされます)。

注意:

RL Languageコマンドライン・インタプリタは、起動時(およびclearコマンドの使用時)にRuleSessionを内部的に作成します。

例1-13 RuleSessionでのresetの使用

reset();
run();

1.6.2 RuleSessionオブジェクトのJavaアプリケーションでの使用

Javaプログラムでは、RuleSessionインタフェースを使用して、ルールセットの実行、Javaオブジェクトを引数として渡すRL Language関数の起動、およびRL Languageのwatchおよびprintln出力のリダイレクトを行うことができます。例1-14および例1-15に、「hello world」を出力するRuleSessionを使用するJavaプログラムのフラグメントを示します。多くのJavaプログラムのフラグメントと同様に、これらの例もRL Languageプログラムとして有効です。

RL Language環境では、複数のルール・セッションを使用できます。各ルール・セッションは複数のスレッドで使用できますが、ルールは一度に1つのスレッドで起動します。

各ルールのRuleSessionには、ファクトとルールの独自のコピーがあります。ファクトをJavaオブジェクトから作成するには、次のようなコールを使用します。

rs.callFunctionWithArgument("assert", Object;);

ルール、関数またはRL Languageクラスを作成するには、ルールセットを含む文字列を定義し、executeRulesetメソッドを使用します。

例1-14 callFunctionWithArgumentを使用するRuleSessionオブジェクトの使用

import oracle.rules.rl.*;
try {
RuleSession rs = new RuleSession();
rs.callFunctionWithArgument("println", "hello world");
} catch (RLException rle) {
System.out.println(rle);
}

例1-15 executeRulesetを使用するRuleSessionの使用

import oracle.rules.rl.*;
try {
RuleSession rs = new RuleSession();
String rset =
"ruleset main {" +
" function myPrintln(String s) {" +
" println(s);" +
" }" +
"}";
rs.executeRuleset(rset);
rs.callFunctionWithArgument("myPrintln", "hello world");
} catch (RLException rle) {
System.out.println(rle);
}

1.7 硬貨カウンタ・ルール・プログラムの作成

この項では、RL Languageを使用して次のパズルを解く例を示します。

50個の硬貨を使用して合計金額を1ドル50セントにする方法は何通りあるか?

このパズルを解くルール・プログラムには、ルールベース・プログラミングの重要なポイントが含まれています。知識表現、つまり、選択するファクト・クラスが設計上の重要な問題になる可能性があります。ルールで照合および処理するためにデータを便利なフォーマットに整えるには、多くの場合、手続きコードを記述することが有効です。

この例を使用するには、最初に、例1-16に示したRL Languageプログラムをcoins.rlという名前のファイルにコピーします。このプログラムは、RL Languageコマンドラインからincludeコマンドを使用してインクルードできます。coinsプログラムをインクルードする前に、次のようにclear;コマンドを使用して、現行のルール・セッション内をすべて消去します。

RL> clear;
RL> include file:coins.rl;
RL>

次のコード例に示したデバッグ関数は、硬貨カウンタに関する、硬貨カウントのサンプル・ファクト、アクティブ化およびルールを示しています。すべてのファクトはアサートされ、すべての解答のアクティブ化がアジェンダに配置されます。ファクトはpopulate_factsで生成されると、ルール条件と照合され、find_solutionでは一致が出力されることに注意してください。

RL> watchFacts();
RL> watchActivations();
RL> watchRules();
RL> reset();
RL> showActivations();
RL> run();
The rule is fired for each activation, printing out the solutions
RL>

例1-16では、coinCount、totalAmountなどのグローバル変数定義の先頭にあるキーワードfinalによって、Javaと同様に、変数が定数としてマークされます。ルール条件の定数は参照できますが、変数は参照できません。

RL Languageでは、すべての変数を初期化する必要があります。final変数を初期化する式は、変数の定義時に1回評価されます。final以外の変数を初期化する式は、変数の定義時およびreset関数がコールされるたびに評価されます。reset関数によってすべてのファクトが作業メモリーから取り消されるため、初期ファクトは、グローバル変数を初期化する式でアサート(assert)することをお薦めします。これによって、resetがコールされるとファクトが再度アサートされます。

例1-16に、グローバル変数を初期化する式の使用方法を示します。initializedグローバル変数は、populate_facts関数を使用して初期化されます。この関数は、resetがコールされるたびに再実行されます。このpopulate_facts関数には、forループ内にネストされたwhileループがあります。このforループは、硬貨の額面を示す文字列の配列に対して反復されます。whileループは、硬貨の額面ごとに、カウントと合計(合計金額は$1.50を超えません)を表すファクトをアサートします。たとえば、50セント硬貨の場合は次のようになります。

coin(denomination "half-dollar", count:0, amount:0)
coin(denomination "half-dollar", count:1, amount:50)
coin(denomination "half-dollar", count:2, amount:100)
coin(denomination "half-dollar", count:3, amount:150)

このようなファクトを作業メモリーで使用すると、カウントの合計をcoinCountに、金額の合計をtotalAmtにする必要がある条件を使用して、ルールfind_solutionが各額面に対して照合されます。find_solutionのアクティブ化は、run関数によって起動します。

例1-16 硬貨カウントのプログラム・ソース

final int coinCount = 50;
final int totalAmt = 150;
final String[] denominations = new String[]
{"half-dollar" , "quarter", "dime", "nickel", "penny" };
class coin {
String denomination;
int count;
int amount;
}
function populate_facts() returns boolean
{
for (int i = 0; i < denominations.length; ++i) {
String denom = denominations[i];
int count = 0;
int total = 0;
int amount = 0;
if (denom == "half-dollar" ) { amount = 50; }
else if (denom == "quarter" ) { amount = 25; }
else if (denom == "dime" ) { amount = 10; }
else if (denom == "nickel" ) { amount = 5; }
else { amount = 1; }

while (total <= totalAmt && count <= coinCount)
{
assert(new coin(denomination: denom,
count : count,
amount : total));
total += amount;
count ++;
}
}
return true;
}
boolean initialized = populate_facts();
rule find_solution
{
if(fact coin(denomination: "penny") p
&& fact coin(denomination: "nickel") n
&& fact coin(denomination: "dime") d
&& fact coin(denomination: "quarter") q
&& fact coin(denomination: "half-dollar") h
&& p.count + n.count + d.count + q.count + h.count == coinCount
&& p.amount + n.amount + d.amount + q.amount + h.amount == totalAmt)
{
println("Solution:"
+ " pennies=" + p.count
+ " nickels=" + n.count
+ " dimes=" + d.count
+ " quarters=" + q.count
+ " half-dollars=" + h.count
);
}
}
run();

2 ルール・エンジンのアルゴリズム

この章では、ルール・エンジンで使用される既存のReteアルゴリズムについて説明するとともに、Non-Reteアルゴリズムを紹介します。

この章の内容は次のとおりです。

- 概要

- Non-Reteアルゴリズムの構成

2.1 概要

Reteアルゴリズムはチャールズ・フォーギー氏により発明されたもので、彼が1979年に発表した博士論文のテーマでした。当時のエキスパート・システムで使用するために考案されたもので、ルール・エンジンの作業メモリー内のファクトは一連の推論サイクルにわたって徐々に変化するという知見に基づいています。その威力のほとんどは、パフォーマンス向上とメモリー使用量増大のトレードオフの上に成り立っています。

以前のルール条件の評価結果をキャッシングしておけば、作業メモリーに小さな変更を加えるたびに、すべてのルール条件を再評価する必要がなくなります。しかし、ビジネス・ルールのユース・ケースの多くは、このような使用プロファイルには適合しないため、Reteアルゴリズムを使用するメリットが得らないうえに、このアルゴリズム特有のメモリー消費に関するオーバーヘッドも発生します。

Non-Reteアルゴリズム(NRE)は、Reteアルゴリズムの代替で、Reteアルゴリズムと比較して消費メモリーが少なくなります。ビジネス・ルールのユース・ケースの多くでは、パフォーマンスも向上します。NREアルゴリズムの中核は、新しいルール条件評価アプローチにあります。ルール・エンジンの大部分は変更されることなく、ReteアルゴリズムとNREアルゴリズムで共有されます。外部で定義された既存のReteアルゴリズムのセマンティクスは、NREアルゴリズムでも保持されます。次に、新しいアルゴリズムの重要なポイントをいくつか示します。

- より簡素化された内部ルール表現。

- ルール・テスト、ルール・アクション、およびユーザー定義の関数のために生成されたバイト・コード。

- より効率的な変更操作。

- ルール条件は、それを含んでいるルールセットがスタックの先頭になるまでは評価されない。最初の評価の後、必要に応じてファクト操作で再評価が行われる。

- ルール実行中にルールセット・スタックにルールセットが1回のみ存在する場合は、不要な再評価を回避できる。

2.1.1 ReteアルゴリズムとNREアルゴリズムの違い

2つのアルゴリズムの間の2つの主な相違は次のとおりです。

- ルール条件の評価:

- Reteアルゴリズムでは、ルール条件はファクト操作(アサート、変更、リトラクト)が行われるときに評価されます。

- 非Reteアルゴリズムでは、ルール条件は、そのルールセットがスタックの先頭になったときに初めて評価され、その後のファクト操作で評価されます。

- ルールの起動順序。ルールの起動順序が定義されていない場合があります。たとえば、1つのファクトによって複数のルールが同時にアクティブ化され、それらのプロパティが同一である場合です。このような場合、ルールのアクティブ化の起動順序は異なることがあります。

注意:

ルールの既存のセットが、Reteアルゴリズムでのそのルールの起動順序が定義されていない可能性があっても、その順序に明示的に依存していることがあります。Non-Reteアルゴリズムではその順序が異なる場合があるため、作成したルールの潜在的な不具合の原因になりかねません。

2.2 非Reteアルゴリズムの構成

使用するアルゴリズムの選択は、RuleSessionまたはRuleSessionPoolの作成時に行う必要があります。

後方互換性を確保するために、デフォルトはReteアルゴリズムになります。アルゴリズム構成パラメータで鍵となるのはRuleSession.CFG_ALGORITHMで、次の2つの値があります。

- RuleSession.ALGORITHM_RETE

- RuleSession.ALGORITHM_NRE

また、RuleSession.CFG_ALLOW_ERROR_SUPPRESSIONという構成パラメータもあります。これはブール型です。デフォルトは、trueです。falseに設定すると、エラーの抑制が有効化されないことがルール・エンジンに通知されます。この場合、エラーの抑制を有効にしようとすると、例外がスローされます。この設定により、Non-Reteアルゴリズムではヒープをさらに節約できます。

ルールの実行中に複数のルールセットが実行されることがよくあります。また、各ルールセットがルールセット・スタックにプッシュされて、そのルールセット内のルールが起動されたら、そのルール実行中にはスタックに再プッシュされないのが一般的です。Non-Reteアルゴリズムでは、スタックにおけるルールセットの出現回数を1回に限定して指定することで、このようなケースでのパフォーマンスの向上を実現できます。この設定は、次のRL組込み関数で設定および問合せ可能です。

- function setRulesetsOnStackOnce(boolean bv) returns boolean

- function isRulesetsOnStackOnce() returns boolean

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の今後のリリースで使用される予定です。

この章の内容は次のとおりです。

- ルールセット

- 型

- 識別子

- リテラル

- 定義

- ファクト・クラス宣言

- import文

- 式の使用

- アクションおよびアクション・ブロック

- ルールグループ

- 組込み関数

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)が含まれています。

次のコード例で示されているルールは、次の条件が満たされるまで起動されません。

1. enterRoomファクトがアサートされる。

2. 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

型変換

値をある型から別の型に変換する方法はいくつかあります。

1. String連結演算子+を使用した、任意の型からStringへの変換。

2. コンテキストからの暗黙的変換。たとえば、intをdoubleに加算する場合は、最初にintがdoubleに変換され、その後で2つのdoubleが加算されます。

3. 2つの数値型間のキャスト。

4. 継承で関連付けられた2つのクラス間のキャスト

5. 変換を実行する関数またはメソッドの起動。たとえば、toStringです。

表3-1は、様々な型の暗黙的変換の要約です。各行は、「変換元」列の型が、「変換先」列の型リストに示されているように暗黙的に変換される可能性があることを示しています。

表3-1 暗黙的な型変換

変換元

変換先

int

double、float、long

float

double

long

double、float

short

int、double、float、long

byte

int、double、float、long、short

char

int、double、float、long

String

Object

Object

Object(変換元オブジェクトが変換先オブジェクトのサブクラスの場合)

fact set

boolean

array

Object

注意:

オブジェクトはJavaまたはRL Languageのクラスまたは配列のインスタンスです。型変換が可能であるのは、クラスが継承(実装または拡張)で関連付けられている場合のみです。

表3-2は、様々な型について許可されているキャスト変換の要約です。キャストを使用すると、ビット数の多いプリミティブ型をビット数の少ないプリミティブ型に、例外をスローすることなく変換できます。

表3-2に示されている型変換には、明示的なキャスト演算子が必要です。次に例を示します。

int i = 1;
short s = (short)i;

注意:

表3-2に示されているような数値型を含む型変換では、上位ビットが失われる可能性があり、オブジェクトが関係するこのような変換では、RLClassCastExeptionがスローされる場合があります。

表3-2 明示的な型の変換

変換元

変換先

double

float、long、int、short、byte、char

float

long、int、short、byte、char

long

int、short、byte、char

short

byte、char

byte

char

char

byte

キャストを使用して、ビット数の多いプリミティブ型をビット数の少ないプリミティブ型に変換するとき、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ではマルチディメンション配列はサポートされていません。

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エンコーディングのchar

byte、char、short、int、long、float、double

範囲0から65535の整数またはchar

char、int、long、float、double

範囲-128から127の整数

byte、short、int、long、float、double

範囲-32768から32767の整数

short、int、long、float、double

整数

int、long、float、double

末尾がLの整数

long、float、double

浮動小数点定数

double

末尾がFの浮動小数点定数

float、double

""で囲まれた文字列

String、Object

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のクラス定義のqnameはhello.enterRoomです。

例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つの事項が発生する必要があります。

1. そのルールのアクティブ化がアジェンダに存在すること。

2. 包含ルールセットがルールセット・スタックの最上位にあること。

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は、例3-9の実行結果を示しています。

例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では、祖先のすべてのペアが出力されます。最初に、ファミリ・ツリーがアサートされます。例3-13は、例3-12のコードの実行結果を示しています。

例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;

ファクト・コンテキスト内の出現順が次のようになる例の場合

1. fact class T

2. assertXPath AImpl

3. assert TImpl (assertXPath実装で内部的に実行)

AImplは順序付けでTImplより前にありますが、AImplはTImplを拡張し、このため例外が発生します。このファクト・コンテキストの修正は、手順2の前の任意の場所でfact class TImpl;を明示的に発行することです。

3.7 import文

import文では、Javaクラスの参照時にパッケージ名修飾を省略できます。

構文

import ::= import ( Java-class-name | Java-package-name* ) ;

Java-package-name ::= qname

使用上の注意

インポート・コマンドはルールセット内に配置でき、インポートのスコープが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)

式は条件またはアクションで使用しますが、いくつか制限事項があります。式は厳密に型指定されます。

構文

expression ::= boolean-expression

| numeric-expression

| string-expression

| array-expression

| fact-set-expression | object-expression

| comparable-expression

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-expression

| boolean-primary-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

+ , -

加算または減算

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-primary-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-primary-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

| ! fact-set-expression

| exists fact-set-expression

| fact-set-pattern

| (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には次のものを含めることはできません。

- アサート

- 変更

- new

- 非ファイナル・グローバル変数の参照

演算子の優先順位は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 集計関数

関数

説明

average()

一致するファクトの平均を計算します。結果はdoubleです。

sum()

一致するファクトの合計を計算します。結果はdoubleまたはlongです。

count()

結果はlongです。

minimum()

一致するファクトの最小値を計算します。

maximum()

一致するファクトの最大値を計算します。

collection()

結果はファクトのjava.util.Listです。

ユーザー定義

結果の型が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.6 比較式

比較式では、==、!=、<、<=、>および>=演算子を使用して、java.lang.Comparableを実装するオブジェクトを比較できます。この式を使用すると、日付を簡単に比較できます。また、金額を表すために通常使用されるBigDecimalをこの式で比較できます。

構文

comparable-expression ::=

java.lang.Comparableを実装する型のjava.lang.Comparable | memberを実装する型のqname変数

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

| string-primary-expression

| numeric-primary-expression

| boolean-primary-expression

| object-primary-expression

array-primary-expression ::=

array-constructor

| (配列を戻す)function-call

| (1次元のJava配列を戻す)method-call*

| ( array-expression )

| array-target-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

numeric-target-expression ::=

qname(数値型の変数)

| (数値型の)member

| array-primary-expression(ベース型は数値) [ numeric-expression ]

boolean-primary-expression ::=

boolean-literal

| (ブールを戻す)function-call

| (ブールを戻す)method-call

| ( boolean-expression )

| boolean-target-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

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

| assign | incr-decr-expression | primary-action

action-block ::= { ( variable | action )* }

使用上の注意

アクション・ブロックは、任意の数のローカル変数宣言とアクションです。変数は、同じアクション・ブロック内の後続の変数初期化式およびアクションで参照可能です。

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にはアクション・ブロックが必要であり、単一のセミコロンの終了アクションは許可されていません。

構文

if ::= if if-test action-block [ else if | action-block ]

if-test ::= boolean-expression

例

例3-34は、RL Languageのif elseアクション・ブロックを示しています。例3-35は、アクション・ブロックが必要であることを示しています。

例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アクション・ブロック

テストがtrueの間はアクション・ブロックが実行されます。return、throwまたはhaltでアクション・ブロックを終了できます。

構文

while ::= while while-test action-block

while-test ::= boolean-expression

使用上の注意

Javaと異なり、RL Languageにはアクション・ブロックが必要であり、単一のセミコロンの終了アクションは許可されていません。

例

例3-36では"bye"が2回出力されます。

例3-36 whileアクションの例

int i = 2;
while (i-- > 0) {
println("bye");
}

例3-37 アクション・ブロックのない無効なwhileアクション

while (i-- > 0) println("no");

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で捕捉できます。

構文

throw ::= throw throwable ;

throwable ::= object-primary-expression

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 decrementアクション

clear;
int i = 1;
--i;
println(i);

3.10.11 primaryアクション

基本アクションは、関数コール、assertまたはJavaメソッド・コールなど、その二次的作用のために実行される基本的な式です。たとえば、println関数は基本アクションとしてよく使用されます。

構文

primary-action ::= primary-expression ;

3.11 Rulegroup

ルールグループでは、デシジョン表のオーバーライドがサポートされます。これにより、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では「Pavi has highest salary 65000.0」と出力され、例3-46では「dept 10 has no employees!」と出力されます。

例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();

関連項目:

assertTree、id、object、retract

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インスタンスをアサートし、それに含まれる値クラス・オブジェクトを抽出して続行します。

関連項目:

assert

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);

関連項目:

assert、id、object、retract

3.12.4 clearRule

名前付きのルールをルール・セッションから消去します。ルールのアクティブ化はすべてアジェンダから削除されます。

構文

function clearRule(String 名前);

関連項目:

getRuleSession

3.12.5 clearRulesetStack

ルールセット・スタックを空にします。

構文

function clearRulesetStack();

関連項目:

getRulesetStack、getStrategy、popRuleset、pushRuleset、run、setStrategy

3.12.6 clearWatchRules、clearWatchActivations、clearWatchFacts、clearWatchFocus、clearWatchCompilations、clearWatchAll

clearWatch関数は、デバッグ情報の出力を停止します。

構文

function clearWatchRules(); function clearWatchActivations(); function clearWatchFacts(); function clearWatchFocus(); function clearWatchCompilations(); function clearWatchAll();

関連項目:

watchRules_ watchActivations_ watchFacts_ watchFocus_ watchCompilations

3.12.7 contains

contains()関数はJava Collectionのcontains()メソッドに似ていますが、コレクション内のJAXBElementの存在を処理する機能を持っています。

構文

contains(Collection c, Object o) returns boolean

使用方法

contains()は、コレクションc内でJAXBElementを検出すると、そのJAXBElementから値クラスを取得して、オブジェクトoと比較します。

関連項目:

assertTree

3.12.8 getCurrentDate

getCurrentDate関数では、CurrentDateファクトに関連付けられている日付が戻されます。

構文

getCurrentDate() returns Calendar

使用上の注意

有効日と現在の日付は、直交する2つのアイテムです。有効日は、有効開始日および有効終了日のプロパティに従って有効になっているルールを判別するのに使用します。CurrentDateファクトでは、ルール・エンジンが管理している現在の日付を表すファクトを推論の対象にできます。

現在の日付を設定しても、有効日のセマンティクスには影響を与えません。

日付を推論の対象にするためのルールをルール内に明示的に作成する場合は、CurrentDateファクトを使用します。有効開始日または有効終了日、あるいはその両方をルールに割り当て、データ内の日付から判別されるルールを有効にする場合は、setEffectiveDate()を使用します。

関連項目:

setCurrentDate、getEffectiveDate、setEffectiveDate

3.12.9 getDecisionTrace

現在のトレースを戻し、新しいトレースを開始します。

構文

getDecisionTrace() returns DecisionTrace

使用上の注意

関連項目:

getDecisionTraceLevel、getDecisionTraceLevel、watchRules_ watchActivations_ watchFacts_ watchFocus_ watchCompilations

3.12.10 getDecisionTraceLevel

現在のデシジョン・トレース・レベルを取得します。

構文

getDecisionTraceLevel() returns int

使用上の注意

サポートされているデシジョン・トレース・レベルには、次のレベルが含まれます。

- オフ: デシジョン・トレースは無効です。これは、RuleSession.DECISION_TRACE_OFFとして定義されます。

- 本番: 起動されたルールがトレースに表示されます。これは、RuleSession.DECISION_TRACE_PRODUCTIONとして定義されます。

- 開発: watchAll()によく似た詳細なデシジョン・トレース。これは、RuleSession.DECISION_TRACE_DEVELOPMENTとして定義されます。

関連項目:

getDecisionTrace、getDecisionTraceLimit、watchRules_ watchActivations_ watchFacts_ watchFocus_ watchCompilations

3.12.11 getDecisionTraceLimit

トレース内のイベント数に対する現在の制限値を戻します。

構文

getDecisionTraceLimit() returns int

使用上の注意

関連項目:

getDecisionTrace、getDecisionTraceLevel

3.12.12 getEffectiveDate

getEffectiveDate関数では、有効日の現在値が戻されます。

構文

getEffectiveDate() returns Calendar

使用上の注意

有効日と現在の日付は、直交する2つのアイテムです。有効日は、有効開始日および有効終了日のプロパティに従って有効になっているルールを判別するのに使用します。CurrentDateファクトでは、エンジンが管理している現在の日付を表すファクトを推論の対象にできます。どちらも明示的に設定できます。

現在の日付を設定しても、有効日のセマンティクスには影響を与えません。有効日を設定しても、CurrentDateファクトには影響を与えません。

日付を推論の対象にするためのルールをルール内に明示的に作成する場合は、CurrentDate (setCurrentDate())を使用します。有効開始日または有効終了日、あるいはその両方をルールに割り当て、データ内の日付から判別されるルールを有効にする場合は、setEffectiveDate()を使用します。

関連項目:

setEffectiveDate、getCurrentDate、setCurrentDate

3.12.13 getFactByType

この関数では、作業メモリー内にインスタンスが1つのみ存在するときに、classNameで識別されるファクト・タイプが戻されます。存在しない場合は、nullが戻されます。作業メモリー内にそのファクト・タイプの複数のインスタンスが存在する場合、例外がスローされます。

構文

function getFactByType(String className) returns Object

関連項目:

showFacts

3.12.14 getFactsByType

指定したクラスのインスタンスである、作業メモリー内のすべてのファクトのリストが戻されます。

構文

function getFactsByType(String className) returns List

関連項目:

showFacts、watchRules_ watchActivations_ watchFacts_ watchFocus_ watchCompilations

3.12.15 getRulesetStack

ルールセット・スタックをルールセット名の配列として戻します。

構文

function getRulesetStack() returns String[];

使用上の注意

戻り値: ルールセット名の配列としてのルールセット・スタック

スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。

関連項目:

clearRulesetStack、getStrategy、popRuleset、pushRuleset、setRulesetStack、setStrategy

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 && … { … } }");
}
}

関連項目:

clearRule

3.12.17 getStrategy

現在の戦略を戻します。表3-7に、使用可能な戦略の値が示されています。

構文

function getStrategy() returns String;

関連項目:

clearRulesetStack、getRulesetStack、popRuleset、pushRuleset、setStrategy

3.12.18 halt

halt関数では、現在起動中のルールの実行が停止され、停止されたルールの実行元であるrun、runUntilHaltまたはstep関数に制御が戻されます。アジェンダはそのままであるため、後続のrun、runUntilHaltまたはstepを実行するとルールの起動を再開できます。

halt関数は、run、runUntilHaltまたはstep関数のコンテキスト外で起動された場合は効果がありません。

構文

function halt();

関連項目:

reset、run、runUntilHalt、step

3.12.19 id

オブジェクトobjに関連付けられているファクトIDを戻します。objがファクトに関連付けられていない場合は、-1が戻されます。

構文

function id(Object obj) returns int;

関連項目:

assert、object、retract

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

関連項目:

setErrorInRuleConditionSuppressed

3.12.21 isRulesetsOnStackOnce

このルール実行設定の現在値を返します。

構文

function isRulesetsOnStackOnce() returns boolean

関連項目:

setRulesetsOnStack

3.12.22 object

特定のファクトIDに関連付けられているオブジェクトを戻します。ファクトIDがない場合は、nullが戻されます。

構文

function object(int factId) returns Object;

関連項目:

assert、id、retract

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

関連項目:

clearRulesetStack、getRulesetStack、getStrategy、pushRuleset、setStrategy

3.12.25 pushRuleset

特定のルールセットをスタックに追加し、そのルールセットをフォーカスにします。すでにフォーカスであるルールセットを追加するとエラーが発生します(このエラーについてはRLIllegalArgumentExceptionがスローされます)。

スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。

構文

function pushRuleset(String focus);

例

例3-48は、pushRuleset関数を使用したRL Languageを示しています。例3-49は、popRuleset関数を使用したRL Languageを示しています。

例3-48 pushRulesetの使用 - RLIllegalArgumentExceptionのスロー

clearRulesetStack();
pushRuleset("main");        // focus is "main"
pushRuleset("main");        // RLIllegalArgumentException

例3-49 popRulesetの使用 - RLRuntimeExceptionのスロー

clearRulesetStack();
popRuleset();        // RLRuntimeException

関連項目:

clearRulesetStack、getRulesetStack、getStrategy、popRuleset、setStrategy

3.12.26 retract

オブジェクトobjに関連付けられているファクトを作業メモリーから削除します。

構文

function retract(Object obj);

使用上の注意

取消しはアジェンダに影響を与える可能性があります。取り消されたファクトに依存するアクティブ化はアジェンダから削除されます。

(!を使用して)ファクトが存在しないことをテストする条件があるルールによって、アジェンダに新しいアクティブ化が配置される可能性があります。

関連項目:

assert、id、object

3.12.27 reset

作業メモリーからすべてのファクトを消去し、アジェンダからすべてのアクティブ化を消去して、非ファイナル・グローバル変数の初期化式を再評価します。

構文

function reset();

関連項目:

halt、run、runUntilHalt、step

3.12.28 run

アジェンダに存在するルール・アクティブ化を、次の条件に該当するまで起動します。

- ルール・アクションでhaltが直接または間接的にコールされるまで。たとえば、ルール・アクションによってコールされた関数でhaltがコールされる場合です。

- アジェンダが空になるまで。

- ルールセット・スタックが空になるまで。

構文

function run() returns int;

function run(String rulesetName) returns int;

使用上の注意

引数rulesetNameが指定された場合は、ルールの起動前に、名前付きルールセットがルールセット・スタックの最上位に追加されます。

nullのrulesetNameが指定された場合、ルールセット・スタックはルールの起動前に変更されません。

rulesetNameが指定されず、デフォルトのmainルールセットがルールセット・スタック上に存在しない場合は、ルールの起動前に、mainがルールセット・スタックの最下位に配置されます。

戻り値: int。起動されたルールの数。

関連項目:

halt、reset、runUntilHalt、step

3.12.29 runUntilHalt

この関数では、haltがコールされるまでルール・アクティブ化が起動されます。runおよびstepとは異なり、runUntilHaltは、アジェンダが空になっても戻りません。また、runUntilHaltでは、ルールセット・スタックから最下位のルールセット名は削除されません。かわりに、アジェンダにアクティブ化が格納されるのを待機します。

構文

function runUntilHalt() returns int;

使用上の注意

メインのRuleSessionスレッドがビジーであるときにアクティブ化をアジェンダに追加する唯一の方法であるrunUntilHaltの実行は、2番目のスレッドに対して行われ、次のいずれかが実行されます。

1. PropertyChangeListenersを使用したJava Beanファクトの変更

2. assertまたはretract関数の実行

runUntilHaltの使用時はルールを注意して設計する必要があります。たとえば、プロパティが最小値のファクトを検出しようとするルールは、ファクトの最初のインスタンスがアサートされたときに起動され、その後は、それより小さい値のプロパティが設定された別のインスタンスがアサートされるたびに起動されます。

関連項目:

halt、reset、run、step

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関数を起動すると、現在の日付が任意の値に設定される場合があります。

関連項目:

getCurrentDate、getEffectiveDate、setEffectiveDate

3.12.31 setDecisionTraceLevel

デシジョン・トレース・レベルを指定したレベルに設定します。

構文

setDecisionTraceLevel(int level)

使用上の注意

サポートされているデシジョン・トレース・レベルには、次のレベルが含まれます。

- オフ: デシジョン・トレースは無効です。これは、RuleSession.DECISION_TRACE_OFFとして定義されます。

- 本番: 起動されたルールがトレースに表示されます。これは、RuleSession.DECISION_TRACE_PRODUCTIONとして定義されます。

- 開発: watchAll()によく似た詳細なデシジョン・トレース。これは、RuleSession.DECISION_TRACE_DEVELOPMENTとして定義されます。

関連項目:

getDecisionTrace、getDecisionTraceLevel、getDecisionTraceLevel、setDecisionTraceLimit、watchRules_ watchActivations_ watchFacts_ watchFocus_ watchCompilations

3.12.32 setDecisionTraceLimit

トレース内のイベント数の制限値を設定します。

構文

setDecisionTraceLimit(int count)

使用上の注意

デフォルト値は10000です。

関連項目:

getDecisionTrace、getDecisionTraceLevel、getDecisionTraceLevel、setDecisionTraceLevel

3.12.33 setEffectiveDate

setEffectiveDate関数では、ルール・エンジンの有効日が更新されます。

デフォルトでは、有効日の値は、ルール・エンジンによって暗黙的に管理されます。この場合、組込み関数のrunファミリが起動されると、有効日が現在のシステム日付に更新されます。これは、任意のルールが起動される前に実行されます。そのため、新しい有効日は、ルールの起動が開始される前に適用されます。runUntilHaltの場合は、アジェンダにあるルールのアクティブ化が0個から1個以上に遷移するたびに、この更新が実行されます。

構文

setEffectiveDate(Calendar newDate)

使用上の注意

有効日を変更する唯一の方法は、setEffectiveDateを起動することです。reset関数を起動すると、有効日は任意の値に設定される場合があります。

RLIllegalArgumentException例外は、newDate引数がnullの場合にスローされます。

一度setEffectiveDate関数を呼び出すと、有効日を必要に応じて更新する作業がアプリケーションの役割になります。ルール・エンジンでは、有効日が暗黙的に管理されなくなります。

この状態は、reset関数を起動するまで存続します。

これは、デバッグや特定時点でのルール評価の実行、または有効日をアプリケーションで制御する必要があるその他のユースケースで役立ちます。

関連項目:

getEffectiveDate、getCurrentDate、setCurrentDate

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組込み関数で問合せ可能です。

関連項目:

isErrorInRuleConditionSuppressed

3.12.35 setRulesetStack

ルールセット・スタックをルールセット名の特定の配列に設定します。

スタックの最上位であるエントリ0(ゼロ)はフォーカス・ルールセットです。フォーカス・ルールセットは、後続のrun、runUntilHaltまたはstep関数の実行によってアクティブ化が最初に起動されるルールセットです。

構文

function setRulesetStack(String[] rulesetStack

関連項目:

clearRulesetStack、getRulesetStack、getStrategy、popRuleset、pushRuleset、setStrategy

3.12.36 setRulesetsOnStack

true値を設定したこの関数の呼出しは、スタックにプッシュされるルールセットが、ルールの実行中に一度しかスタックにプッシュされないことを示します。前の値は返されます。デフォルト値はfalseです。

構文

function setRulesetsOnStackOnce(boolean bv) returns boolean

関連項目:

isRulesetsOnStackOnce

3.12.37 setStrategy

戦略では、同じルールセット内の優先度が同じアクティブ化の実行順序が指定されます。表3-7は、有効な戦略の値を示しています。

表3-7 setStrategyおよびgetStrategy関数の戦略の値

戦略

説明

キュー

アクティブ化は、古い方から順に起動されます。

スタック

アクティブ化は、新しい方から順に起動されます。

構文

function setStrategy(String strategy);

関連項目:

clearRulesetStack、getRulesetStack、getStrategy、popRuleset、pushRuleset

3.12.38 showActivations

show関数では、ルール・セッションの状態が出力ライターに出力されます。表示可能な状態は、アジェンダ上のすべてのアクティブ化です。

構文

function showActivations();

関連項目:

clearWatchRules_ clearWatchActivations_ clearWatchFacts_ clearWatchFocus_ clearWatchCompilations_ clearWatchAll、showFacts、watchRules_ watchActivations_ watchFacts_ watchFocus_ watchCompilations

3.12.39 showFacts

show関数では、ルール・セッションの状態が出力ライターに出力されます。表示可能な状態は、作業メモリー内のすべてのファクトです。

構文

function showFacts();

関連項目:

clearWatchRules_ clearWatchActivations_ clearWatchFacts_ clearWatchFocus_ clearWatchCompilations_ clearWatchAll、showActivations、watchRules_ watchActivations_ watchFacts_ watchFocus_ watchCompilations

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関数の呼出しを使用することにより、記述したルールの不具合が原因で発生する可能性のある、ルール起動の無限ループを捕捉できます。

関連項目:

halt、reset、run、runUntilHalt

3.12.41 watchRules、watchActivations、watchFacts、watchFocus、watchCompilations

watch関数は、重要なルール・セッション・イベントに関する情報の出力を有効にします。情報は、イベントが発生するたびに出力ライターに出力されます。出力を無効にするには、clearWatch関数を使用します。

表3-8で、使用可能なデバッグ情報について説明します。

表3-8 watch関数のイベントの説明

デバッグ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

4 コマンドライン・インタフェースの使用

この章では、ルールセットをSystem.inから読み込み、関数println、watchおよびshowからの出力をSystem.outに書き込むRLコマンドラインについて説明します。

この章の内容は次のとおりです。

- コマンドライン・インタフェースの開始と使用

- RLコマンドラインのオプション

- RLコマンドラインの組込みコマンド

4.1 コマンドライン・インタフェースの開始と使用

次のコマンドは、プロンプトRL>を使用して、単純なコマンドライン・インタフェースを起動します。

この例ではJava Beanが含まれていません。

java -jar SOA_ORACLE_HOME/soa/modules/oracle.rules_11.1.1/rl.jar -p "RL> "

ここで、SOA_ORACLE_HOMEは、SOAモジュールがインストールされる場所です(例: c:/Oracle/Middleware)。-pオプションはプロンプトを指定します。

次に、このBeanにアクセスするためのRL Languageコマンドラインの開始方法を示します。

java -classpath SOA_ORACLE_HOME/soa/modules/oracle.rules_11.1.1/rl.jar;BeanPath oracle.rules.rl.session.CommandLine -p "RL> "

BeanPathは提供されているJava Beanクラスへのクラスパス・コンポーネントです。

このコマンドライン・インタフェースを終了するには、コマンド・プロンプトで特殊なアクションexit;を使用します。exit;アクションをルールセットに含めることはできません。かわりに、任意のアクションでSystem.exit(int)メソッドを起動して終了できます。

RLコマンドライン・インタフェースは、入力を行単位で蓄積し、入力ストリームに次のいずれかが含まれるとその入力を解析します。

- 完全な名前付きルールセットが含まれる場合

- 名前なしルールセット内の、1つ以上の完全なimport、include、ruleset、definitionアクション・コマンドが含まれる場合。

注意:

ifとelse、try、catchとfinallyアクションでは、終了場所を先に確認する必要があります。else句のないifまたはfinally句のないtryをRLコマンドラインで実行するには、セミコロン終了文字を追加する必要があります。

これは、includeまたはRuleSession APIを使用してRLを実行する場合は必要ありません。

次のコード例では、RLコマンドライン入力処理のサンプルを示します。

RL> int i = 1;
RL> if (i > 0) {println("i positive");}
// nothing happens - waiting for possible "else"
;
i positive
RL>

入力は、行の最後で完了する必要があります。たとえば、行の途中でアクションが終了している場合、そのアクションは、次のアクションが行の最後で完了するまで解析されません。

例4-1 コマンドライン入力処理の例(行の終了まで待機する例)

RL> println("delayed"
); println("hello"
); println("world");
delayed
hello
world
RL>

4.1.1 コマンドライン入力処理の使用

コマンドライン入力処理に関する注意

1. コマンドラインでは入力を複数のブロックに分割してから、各ブロックをインタプリタに渡します。閉じカッコまたはセミコロンを入力しない場合、コマンドラインでは、ブロック全体を解析する前に閉じカッコまたはセミコロンの入力を待機するため、エラーは発生しません。

2. コマンドライン・インタプリタを対話形式、つまり-iオプションを設定して使用すると、入力が、行番号を付ける目的で、新規行で終了する小規模なルールセットに分解されます。エラーは、ルールセット内の番号を使用してレポートされます。
たとえば、次の行で構成される入力があるとします。

int i = 0; i = 1; // this is a ruleset
i = "i";  // this is another ruleset

この例の場合、コマンドラインでは次のエラーがレポートされます。

Oracle Business Rules RL: type check error
ConversionException: cannot convert from type 'java.lang.String' to type 'int'
at line 1 column 5 in main

このような動作を回避するには、ルールセットの入力を明示的に囲みます。次に例を示します。

ruleset main {
int i = 0; i = 1;
i = "i";
}

これで、エラーは3行目で発生します。あるいは、includeを使用して入力ファイルをインクルードできます。

4.2 RLコマンドラインのオプション

次の表は、RLコマンドラインのオプションについて説明しています。

表4-1 RLコマンドラインのオプション

フラグ

説明

–i

ルールセットを、デフォルトのSystem.inではなく、次の引数で指定したファイルから読み込みます。

例:

-i myInput.rl

注意: コマンドラインでは入力を複数のブロックに分割してから、各ブロックをインタプリタに渡します。ファイルmyInput.rlの最後に閉じカッコまたはセミコロンが含まれていない場合、コマンドラインでは、ブロック全体を解析する前に閉じカッコまたはセミコロンの入力を待機するため、エラーは発生しません。したがって、コマンドラインの入力を待機している間に、-iオプションを使用して提供された不完全な入力ファイルが実行され、ファイルmyInput.rlの有効なコード部分が実行されて終了する場合があります。

–c

次の引数を最初のRLコマンドとして実行し、入力の読込みを開始します。このオプションは、デバッグ用の設定と関数のファイルを読み込むのに便利です。

例:

-c "include file:debugSettings.rl;"

コマンドを実行した後に入力から読み込まない場合は、コマンドの後にexit;を追加します。

例:

-c "include file:script.rl; exit;"

–p

次の引数をプロンプト文字列として設定します。

例:

-p "RL> "

-o

println、watchおよびshowからの出力を、System.outではなく、次にくる引数で指定された名前のファイルに書き込むように指定します。

例:

–o debug.log

–v

バージョン情報を出力します。

4.3 RLコマンドラインの組込みコマンド

この項では、RLコマンドライン・インタフェースによって実装されるコマンドについて説明します。これらのコマンドはRLの一部ではありません。

したがって、これらのコマンドをブロック内に表示したり、ルールセットに含めることはできません。

4.3.1 clearコマンド

現行のRuleSessionオブジェクトを破棄し、新規オブジェクトを割り当てます。これによって、ルール、変数、クラスおよび関数がすべて破棄されます。

clear;を使用してコマンドラインを再開するかわりに、exit;と入力し、Javaコマンドを再発行して別のコマンドラインを開始することもできます。

4.3.2 exitコマンド

コマンドライン・インタフェースを終了します。コマンドライン・インタフェースは、入力のend-of-fileに到達した場合にも終了します。

5 RuleSessionの使用

この章では、RuleSessionオブジェクトの使用方法を説明します。

この章の内容は以下のとおりです。

- RuleSessionコンストラクタのプロパティ

- RuleSessionのメソッド

- RL型からJava型への変換

- エラー処理

- RLクラスの反映

- ルール対応プログラムからの結果の取得

- RLスタック・トレースのデバッグ

- RuleSessionプールの使用

- RuleSessionオプションの使用

- デシジョン・トレースの使用方法

5.1 RuleSessionコンストラクタのプロパティ

この項では、ルール対応アプリケーションを作成する手順を示し、RuleSessionオブジェクトの使用方法について説明します。RuleSessionオブジェクトはパッケージoracle.rules.rlに含まれています。

RuleSessionコンストラクタは、引数がない場合、デフォルトのロケールおよびロギング・オプションが設定されたRuleSessionを戻します。

表5-1に、RuleSessionコンストラクタに渡されるマップで設定可能な構成パラメータを示します。

表5-1 RuleSessionコンストラクタの構成パラメータ

パラメータ・キー

値

CFG_LOGGING

ブール値。trueの場合、ロギングが有効です。Falseの場合、ロギングが無効です。デフォルトは、trueです。

CFG_LOCALE

任意のロケールに対するロケール・オブジェクト。デフォルトはJVMデフォルト・ロケールです。

CFG_WATCH

RAWアクティビティ監視のトレース機能に関する必要な設定。この設定は、セッションのリセット時にリストアされます。

WATCH_RULES: 起動される監視ルール。

WATCH_ACTIVATIONS: 監視ルールのアクティブ化および非アクティブ化。

WATCH_FACTS: 監視のファクト操作(アサート、変更、撤回)。

WATCH_FOCUS: 監視ルールセット・スタックの変更。

WATCH_COMPILATION: 監視ルールの定義。

WATCH_ALL: 前述のすべての監視。

デフォルトでは、トレース設定は1つも有効化されません。

CFG_DECISION_TRACE_LEVEL

トレース対象のルール・エンジン・アクティビティを制御するデシジョン・トレース・レベルを設定します。このレベルは、セッションのリセット時にリストアされます。

DECISION_TRACE_OFF: すべてのデシジョン・トレースを無効化します。

DECISION_TRACE_PRODUCTION: 起動されるルールをトレースします。

DECISION_TRACE_DEVELOPMENT: 詳細なデシジョン・トレース。WATCH_ALLおよびリセットのトレースに相当します。

デフォルトはDECISION_TRACE_OFFです。

CFG_DECISION_TRACE_LIMIT

トレースが取得されるまで内部的に格納されるトレース・エントリ数に制限を課す整数。

デフォルトのデシジョン・トレース制限は10000です。

5.2 RuleSessionのメソッド

outputWriterプロパティは、println、watchおよびshowの出力先を決定します。

rulesetNameプロパティは、明示的にルールセット名を指定せずに、RL文の実行時にルールセットを設定します。デフォルトのrulesetNameはmainです。

executeRulesetメソッドは、指定のルールセット・テキスト(Stringまたはjava.io.Readerとして指定)を解析して実行します。

callFunctionメソッドは、名前付きRL関数(組込みRL関数または以前にexecuteRulesetメソッドの1つを使用してパラメータなしで定義した関数)を起動し、その結果を戻します。単一の引数を取る関数は、callFunctionWithArgumentメソッドを使用して起動できます。任意の数の引数を取る関数は、callFunctionWithArgumentListまたはcallFunctionWithArgumentArrayメソッドを使用してコールできます。引数のリストまたは配列には、各RL関数パラメータのJavaオブジェクトが記載されている必要があります。

5.3 RL型からJava型への変換

次の表では、引数をRL関数に渡すためにJavaオブジェクト型をRL型に変換する方法について説明します。

表5-2に、引数をRL関数に渡すためにJavaオブジェクト型をRL型に変換する方法、およびRL関数の戻り値をJavaに渡すためにRL型をJava型に変換する方法を示します。

表5-2 RLからJavaオブジェクトへの変換

Javaクラス

RL型

java.lang.Integer

int

java.lang.Character

char

java.lang.Byte

byte

java.lang.Short

short

java.lang.Long

long

java.lang.Double

double

java.lang.Float

float

java.lang.Boolean

boolean

Object

Object

int[]

int[]

char[]

char[]

byte[]

byte[]

short[]

short[]

long[]

long[]

double[]

double[]

float[]

float[]

boolean[]

boolean[]

Object[]

Object[]

5.4 エラー処理

RuleSessionメソッドの起動でParseExceptionまたはTypeCheckExceptionがスローされても、RuleSessionの状態には影響を与えません。Javaアプリケーション(たとえば、対話型のコマンドライン)では、これらの例外を検出し、RuleSessionの使用を続行できます。

RuleSessionメソッドの起動でRLRuntimeExceptionがスローされた場合は、RuleSessionの状態に影響を与える可能性があり、アプリケーションでRuleSessionを処理できない状態になる場合があります。堅牢なアプリケーションの場合は、RLでRLRuntimeExceptionを検出し、例外がスローされた近辺でリカバリするように試みます。

その他の例外は、多くの場合、アプリケーションで処理できない重大な問題を示します。

5.5 RLクラスの反映

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に含まれます。

5.6 ルール対応プログラムからの結果の取得

Oracle Business Rulesを使用してルール対応プログラムを作成したときの一般的な疑問は、「評価の結果を取得する方法は?」です。

この項では、ルール・エンジンからルール評価の結果を抽出または表示する方法を説明します。

内容は次のとおりです。

- 結果例の概要

- 外部リソースを使用した結果の取得

関連項目:

詳細は、『Oracle Business Process Managementによるビジネス・ルールの設計』の「スタンドアロン(SOA/BPM以外の)シナリオでのルールの使用」を参照してください

5.6.1 結果の例の概要

この項で使用する例は、高速道路の事故通知システムを示しています。それぞれの例は、ルール・エンジンの評価結果にアクセスするための異なる方法を示しています。これらの例では、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オブジェクトと同様に、ルール・エンジンの結果を保持できます。

5.6.2 外部リソースを使用した結果の取得

この方法は、結果用のコンテナをアサートする方法と同じです。ただし、コンテナではなくオブジェクトを使用して、ルール・エンジンの外部にあるリソースに作用します。たとえば、予定の作業をキューに挿入したりスケジュールする場合、データベースを更新する場合、メッセージを送信する場合が該当します。結果を導出するには、アクションでアクセス可能な任意のJavaメソッドを起動できます。コンテナを使用する場合と同様に、外部リソースにアクセスするためにこの例で使用されているオブジェクトは、その内容が推論の対象でないため、再度アサートされることはありません。

次の例に示すIncidentDispatcherオブジェクトは、アサートされて通知の配信に使用されます。

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);
}
}

例5-1に示すJavaコードはIncidentDispatcherおよびTrafficIncidentをアサートし、ルール・エンジンを起動します。これは、推論の対象となるオブジェクトを使用しても実行できます。ただし、この場合は、ルール起動の無限ループを回避するために、ルール条件のテストが必要になります。

例5-1 外部リソースを使用した結果の例

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");

5.7 RLスタック・トレースのデバッグ

ランタイムでは、RLスタック・トレースに詳細なデバッグ情報が提供されます。エラーが発生した場合は、可能なかぎり、問題箇所の識別に役立つ特別なコンテキストが提供されます。この特別なコンテキストは、ルールSDKとルール・デザイナを併用している場合に有効です。

スタック・トレースには、ルール条件、ルール・アクション、関数、変数およびRLクラス定義に関する情報を示す特別なコンテキストが含まれています。XPath形式のフォーマットは、RL構成とそれに続くカッコで囲まれた名前(名前が指定されている場合)で構成されます。構成の後に大カッコで囲まれた番号nが表示される場合は、前の構成に続いてn番目の項目を示します。ルールSDKと併用している場合、ルール・デザイナでは、RL生成によってエラーの場所を非常に特定しやすくなります。

たとえば、例5-2に示されたルールセットについて考えてみます。このルールセットを実行すると、次のレポートが提供されます。

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

例5-2 テスト・ルールセット

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());

5.8 RuleSessionプールの使用

ルールを使用する典型的なアプリケーションでは、個々のリクエストに対応する異なるファクトを使用して、同じルールを何回も評価します。RuleSessionの初期化に要する時間は、含まれているルールの数によって異なりますが、通常は数秒です。

これに対し、ルールの実行に必要なのは、初期化よりはるかに短い時間です。したがって、RuleSessionを1回初期化し、新規の各リクエストに対して再利用することで、パフォーマンスを向上させることができます。RuleSessionプールを使用すると、RuleSessionインスタンスのプールを作成できるため、ルールを使用するアプリケーションのパフォーマンスとスケーラビリティが向上します。

RuleSessionプールは、ルール、型、関数の共通の定義をプール内のすべてのセッションで共有します。これにより、同じ数の個別のセッションを使用する場合と比較してメモリー消費量を大幅に削減できます。この共有により、新規セッションを元のルール言語テキストから作成する必要がなくなるため、新規セッションを作成するコストも大幅に低減されます。

5.8.1 RuleSessionプールの作成方法

負荷の増加に対応したパフォーマンスを実現するには、複数のRuleSessionが必要です。RuleSessionインスタンスのプールにより、ルールを使用するアプリケーションのパフォーマンスとスケーラビリティが向上します。プールは、RLコードのリストを使用してインスタンス化されます。RLコードは、プールで作成された各RuleSessionを初期化するために使用されます。RLコードは、リストに記載されている順に実行されます。最初に作成するRuleSessionインスタンスの数を指定できます。一般的には小さい値を指定しますが、通常は、このデフォルト値で十分です。

アプリケーションで使用中のルールが更新された場合は、後続のルール実行で新しいルールが使用されるように、アプリケーションは新しいルールをロードする必要があります。これをプールでサポートするには、refreshPoolメソッドを起動して新しいRLのリストを渡します。プールが更新されると、getPoolableRuleSessionで戻されるRuleSessionは、新しいRLコードで初期化されています。更新前に取得されたRuleSessionがreturnPoolableRuleSessionを使用して戻された場合、そのRuleSessionはプールに戻されません。更新後のプールに保存されるのは、新しいRLコードで初期化されたRuleSessionのみです。

RLコードは通常、ルールSDKで作成されたRuleDictionaryから生成されます。例5-3は、RuleDictionaryから生成されたRLコードでRuleSessionPoolを作成および使用する方法を示しています。

例5-3 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);

5.8.2 RuleSessionプールの使用方法

RuleSessionを使用してルールを実行する場合は、プールからRuleSessionを取得し、実行後にプールに戻します。プール可能なRuleSessionを取得するには、getPoolableRuleSessionメソッドを起動します。プールでは、必要に応じて新しいRuleSessionが作成されます。getPoolableRuleSessionの起動は、空きRuleSessionの待機を妨げることはありません。

RuleSessionPoolは、RuleSession構成パラメータのマップを使用して作成できます。また、プール内のすべてのセッションは指定どおりに構成されます。

ルール実行の完了後、プール可能なRuleSessionをプールに戻すには、returnPoolableRuleSessionメソッドを起動します。プールに戻されたRuleSessionをプールでリセットするには、組込みRL関数のreset()を起動します。これによって、作業メモリーからすべてのファクトが削除され、そのRuleSessionは次の実行のために準備されます。プールから取得したすべてのRuleSessionは、プールに戻す必要があります。ルールの実行中に発生したエラーが原因で今後の使用に適さなくなったRuleSessionは、プールで検出されて廃棄されます。

reset()関数は、作業メモリーの消去に加えて、非ファイナル・グローバル変数のイニシャライザを再実行します。非ファイナル・グローバル変数のイニシャライザを使用すると、必要な場合は、リセット時に他の初期化を実行できます。

次のコード例は、プールからRuleSessionを使用する方法を示しています。

PoolableObject po = pool.getPoolableRuleSession();
RuleSession engine = po.getPooledObject();
// use the RuleSession to execute rules as required here
pool.returnPoolableRuleSession(po);

プールのサイズに対するソフト上限を指定できます。この指定によって、一時的な需要の増加に対応するためにプールを拡大する一方、需要の減少時には、プールをソフト上限まで縮小できます。

getPoolableRuleSessionメソッドが起動されてプールが空の場合には、RuleSessionプールの実装を使用してRuleSessionインスタンスを作成します。負荷が非常に大きい場合は、ソフト制限を超えるインスタンス件数になります。

負荷の減少に従って、プール内のRuleSessionインスタンスの数は、ソフト制限まで自動的に減少します。

5.9 RuleSessionオプションの使用

RuleSessionを使用したRLランタイムは、次のオプションをサポートしています。

次のオプションがサポートされます。

- RuleSession.CFG_LOGGING

- RuleSession.CFG_DECISION_TRACE_LEVEL

- RuleSession.CFG_DECISION_TRACE_LIMIT

5.9.1 CFG_LOGGINGシステム・プロパティの使用

RL Languageランタイムでは、システム・プロパティとしてのCFG_LOGGINGと、RuleSessionコンストラクタに渡される構成マップのBooleanが検索されます。システム・プロパティの値は、マップの値でオーバーライドされます。

5.9.2 CFG_DECISION_TRACE_LEVELオプションの使用

RuleSession.CFG_DECISION_TRACE_LEVEL初期化パラメータをインクルードして、RuleSessionまたはRuleSessionPoolコンストラクタに渡される構成マップのレベルを指定することで、RuleSessionまたはRuleSessionPoolのトレース・レベルを構成できます。これはRuleSessionの作成時のデシジョン・トレース・レベルを設定します。reset()を起動すると、reset()の後、ルール実行中にレベルが変更されていた場合にレベルを構成値に戻すことができます。詳細は、「ルール・エンジン・レベルのデシジョン・トレースの使用方法」を参照してください。

5.9.3 CFG_DECISION_TRACE_LIMITオプションの使用

トレースのサイズは、デシジョン・トレース内のエントリ数を制限することで制限します。JVM内で使用可能なすべてのヒープを消費するトレースを作成することから、ルール内の不具合の可能性があるため、ルール起動の無限ループを回避するために制限が必要となります。トレースの制限は、setDecisionTraceLimit関数を使用して設定します。この制限は、RuleSession (またはRuleSessionPool)で構成することも可能です。構成するには、RuleSessionまたはRuleSessionPoolコンストラクタに渡される構成マップに目的の制限を指定したRuleSession.CFG_DECISION_TRACE_LIMIT初期化パラメータをインクルードします。詳細は、「ルール・エンジン・レベルのデシジョン・トレースの使用方法」を参照してください。

5.10 デシジョン・トレースの使用

Oracle Business Rulesでは、デシジョン・トレースはルール・エンジンの実行のトレースです。これには、ルールを起動したときのファクトの状態など、ルール・エンジンの状態に関する情報が含まれます。

Oracle Business Rulesのルール・エンジンは、デシジョン・トレースXMLスキーマから、JAXBで生成されたJavaクラスを使用してデシジョン・トレースを構成し、戻します。

5.10.1 ルール・エンジン・レベルのデシジョン・トレースの概要

デシジョン・トレースをビジネス・アナリストにわかりやすく表示するには、関連付けられているルール・ディクショナリを利用できる必要があります。トレースに関連付けられているルール・ディクショナリを使用すると、トレースの出力に、トレース内にある関連するディクショナリのすべてのコンテンツ情報を含める必要がなくなるため、より柔軟性があり効率的なアプローチが可能になります。

XMLスキーマは、ファイルdecisiontrace.xsd内にあり、これはJarファイルrl.jarの一部です(oracle/rules/rl/trace/decisiontrace.xsd)。該当するパッケージは、oracle.rules.rl.trace、oracle.rules.rl.extensions.traceおよびoracle.rules.sdk2.decisiontraceです。decisiontrace XMLスキーマから生成されたJavaクラス・パッケージは、パッケージoracle.rules.rl.trace内にあり、Javadocに含まれています。詳細は、Oracle Business Rules Java APIリファレンスを参照してください。

5.10.2 ルール・エンジン・レベルのデシジョン・トレースの使用

デシジョン・トレースは、一連のXML要素であり、ルールの評価中に発生したルール・エンジン・イベントを示しています。デシジョン・トレースに追加されるイベントの種類は、指定したトレース・レベルによって決まります。次のようなイベントが含まれます。

- ファクト操作(アサート、撤回、変更)

- ルールの起動

- アジェンダで追加または削除されたルールのアクティブ化

- ルールセット・スタックの変更

- ルールのコンパイル

- リセット(デシジョン・トレース分析で状態を維持するために必要)

各トレースには、特定のイベントに関する情報が含まれます。たとえば、ファクト操作のイベント・エントリは次の内容で構成されます。

- 操作の種類(アサート、変更、撤回)

- 作業メモリー内のファクトのID

- ファクト・タイプ名(RL内のファクト・クラス)

- ランタイム・オブジェクト・タイプ名

- ファクト・オブジェクト・データ(ゼロ個以上のファクト・プロパティのプロパティ名と値など)

- 操作がルール・アクションの結果であった場合は、ルール名、RL名

- ミリ秒単位のタイムスタンプ

ファクト操作のイベント・トレースでは、ファクト・オブジェクトのコンテンツはJava Beanとしてのオブジェクトの構造を反映します。Beanプロパティが他のBeanへの参照の場合、関連するBeanのコンテンツがトレースに含まれます。Beanプロパティの値は、次のいずれかになります。

- プロパティの文字列表現。これは、java.*およびjavax.*パッケージのプリミティブ型およびクラスである場合です。

- それぞれのプロパティ値を持つ、ネストされたBeanオブジェクト。

- ファクトID。これは、プロパティ値がオブジェクトであり、オブジェクト自身がファクトとしてアサートされている場合に発生します。トレースの時点でのファクトのデータは、トレース分析時のファクトIDを使用することでRuleEngineStateから取得できます。

- トレースでListとしてアクセスされる値のコレクション。

- トレースでListとしてアクセスされる値の配列。

トレースに含まれる値がどれになるかを実行時に調べるには、nullに対してテストします。null以外の値を持つのは、正しい値のみです。

表5-3に、ルール・エンジンでデシジョン・トレースを制御したりデシジョン・トレースにアクセスするRL関数を示します。

表5-3 RLデシジョン・トレース関数

関数

説明

getDecisionTrace

現在のトレースを戻し、新しいトレースを開始します。

getDecisionTraceLevel

現在のデシジョン・トレース・レベルを取得します。

getDecisionTraceLimit

トレース内のイベント数に対する現在の制限値を戻します。

setDecisionTraceLevel

デシジョン・トレース・レベルを指定したレベルに設定します。

setDecisionTraceLimit

トレース内のイベント数の制限値を設定します。

デフォルトの制限値は10000です。

5.10.2.1 デシジョン・トレース・レベルの設定

デシジョン・トレース・レベルは、setDecisionTraceLevel関数を起動することで設定できます。RuleSession.CFG_DECISION_TRACE_LEVEL初期化パラメータをインクルードして、RuleSessionまたはRuleSessionPoolコンストラクタに渡される構成マップのレベルを指定することで、RuleSessionまたはRuleSessionPoolの初期トレース・レベルを構成することもできます。これはRuleSessionを作成する時点でのデシジョン・トレース・レベルを設定します。

setDecisionTraceLevel関数は初期化後にRuleSessionまたはRuleSessionPoolオブジェクトで起動できます。reset()を起動すると、この関数によりデシジョン・トレース・レベルが構成値に戻されます(ルール実行中にレベルが変更された場合)。したがって、reset()関数はデシジョン・トレースの制限を、RuleSessionまたはRuleSessionPoolの初期化で設定した値にリセットします。このような場合、reset()は初期化パラメータを使用して指定された値をリストアします。

注意:

こうしたRuleSessionに対するreset()のセマンティクスは、CFG_DECISION_TRACE_LIMITまたはCFG_DECISION_TRACE_LEVELあるいはその両方の初期化パラメータを使用して初期化された (または、プールがCFG_DECISION_TRACE_LIMITまたはCFG_DECISION_TRACE_LEVELあるいはその両方の初期化パラメータを使用して作成されている場合に、RuleSessionPoolから取得した)RuleSessionに対してのみ有効です。

トレースのサイズは、デシジョン・トレース内のエントリ数を制限することで制限します。JVM内で使用可能なすべてのヒープを消費するトレースを作成することから、ルール内の不具合の可能性があるため、ルール起動の無限ループを回避するために制限が必要となります。トレースの制限は、setDecisionTraceLimit関数を使用して設定します。この制限は、RuleSession (またはRuleSessionPool)で構成することも可能です。構成するには、RuleSessionまたはRuleSessionPoolコンストラクタに渡される構成マップに目的の制限を指定したRuleSession.CFG_DECISION_TRACE_LIMIT初期化パラメータをインクルードします。

runUntilHaltを使用するルール・アプリケーションでは、トレースの制限に達する前にアプリケーションでgetDecisionTraceを呼び出す必要があります。

デシジョン・トレースは、トレース・データに構造を提供し、これをプログラム的に操作できるようにします。ただし、トレース自体は分析するには、扱いにくい場合があります。トレース分析クラス(oracle.rules.rl.extensions.trace.TraceAnalysis)は、デシジョン・トレースを分析し、トレースの内容を調べやすくします。このクラスを使用して作業メモリー、アジェンダおよびルールセット・スタックの状態をトレースから構成します。

TraceAnalysis APIは次をサポートします。

- トレース内に現れるファクト・タイプのリストの取得。

- トレース内で起動されたルールの名前のリストの取得。

- 特定のファクト・タイプの各インスタンスに対する最終ファクト・トレースのリストの取得。

- ファクトIDで指定された特定のファクトに対する最終ファクト・トレースの取得。

- ファクトIDで指定されたファクトに対するすべてのファクト・トレースの取得。

- ファクト・トレースで、ファクト・トレースがルール・アクションによって作成された場合に、アクションが実行されるルールの起動のルール・トレースの取得。

- ルール・トレースで、一致してルールが起動された各ファクトに対するファクト・トレースのリストの取得。

- 次または前のトレースの取得。トレースの調査は通常、トレースの反復ではありません。たとえば、あるファクト・トレースからルール・トレースを取得することは、本質的にはそのルール・トレースへのジャンプです。そのルール・トレースの周囲のトレースは直接調べることができます。

- 名前で指定されたルールに対するルール・トレースのリストの取得。

- トレース・エントリに対するルール・エンジンの状態の取得。ルール・エンジンの状態は、トレースを生成したアクティビティの後のルール・エンジンの状態を反映します。このAPIを使用することで、各トレースの時点でのルール・エンジンの状態を調べることができます。このAPIは開発レベルのトレースで最も役立ちます。本番レベルのトレースでは、追跡できるのは作業メモリー内にあるファクトのみで、それにはファクトの内容は含まれていません。

例5-4に、デシジョン・トレース分析APIを使用したコード・サンプルを示します。

例5-4 デシジョン・トレース分析APIの使用方法

DecisionTrace trace;
...
TraceAnalysis ta = new TraceAnalysis(trace);
// Get all of the last fact traces for a fact type.
List<FactTrace> factTraces = ta.getLastFactTraces("com.example.MyFactType");
// From a particular fact trace, how it was arrived at may be explored, first by
// obtaining the rule that asserted or modified the fact.
// From the FactRecord, the rule that resulted in the record can be obtained.
FactTrace factTrace = factTraces.get(0);  // assumes there is one
RuleTrace ruleTrace = ta.whichRule(factTrace);
// The ruleTrace will be null if the fact operation was not part of a rule action.
System.out.print("Fact " + factTrace.getFactId() + ", a " + factTrace.getFactType() + " " + factRecord.getFactOp());
if (ruleTrace != null)
System.out.println(" by rule " + ruleTrace.getRuleName());
else
System.out.println("");
// The analysis can continue by obtaining the list of FactRecords that matched the rule and
// proceeding to analyze the trace back in time.
List<FactTrace> matchingFacts = ta.getRuleMatchedFacts(ruleTrace);

5.10.3 本番レベルおよび開発レベルのトレース用のデシジョン・トレースのサンプル

例5-5に、本番レベルのトレース・ドキュメントのサンプルを示します。

例5-5 本番レベルのデシジョン・トレースのサンプル

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<decision-trace xmlns="http://xmlns.oracle.com/rules/decisiontrace">
<trace-entries xsi:type="rule-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975549890</timestamp>
<rule-name>OrderDiscount.goldCustomer</rule-name>
<token-time>0</token-time>
<sequence-number>1</sequence-number>
</trace-entries>
<trace-entries xsi:type="rule-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975549893</timestamp>
<rule-name>OrderDiscount.goldCustomerDiscount</rule-name>
<token-time>0</token-time>
<sequence-number>2</sequence-number>
</trace-entries>
<trace-entries xsi:type="rule-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975549894</timestamp>
<rule-name>OrderDiscount.applyDiscount</rule-name>
<token-time>0</token-time>
<sequence-number>3</sequence-number>
</trace-entries>
</decision-trace>

5.10.4 開発レベルのデシジョン・トレースのサンプル

例5-6に、開発レベルのディジョン・トレース・ドキュメントのサンプルを示します。

例5-6 開発レベルのデシジョン・トレースのサンプル

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<decision-trace xmlns="http://xmlns.oracle.com/rules/decisiontrace">
<trace-entries xsi:type="fact-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975491008</timestamp>
<fact-id>1</fact-id>
<operation>assert</operation>
<fact-type>com.example.Customer</fact-type>
<object-type>com.example.Customer</object-type>
<fact-object>
<properties>
<name>YTDOrderAmount</name>
<value>
<string>2000.0</string>
</value>
</properties>
<properties>
<name>level</name>
<value>
<string>null</string>
</value>
</properties>
<properties>
<name>name</name>
<value>
<string>OneLtd</string>
</value>
</properties>
<properties>
<name>pastDue</name>
<value>
<string>false</string>
</value>
</properties>
</fact-object>
</trace-entries>
<trace-entries xsi:type="activation-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975491024</timestamp>
<rule-name>OrderDiscount.goldCustomer</rule-name>
<token-time>2</token-time>
<fact-ids>1</fact-ids>
<operation>add</operation>
</trace-entries>
<trace-entries xsi:type="fact-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975491025</timestamp>
<fact-id>2</fact-id>
<operation>assert</operation>
<fact-type>com.example.Order</fact-type>
<object-type>com.example.Order</object-type>
<fact-object>
<properties>
<name>customerName</name>
<value>
<string>OneLtd</string>
</value>
</properties>
<properties>
<name>discount</name>
<value>
<string>0.0</string>
</value>
</properties>
<properties>
<name>grossAmount</name>
<value>
<string>400.0</string>
</value>
</properties>
<properties>
<name>netAmount</name>
<value>
<string>0.0</string>
</value>
</properties>
<properties>
<name>number</name>
<value>
<string>1001</string>
</value>
</properties>
</fact-object>
</trace-entries>
<trace-entries xsi:type="activation-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975491035</timestamp>
<rule-name>OrderDiscount.goldCustomerDiscount</rule-name>
<token-time>5</token-time>
<fact-ids>2</fact-ids>
<fact-ids>1</fact-ids>
<operation>add</operation>
</trace-entries>
<trace-entries xsi:type="rule-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975491036</timestamp>
<rule-name>OrderDiscount.goldCustomerDiscount</rule-name>
<token-time>5</token-time>
<fact-ids>2</fact-ids>
<fact-ids>1</fact-ids>
<sequence-number>2</sequence-number>
</trace-entries>
...
<trace-entries xsi:type="rule-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975491036</timestamp>
<rule-name>OrderDiscount.applyDiscount</rule-name>
<token-time>7</token-time>
<fact-ids>2</fact-ids>
<sequence-number>3</sequence-number>
</trace-entries>
...
<trace-entries xsi:type="ruleset-stack-trace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<timestamp>1248975491037</timestamp>
<operation>pop</operation>
<ruleset-name>OrderDiscount</ruleset-name>
</trace-entries>
</decision-trace>

A JavaとRLの相違点のサマリー

この付録では、RL LanguageとJava言語の相違点について説明します。

A.1 RLがJavaと異なる点

この項では、RLとJavaの違いを示します。

- RLには、インタフェースまたはメソッドが含まれません。

- RLグローバル変数はJavaの静的なクラス変数に類似していますが、各ルール・セッションのインスタンスは1つです。

- RLには、staticキーワードがありません。

- RLには、パッケージのかわりにルールセットがあります。ルールセットによって、定義とアクションがグループ化されます。

- RLクラスおよびJavaクラスのインスタンスは、作業メモリーでファクトとしてアサートできます。

- RLファクトはガベージ・コレクションの対象ではないため、明示的に取り消す必要があります。

- RLは解析されます。コンパイルやクラス・ロードはありません。クラスと関数は、使用する前に定義する必要があります。

- RLクラスに含まれるのはデータ・フィールドのみで、コンストラクタやメソッドは含まれません。データ・フィールドの動作は、Java Beanプロパティと同様です。

- Java Beanプロパティは、RL内のフィールドとしてアクセスできます。

- new演算子を使用すると、コンストラクタが定義されているかどうかに関係なく、名前付きプロパティに値を明示的に割り当てることができます。 fact演算子を使用すると、名前付きプロパティと値を照合し、varキーワードを使用して名前付きプロパティから値を取得できます。プロパティは、Javaオブジェクトの場合はJava Beanプロパティ、RLオブジェクトの場合はフィールドになります。

- RL配列は、1次元に制限されています。

- ifおよびwhileアクションは、中カッコ({})で囲んでブロック内に存在する必要があります。

- RLには、switchアクション、continue文、break文、またはネストされたループを終了するためのラベル付きの文がありません。

- RLのforループには、カンマ区切りの初期化式または更新式を複数含めることはできません。

- RLは、ビット単位の&および|演算子をサポートしていません。

- RLは、関数とJavaメソッドのオーバーロードをサポートしています(最適なものが使用されます)。

- RL変数は、定義時に初期化する必要があります。

- RLオブジェクトおよびJavaオブジェクトに対して==を使用すると、常にオブジェクトのequalsメソッドが起動します。RLでは、オブジェクト参照が等価であることはテストできません。オブジェクトに対して!=を使用すると、オブジェクト参照が等価でないことはテストされず、equalsメソッドの否定になります。
次の文について考えてみます。

if (object1 != object2){}

これは、次の文と同じです。

if (! (object1.equals(object2)){}

- クラスまたは関数の前方参照はできません。

- Javaでは、Java BeanのIntrospectorによって書込み専用プロパティがインクルードされます。Beanのようなプロパティはルール内で判断できないためRLに組み込まれません。このため、RLでJavaファクト・タイプのBeanプロパティに適切にアクセスするには、これらのプロパティにgetterとsetterの両方が必要です。setterがありgetterがないプロパティ(書込み専用プロパティ)は、RLの新規構文では使用できません。
たとえば、Bean FooにメソッドsetProp1(int i)のみがある場合、RLではFoo f = new Foo(prop1: 0)を使用できません。

Oracleの法律上の注意点

コピーライト

Copyright © 1994-2017, Oracle and/or its affiliates. All rights reserved.

ライセンス制約の保証と結果的に生じる損害の免責

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

保証免責

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクルまでご連絡ください。

制限付権利について

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

危険な用途への使用について

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、Oracle Corporationおよびその関連会社は一切の責任を負いかねます。

商標と登録商標について

OracleおよびJavaはオラクルおよびその関連会社の登録商標です。その他の社名、商品名等は各社の商標または登録商標である場合があります。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

第三者のコンテンツ、製品、サービスに対する免責事項

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。適用されるお客様とOracle Corporationとの間の契約に別段の定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。適用されるお客様とOracle Corporationとの間の契約に定めがある場合を除いて、Oracle Corporationおよびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

Pre-General Availability (一般提供前)版のドキュメントについて

このドキュメントがPre-General Availability (一般提供前)版の場合:

このドキュメントはPre-General Availability (一般提供前)版であり、デモおよび暫定使用のみを目的としたものです。このソフトウェアを使用するハードウェアに限定するものではありません。Oracle Corporationおよびその関連会社は、このドキュメントに関して一切の責任を負わず、いかなる保証もいたしません。また、このドキュメントを使用したことによって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。

非公開のPre-General Availability (一般提供前)版のドキュメントについて

このドキュメントが非公開のPre-General Availability (一般提供前)版の場合:

このドキュメントに含まれる情報は、情報の共有のみを目的としたものであって、顧客諮問委員会(Customer Advisory Board)のメンバーとしてのお客様の立場でのみ、またはお客様のPre-General Availability Trial Agreement (Pre-GAトライアル契約)のみに従って検討されるべきものとします。マテリアル、コード、または機能の提供をお約束するものではなく、購入決定を行う際の判断材料とすべきではありません。このドキュメントに記載されている特徴または機能の開発、リリースおよび時期については、オラクルの裁量により決定されます。

このドキュメントには、ソフトウェアまたは印刷物などの形式を問わず、オラクルが独占的な権利を有する財産的情報が含まれています。この機密資料へのアクセスと使用は、お客様とオラクルとの間で締結され、お客様が遵守に同意した、Oracle Master Agreement、Oracle License and Oracle Services Agreement (オラクル・ライセンスおよびサービスに関する契約書)、Oracle Partner Network Agreement、Oracle Distribution Agreementまたはその他のライセンス契約の条件に従うものとします。このドキュメントとその内容の開示、コピー、複製および配布には、オラクルによる事前の承諾を必要とします。このドキュメントはライセンス契約の一部となるものではなく、オラクルおよびその子会社や関連会社との契約を構成するものではありません。

ドキュメントのアクセシビリティ

オラクルのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracle Supportへのアクセス

サポートをご契約のお客様には、My Oracle Supportを通して電子支援サービスを提供しています。詳細情報は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info)か、聴覚に障害のあるお客様は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs)を参照してください。