第3章 ユーザーガイド

3.1. 構築

org.drools.builder

図3.1 org.drools.builder

3.1.1. コードによる構築

Knowledge Builder はソースデータを取得し、knowledge package に変換します。knowledge package には Knowledge Base が消費するルールおよびプロセス定義が含まれています。

注記

名前の通り、ResourceType オブジェクトクラスは構築されるリソースのタイプを示します。
ResourceFactory は、reader、クラスパス、URI、ファイルまたは ByteArray など含む複数のソースよりリソースをロードする機能を提供します。

重要

バイナリ (決定テーブルなど) を扱う場合、Reader ベースのリソースハンドラーは使用しないでください。これらのハンドラーはプレインテキストでの使用のみに適しています。
KnowledgeBuilder

図3.2 KnowledgeBuilder

注記

Knowledge BuilderKnowledgeBuilderFactory によって作成されます。
KnowledgeBuilderFactory

図3.3 KnowledgeBuilderFactory

デフォルトの設定を使用して Knowledge Builder を作成します。

例3.1 新しい Knowledge Builder の作成

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
KnowledgeBuilderFactory を使用して設定を作成します。このような設定により Knowledge Builder の挙動を変更できるようになります。

注記

ユーザーの多くは、デフォルトパスにないクラスを Knowledge Builder オブジェクトが解決できるようにするカスタム クラスローダー を提供するために、この設定の作成を行います。
最初のパラメーターは properties のパラメーターです。これは任意のパラメーターで、 null のままにしておくことが可能です。この場合、デフォルトのオプションが使用されます。options パラメーターは、方言の変更や新しい accumulator 関数の登録などのタスクに使用できます。

例3.2 カスタムクラスローダーを使用した新しい Knowledge Builder の作成

KnowledgeBuilderConfiguration kbuilderConf = 
    KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(
        null, classLoader );

KnowledgeBuilder kbuilder = 
	KnowledgeBuilderFactory.newKnowledgeBuilder(kbuilderConf);
全タイプのリソースを繰り返し追加することが可能です。次の例では、.drl ファイルが追加されます。

注記

Knowledge Builder は、JBoss Rules 4.0 Package Builder では不可能であった複数の名前空間の処理を行います。そのため、名前空間に関係なく、リソースの追加を継続することが可能です。

例3.3 DRL リソースの追加

kbuilder.add( ResourceFactory.newFileResource( "/project/myrules.drl" ), 
    ResourceType.DRL);

重要

必ず、追加後に hasErrors() メソッドをチェックしてください。エラーがある時は、リソースを追加したり Knowledge Package を読み出したりしないでください (エラーがある場合、getKnowledgePackages() は空のリストを返します)。

例3.4 検証

if( kbuilder.hasErrors() ) 
{
	System.out.println( kbuilder.getErrors() );
	return;
}
すべてのリソースが追加され、エラーがなくなると Knowledge Packageコレクション を取得します (「コレクション」と表現したのは、パッケージの名前空間ごとに 1 つの Knowledge Package があるからです)。これらの Knowledge Packageシリアライズ可能 で、頻繁にデプロイメントの単位として使用されます。

例3.5 Knowledge Package の取得

Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();
最後の例はこれらすべての要素を組み合わせています。

例3.6 全要素の組み合わせ

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
if( kbuilder.hasErrors() ) {
    System.out.println( kbuilder.getErrors() );
    return;
}

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newFileResource( "/project/myrules1.drl" ),
    ResourceType.DRL);
kbuilder.add( ResourceFactory.newFileResource( "/project/myrules2.drl" ),
    ResourceType.DRL);

if( kbuilder.hasErrors() ) 
{
    System.out.println( kbuilder.getErrors() );
    return;
}

Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();

3.1.2. 設定および Change-Set XML を用いた構築

リソースを追加してプログラミングを行う代わりに、設定を用いて定義を作成することが可能です。これには Change-Set XML を使用します。簡単な XML ファイルは、addremove、および modify の 3 つの要素をサポートします。これらの各要素は、設定エンティティを定義する resource サブ要素のシーケンスを持ちます。

警告

以下の XML スキーマは 規範的 ではなく、説明する目的でのみ記載されています。

例3.7 Change-Set XML のスキーマ (非「規範的」)

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://drools.org/drools-5.0/change-set"
           targetNamespace="http://drools.org/drools-5.0/change-set">

  <xs:element name="change-set" type="ChangeSet"/>

  <xs:complexType name="ChangeSet">
    <xs:choice maxOccurs="unbounded">
      <xs:element name="add"    type="Operation"/>
      <xs:element name="remove" type="Operation"/>
      <xs:element name="modify" type="Operation"/>
    </xs:choice>
  </xs:complexType>

  <xs:complexType name="Operation">
    <xs:sequence>
      <xs:element name="resource" type="Resource"
                  maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Resource">
    <xs:sequence>
      <!-- To be used with <resource type="DTABLE"...&gt> -->
      <xs:element name="decisiontable-conf" type="DecTabConf"
                  minOccurs="0"/>
    </xs:sequence>
    <!-- java.net.URL, plus "classpath" protocol -->
    <xs:attribute name="source" type="xs:string"/>
    <xs:attribute name="type"   type="ResourceType"/>
    <xs:attribute name="basicAuthentication" type="xs:string"/>
    <xs:attribute name="username" type="xs:string"/>
    <xs:attribute name="password" type="xs:string"/>
  </xs:complexType>

  <xs:complexType name="DecTabConf">
    <xs:attribute name="input-type"     type="DecTabInpType"/>
    <xs:attribute name="worksheet-name" type="xs:string"
                  use="optional"/>
  </xs:complexType>

  <!-- according to org.drools.builder.ResourceType -->
  <xs:simpleType name="ResourceType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="DRL"/>
      <xs:enumeration value="XDRL"/>
      <xs:enumeration value="DSL"/>
      <xs:enumeration value="DSLR"/>
      <xs:enumeration value="DRF"/>
      <xs:enumeration value="DTABLE"/>
      <xs:enumeration value="PKG"/>
      <xs:enumeration value="BRL"/>
      <xs:enumeration value="CHANGE_SET"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- according to org.drools.builder.DecisionTableInputType -->
  <xs:simpleType name="DecTabInpType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="XLS"/>
      <xs:enumeration value="CSV"/>
    </xs:restriction>
  </xs:simpleType>

</xs:schema>

注記

BRMS 5.1 以降、ユーザーは HTTP 上で認証されます。例3.7「Change-Set XML のスキーマ (非「規範的」)」 に記載されている次の 3 つの行は、BRMS 5.1 およびそれ以降のバージョンで必要となりますが、BRMS 5.0 では含まれないようにしてください。
    <xs:attribute name="basicAuthentication" type="xs:string"/>
    <xs:attribute name="username" type="xs:string"/>
    <xs:attribute name="password" type="xs:string"/>

重要

現在、add 要素のみがサポートされています。繰り返しの変更をサポートするため、他の要素も後日実装される予定です。
次の例は単一の .drl ファイルをロードします。

例3.8 単純な Change-Set XML

<change-set xmlns='http://drools.org/drools-5.0/change-set'
            xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
            xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd' >
   <add>
      <resource source='file:/project/myrules.drl' type='DRL' />
   </add>
</change-set>
リソースのプロトコルを示す file: プレフィックスに注目してください。Change-Set は、filehttp など java.net.URL によって提供されるすべてのプロトコルをサポートし、classpath の追加バージョンもサポートします。

重要

ファイル名の拡張子から推論されないため、必ずリソースに type 属性を指定するようにしてください。
Java で ClassPath resource loader を使用して、リソースの特定に使用される class loader を指定します (XML では不可能です)。デフォルトでは、Knowledge Builder によって使用される class loader が使用されます (Change-Set XML が ClassPath リソースによってロードされる場合を除きます。この場合、リソースに対して指定された class loader が使用されます)。

例3.9 Change-Set XML のロード

kbuilder.add(ResourceFactory.newUrlResource(url),ResourceType.CHANGE_SET);
change-set には任意数のリソースを含めることができます。結果的に、これらのリソースは追加の設定情報をサポートします (現在、この使用は決定テーブルのみに制限されています)。例3.10「リソース設定を用いた Change-Set XML」 は HTTP URL とクラスパス上の Excel 決定テーブルの両方よりルールをロードします。

例3.10 リソース設定を用いた Change-Set XML

<change-set xmlns='http://drools.org/drools-5.0/change-set'
    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
    xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd' >
    <add>
        <resource source='http:org/domain/myrules.drl' type='DRL' />
        <resource source='classpath:data/IntegrationExampleTest.xls' 
          type="DTABLE">
          <decisiontable-conf input-type="XLS" worksheet-name="Tables_2" />
        </resource>
    </add>
</change-set>
変更通知 機能を提供し、自動的に Knowledge Base を再構築するため、Change-Set は Knowledge Agent を使用する時に便利です (これらの機能の詳細は Knowledge Agent の項の「デプロイメント」に記載されています)。
ディレクトリ内のリソースをすべて追加するため、ディレクトリを指定することも可能です (ソフトウェアはすべてのリソースが同じタイプであることを想定します)。Knowledge Agent を使用する場合、リソースへの変更を継続的にスキャンします。また、キャッシュされた Knowledge Base も再構築します。

注記

change-set を Knowledge Agent と併用することも可能です。詳細は 「KnowledgeAgent」 を参照してください。

例3.11 ディレクトリの内容を追加するための Change-Set XML コード

<change-set xmlns='http://drools.org/drools-5.0/change-set'
    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
    xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd' >
    <add>
        <resource source='file:/projects/myproject/myrules' type='DRL' />
    </add>
</change-set>

3.2. デプロイメント

3.2.1. KnowledgePackage とナレッジ定義

KnowledgePackageナレッジ定義 のコレクションです。ナレッジ定義とは、ルールとプロセスの別の呼び方です。「構築」 に説明がある通り、KnowledgePackageKnowledgeBuilder によって作成されます。KnowledgePackage は自己充足的で、シリアライズ可能です。現在の基本的なデプロイメントユニットを形成します。
KnowledgePackage

図3.4 KnowledgePackage

重要

KnowledgePackageKnowledge Base に追加されますが、KnowledgePackage インスタンスは追加されると再使用できないことに注意してください。別の knowledge base に追加するには、最初に シリアライズ を行い、「クローン」された結果を使用します。 JBoss Rules の今後のバージョンでは、この制限がなくなる予定です。

3.2.2. ナレッジベース

ナレッジベース

図3.5 ナレッジベース

knowledge base は、アプリケーションすべての ナレッジ定義 が格納されるレポジトリです。これには、ルール、プロセス、関数およびタイプモデルが含まれます。knowledge base 自体には「インスタンス」データ (ファクト) は含まれません。この代わりに、セッションは Knowledge Base より作成されます。factsKnowledge Base へ挿入され、process instancesKnowledge Base より開始します。

重要

knowledge base の作成は比較的リソースを多く使用するプロセスですが、セッションの作成はそうではありません。よって、セッションを繰り返し作成できるようにするため、Red Hat は可能な限り knowledge bases をキャッシュすることを推奨します。
knowledge bases オブジェクトも シリアライズ可能 であるため、構築して保存する方がよいでしょう。こうすることで、knowledge packages ではなくデプロイメントの単位として取り扱うことが可能です。
knowledge base を作成する方法の 1 つが KnowledgeBaseFactory クラスを使用する方法です。
KnowledgeBaseFactory

図3.6 KnowledgeBaseFactory

デフォルト設定を使用して作成する方法もあります。

例3.12 新しいナレッジベースの作成

KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
Knowledge Builder と共にカスタマイズされた class-loader を使用してデフォルトの loader にない types を解決したい場合、これを Knowledge Base に設定します (このテクニックは Knowledge Builder に適用されるものと同じです)。

例3.13 カスタム Class-Loader を用いた新しいナレッジベースの作成

KnowledgeBaseConfiguration kbaseConf =
    KnowledgeBaseFactory.newKnowledgeBaseConfiguration( null, cl );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( kbaseConf );

3.2.3. インプロセス構築およびデプロイメント

デプロイメントの最も簡単な形式は インプロセス構築 と呼ばれます。この場合、ナレッジ定義がコンパイルされ、同じ Java 仮想マシンにある knowledge base に追加されます。

重要

この方法を使用する際、drools-${module}-${version}.jar ファイルが必ずクラスパス上にあるようにしてください。

例3.14 Knowledge PackagesKnowledge Base への追加

Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kpkgs );

注記

addKnowledgePackages(kpkgs) メソッドは繰り返し呼び出せることを理解してください。これはナレッジを追加するために行います。

3.2.4. 別プロセスとしての構築およびデプロイメント

Knowledge BaseKnowledgePackage は両方ともデプロイメントの単位であるため、シリアライズすることが可能です。そのため、drools-compiler.jar に必要な構築を実行するため 1 つのマシンを割り当て、すべてをデプロイおよび実行するために他のマシンを確保することができます。2 つ目のマシンは drools-core.jar のみを必要とします。
シリアライズは標準的な Java の用法ですが、以下の例は、あるマシンがデプロイメントユニットを書き込むと別のマシンがどのようにそれを読み取って使用するかを表しています。

例3.15 KnowledgePackage を出力ストリームへ書き込む

ObjectOutputStream out = 
	new ObjectOutputStream( new FileOutputStream( fileName ) );
out.writeObject( kpkgs );
out.close();

例3.16 入力ストリームから KnowledgePackage を読み取る

ObjectInputStream in = new ObjectInputStream( new FileInputStream( fileName ) );
// The input stream might contain an individual
// package or a collection.
@SuppressWarnings( "unchecked" )
Collection<KnowledgePackage> kpkgs =
    ()in.readObject( Collection<KnowledgePackage> );
in.close();

KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kpkgs );
実際の knowledge base 自体もシリアライズ可能であるため、ナレッジパッケージではなく構築と保存を行うことが推奨されます。

注記

Red Hat のサーバー側管理システムである Drools Guvnor はこのデプロイメント方法を使用します。シリアライズされた knowledge packages を URL へコンパイルおよびパブリッシュした後、このアドレスリソースタイプを使用してこれらをロードできます。

3.2.5. ステートフルナレッジセッションとナレッジベースの変更

ステートフルナレッジセッション については 「StatefulKnowledgeSession」 で詳細に説明します。ステートフルナレッジセッションは Knowledge Base によって作成され、返されます。また、任意で参照を保持することも可能です。Knowledge Base が変更されると、変更はセッションのデータに適用されます。これは弱い任意の参照で、ブール値フラグによって制御されます。

3.2.6. KnowledgeAgent

KnowledgeAgent は、リソースの自動ロード、キャッシュ、および再ロードを提供するクラスで、プロパティーファイルより設定されます。使用するリソースが変更されると、KnowledgeAgentKnowledge Base を更新または再構築することができます。factory の設定は使用されるストラテジーを決定します (通常はプルベースで、標準のポーリングを使用します)。

注記

ブッシュベースの更新および再構築を行う機能は、今後のバージョンで追加される予定です。
KnowledgeAgent は、デフォルトのポーリング間隔 (60 秒) で追加されたリソースをすべて継続してスキャンします。最後の変更の日付が更新されると、キャッシュされた Knowledge Base は新しいリソースを使用して自動的に再構築されます。
KnowledgeAgent

図3.7 KnowledgeAgent

KnowledgeBuilderFactory オブジェクトは Knowledge Builder を作成するために使用されます。ログファイルが必要とするため、エージェントは名前を指定する必要があります (ログエントリを正しいエージェントへ関連付けできるようにするためです)。

例3.17 KnowledgeAgent の作成

KnowledgeAgent kagent = 
          KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );
KnowledgeAgentFactory

図3.8 KnowledgeAgentFactory

以下の例は、指定された change-set から新しい knowledge base を構築するエージェントを構築します。

注記

change-set の詳細情報は 「設定および Change-Set XML を用いた構築」 を参照してください。

注記

メソッドは繰り返し呼び出すことが可能です。これにより、徐々に新しいリソースを追加することができます。
KnowledgeAgent は、change set から追加されたリソースを 60 秒ごと (デフォルトの間隔) にポーリングして、更新されたか確認します。変更が検出されると、新しい Knowledge Base を構築します。また、ディレクトリがリソースとして指定された場合は、その内容がスキャンされます。

例3.18 KnowledgePackage を出力ストリームへ書き込む

KnowledgeAgent kagent = 
          KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );
kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) );
KnowledgeBase kbase = kagent.getKnowledgeBase();
リソースのスキャンはデフォルトで無効になっています。これはサービスであるため、特別に開始する必要があります。通知に関しても同様です。スキャンと通知の両方を ResourceFactory を用いてアクティベートします。

例3.19 スキャンおよび通知サービスの開始

ResourceFactory.getResourceChangeNotifierService().start();
ResourceFactory.getResourceChangeScannerService().start();
ResourceChangeScannerService クラスより、デフォルトのリソーススキャン期間を変更します (更新された ResourceChangeScannerConfiguration オブジェクトはサービスの configure() メソッドに渡されるため、サービスは要求に応じて再設定できるようになります)。

例3.20 スキャン間隔の変更

ResourceChangeScannerConfiguration sconf =
    ResourceFactory.getResourceChangeScannerService().
        newResourceChangeScannerConfiguration();
// Set the disk scanning interval to 30s, default is 60s.
sconf.setProperty( "drools.resource.scanner.interval", "30" ); 
ResourceFactory.getResourceChangeScannerService().configure( sconf );
KnowledgeAgents は、空の Knowledge Bases と値が入力されたKnowledge Bases の両方を処理できます。値が入力された Knowledge Bases が提供された場合、KnowledgeAgent が内部から イテレーター を実行し、見つかった各リソースをサブスクライブします。

警告

KnowledgeBuilder がディレクトリのリソースをすべて構築するようにすることは可能ですが、この情報は失われます。つまり、これらのディレクトリは連続してスキャンされません。applyChangeSet(Resource) メソッドによって指定されたディレクトリのみが監視されます。

注記

Knowledge Base を土台として使用する利点の 1 つは、KnowledgeBaseConfiguration クラスで Knowledge Base を提供できることです。リソースの変更が検出され、新しい Knowledge Base がインスタンス化されると、以前の Knowledge Base オブジェクトに属する KnowledgeBaseConfiguration クラスが使用されます。

例3.21 既存のナレッジベースの使用

KnowledgeBaseConfiguration kbaseConf =
    KnowledgeBaseFactory.newKnowledgeBaseConfiguration( null, cl );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( kbaseConf );
// Populate kbase with resources here.

KnowledgeAgent kagent =
    KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent", kbase );
KnowledgeBase kbase = kagent.getKnowledgeBase();
上記の例では、リソースの変更が検出され、新しい Knowledge Base が構築されるまで getKnowledgeBase() メソッドは同じ Knowledge Base インスタンスを返します。これは、以前の Knowledge Base へ提供された KnowledgeBaseConfiguration を用いて行われます。

例3.22 ディレクトリの内容を追加する Change-Set XML

<change-set xmlns='http://drools.org/drools-5.0/change-set'
    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
    xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd' >
   <add>
      <resource source='file:/projects/myproject/myrules' type='PKG' />
   </add>
</change-set>

注記

drools-compiler 依存関係は、PKG という名前のリソースタイプには必要ありません。KnowledgeAgentdrools-core のみを用いてこのようなリソースタイプに対応できます。
KnowledgeAgentConfiguration を使用して KnowledgeAgent のデフォルトの動作を変更します。これは、変更に対するディレクトリの連続スキャンを抑制しながらディレクトリよりリソースをロードするために行います。

例3.23 スキャンの挙動変更

KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();

KnowledgeAgentConfiguration kaconf = 
    KnowledgeAgentFactory.newKnowledgeAgentConfiguration(); 
// Do not scan directories, just files.
kaconf.setProperty( "drools.agent.scanDirectories", "false" );
KnowledgeAgent kagent =
    KnowledgeAgentFactory.newKnowledgeAgent( "test agent", kaconf );
これまで、JBoss Enterprise BRMS Platform が URL よりシリアライズされた Knowledge Packages を構築およびパブリッシュする方法と、Change-Set XML が URL とパッケージの両方を処理する方法を見てきました。これらの方法は、Knowledge Agent の重要なデプロイメントのシナリオを形成します。

3.3. 実行

3.3.1. ナレッジベース

KnowledgeBase はアプリケーションの ナレッジ定義 がすべて含まれるレポジトリで、ルール、プロセス、関数、およびタイプモデルが含まれることがあります。Knowledge Base 自体にはインスタンスデータ (ファクト と呼ばれます) は含まれません。ファクトが挿入でき、プロセスインスタンスが起動できる KnowledgeBase よりセッションが作成されます。

注記

Knowledge Base の作成はリソースを大量に消費するプロセスですが、セッションの作成はリソースを大量に消費しません。繰り返しセッションを作成できるようにするため、可能な限り Knowledge Bases をキャッシュするようにしてください。

例3.24 新しいナレッジベースの作成

KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();

3.3.2. StatefulKnowledgeSession

StatefulKnowledgeSession はランタイムデータを格納し、実行します。StatefulKnowledgeSessionKnowledgeBase より作成されます。
StatefulKnowledgeSession

図3.9 StatefulKnowledgeSession

例3.25 KnowledgeBase より StatefulKnowledgeSession を作成

StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

3.3.3. KnowledgeRuntime

3.3.3.1. WorkingMemoryEntryPoint

WorkingMemoryEntryPoint は、ファクトを挿入、更新、および読み出しするメソッドを提供します。

注記

エントリーポイント という用語は、working memory に複数のパーティションが存在し、ファクトが挿入されるパーティションを選択できることに関連しています。しかし、このユースケースはイベント処理を対象とし、ほとんどのルールベースのアプリケーションはデフォルトのエントリーポイントのみを使用します。
KnowledgeRuntime インターフェースは engine と主な対話を行い、ルールの結果とプロセスのアクションで使用可能です。メソッドとインターフェースに関連するルールに焦点を置きますが、KnowledgeRuntimeWorkingMemoryProcessRuntime の両方よりメソッドを継承します。これは、プロセスとルールに対応する統合 API を提供します。ルールを用いて作業する時、WorkingMemoryEntryPointWorkingMemory、および KnowledgeRuntime の 3 つのインターフェースが KnowledgeRuntime を形成します。
WorkingMemoryEntryPoint

図3.10 WorkingMemoryEntryPoint

3.3.3.1.1. 挿入 (insert)
挿入 (insert) WorkingMemory にファクトについて通知する行為です (ksession.insert(yourObject) など)。挿入が行われると、システムはルールに対する一致があるか各ファクトを調べます。ルール実行の有無に関する決定はすべて挿入時に行われます。ただし、fireAllRules() が呼び出されるまでルールは実行されません。必ずすべてのファクトが挿入された後に行います。

注記

fireAllRules() が呼び出された時に条件評価が行われるという誤った考えを持ったユーザーが過去に存在しました。

注記

assert (アサート) または assertion という用語は、利用可能なファクトを示すため、通常は専門システムと関連して使用されます。しかし、ほとんどの言語で「assert」がキーワードとして使用されるため、混乱を防ぐために Red Hat は insert (挿入) というキーワードを使用することにしました。そのため、assert と insert は多くの場合、同じ意味で使用されます。
オブジェクトが挿入されると、ファクトハンドル を返します。FactHandleworking memory 内で挿入されたオブジェクトを示すために使用されるトークンです。 オブジェクトが変更または取り消された時に、working memory との対話にも使用されます。
Cheese stilton = new Cheese("stilton");
FactHandle stiltonHandle = ksession.insert( stilton );
working memory は、equalityidentity の 2 つのアサーションモードのいずれかで操作します (デフォルトは identity です)。
  • Identity が使用される場合、working memoryIdentityHashMap を使用してアサートされたオブジェクトをすべて格納します。インスタンスが新たにアサートされると、常に新しい FactHandle が返されます。同じインスタンスを繰り返し挿入すると、元のファクトハンドルが返されます。
  • Equality が使用される場合、working memoryHashMap を使用してアサートされたオブジェクトをすべて格納します。同等のオブジェクトがアサートされていない場合、インスタンスが新たにアサートされると、新しい FactHandle のみが返されます。
3.3.3.1.2. 取り消し
取り消し は、working memory よりファクトを削除することを意味します。ファクトの追跡やルールの一致は行われないようになります。さらに、そのファクトに依存するアクティベートされたルールは、キャンセルされます。取り消しは、アサート時に返された FactHandle を使用して実行されます。

注記

特定のファクトが存在しない時に実行されるルールを作成することは可能です (not および exist キーワードを使用)。このような場合にファクトを取り消すと、ルールがアクティベートされる原因となることがあります。
Cheese stilton = new Cheese("stilton");
FactHandle stiltonHandle = ksession.insert( stilton );

ksession.retract( stiltonHandle );
3.3.3.1.3. 更新
ファクトの変更を rule engine に通知し、変更されたファクトを再処理できるようにする必要があります。ファクトが更新済みであると見なされる場合、working memory より自動的に取り消され、再度挿入されます。
変更されたオブジェクトが working memory 自体に通知できない場合、update メソッドを使用して通知します。update メソッドは常に変更されたオブジェクトをセカンダリパラメーターとして取ります。これにより、新しいインスタンスを 不変オブジェクト に対して指定できます。

注記

update メソッドは、シャドウプロキシ が有効になったオブジェクトのみに使用できます。

重要

update メソッドは Java コードと併用する場合のみ使用できます。オブジェクトの setter メソッドへの呼び出しを提供するため、ルール内で modify キーワードを使用します。
Cheese stilton = new Cheese("stilton");
FactHandle stiltonHandle = workingMemory.insert( stilton );
...
stilton.setPrice( 100 );
workingMemory.update( stiltonHandle, stilton );

3.3.3.2. ワーキングメモリー

working memoryagenda へのアクセスを提供します。また、クエリの実行を許可し、名前付きの entry points へのアクセスを許可します。
ワーキングメモリー

図3.11 ワーキングメモリー

3.3.3.2.1. クエリ
クエリ を使用してファクトセットを読み出します。ルールで使用されるためパターンが基になります。これらのパターンはオプションのパラメーターを使用することもあります。
Knowlege Base にクエリを定義します。Knowlege Base よりクエリを呼び出して一致する結果を返します。結果コレクション上で繰り替えされる間、get(String identifier) メソッドを使用してクエリのバインド識別子へアクセスできます。getFactHandle(String identifier) を使用すると、その識別子の FactHandle を読み出すことができます。
クエリ結果

図3.12 クエリ結果

QueryResultsRow

図3.13 QueryResultsRow

例3.26 簡単なクエリの例

QueryResults results =
    ksession.getQueryResults( "my query", new Object[] { "string" } );
for ( QueryResultsRow row : results ) {
    System.out.println( row.get( "varName" ) );
}

3.3.3.3. ライブクエリ

JBoss Enterprise BRMS 5.2 はライブクエリをサポートします。
ライブクエリはアタッチされたリスナーを使用し、ビューとして開かれます。また、このビューの内容に対する変更イベントをパブリッシュします。これにより、パラメーターを用いてクエリを実行することが可能になり、結果ビューで変更をリッスンできるようになります。

例3.27 ViewChangedEventListener の実装

final List updated = new ArrayList();
final List removed = new ArrayList();
final List added = new ArrayList();
 
ViewChangedEventListener listener = new ViewChangedEventListener() {           
 public void rowUpdated(Row row) {
  updated.add( row.get( "$price" ) );
 }
  
 public void rowRemoved(Row row) {
  removed.add( row.get( "$price" ) );
 }
  
 public void rowAdded(Row row) {
  added.add( row.get( "$price" ) );
 }
};       
 
// Open the LiveQuery
LiveQuery query = ksession.openLiveQuery( "cheeses",
                                          new Object[] { "cheddar", "stilton" },
                                          listener );
...
...
query.dispose() // make sure you call dispose when you want the query to close

3.3.3.4. KnowledgeRuntime

KnowledgeRuntime は、ルールとプロセスの両方へ適用可能なその他のメソッドを提供します。グローバルを設定したり、ExitPoints を登録するメソッドがこの一例となります。
KnowledgeRuntime

図3.14 KnowledgeRuntime

3.3.3.4.1. グローバル
グローバルrule engine へ渡すことができる名前付きオブジェクトです。挿入する必要はありません。統計情報やルールの右側で使用されるサービスに対して最も頻繁に使用されます。また、rule engine よりオブジェクトを返す手段としても使用されます。
ルールの左側でグローバルを使用するには、次の手順に従います。
  1. 不変であることを確認します。
  2. セッションに設定する前に rules ファイルで宣言します。
    global java.util.List list
  3. これで、Knowlege Base がグローバル識別子とそのタイプを認識するようになったため、任意セッションの ksession.setGlobal を呼び出します。

    警告

    最初にグローバルタイプと識別子を宣言しないと、例外がスローされます。
  4. セッションにグローバルを設定するには、ksession.setGlobal(identifier, value) を使用します。
    List list = new ArrayList();
    ksession.setGlobal("list", list);

    警告

    設定される前にルールがグローバルを評価すると、NullPointerException 例外がスローされます。

3.3.3.5. StatefulRuleSession

NullPointerExceptionStatefulKnowledgeSession によって継承されます。これは、engine 外部に適用可能なルール関連のメソッドを提供します。
StatefulRuleSession

図3.15 StatefulRuleSession

3.3.3.5.1. アジェンダ フィルター
AgendaFilters

図3.16 AgendaFilters

アジェンダフィルターfilter インターフェースの実装です。アジェンダフィルターを使用して実行権利の有効化を許可または拒否します (フィルターできるかは実装に完全依存します)。

注記

バージョン 5.0 では提供されないフィルターで、以前のバージョンの JBoss Rules に含まれているフィルターが複数あります。これらのフィルターは簡単に実装できます。実装方法は JBoss Rules 4 のコードベースを参照してください。
フィルターを使用するには、fireAllRules() を呼び出す時に指定します。次の例では、 Test という文字列で終わるルールのみ実行が許可されます。他のルールはフィルターによって除外されます。
ksession.fireAllRules( new RuleNameEndsWithAgendaFilter( "Test" ) );

3.3.4. アジェンダ

アジェンダ は RETE 機能です。 working memory でアクションが実行される時、ルールが完全一致すると実行可能になります。単一の working memory アクションによって複数のルールを実行可能にできます。ルールが完全一致すると、アクティベーションが作成されます。これはルールと、一致するファクトの両方を参照し、Agenda 上に置かれます。次に Agenda は、競合解決ストラテジを介してアクティベーションの順序を決定します。
engine は 2 つの段階を繰り返します。
  1. 最初の段階は ワーキングメモリーアクション段階 と呼ばれます。ほとんどの作業はこの段階で行われ、 結果 (右側) または主要な Java アプリケーションプロセスのいずれかになります。結果が終了したり、主要の Java アプリケーションが fireAllRules() を呼び出すと、engine がアジェンダの第 2 段階へ切り替えられます。
  2. 第 2 段階は アジェンダ評価段階 と呼ばれます。この段階でシステムは実行するルールを検索します。何も検出されないと終了します。検出されたルールがある場合はそのルールを実行し、その後ワーキングメモリーアクション段階へ切り替えます。
    2段階の実行

    図3.17 2段階の実行

  3. プロセスは agenda が消去されるまで繰り替えされ、消去された時点で時間制御が呼び出しアプリケーションへ返されます。

    注記

    ワーキングメモリーアクションの実行中、ルールは実行されません。
    アジェンダ

    図3.18 アジェンダ

3.3.4.1. 競合の解決

agenda に複数のルールがある場合、競合解決ストラテジが必要となります。ルールの実行はワーキングメモリーに影響を与えることがあるため、rule engine はルールが実行される順序を認識する必要があります (たとえば、ruleA を実行すると ruleB がアジェンダより削除される原因となることがあります)。
JBoss Rules は次の 2 つの競合解決ストラテジーを使用します。
  • Salience
  • LIFO (後入れ先出し)
salience ストラテジーを使用すると特定ルールが他のルールよりも優先度が高いことを指定できます (大きい数字を割り当てます)。この場合、高い salience を持つルールが優先されます。
LIFO ストラテジーは、割り当てられた working memoryaction counter 値を基に優先度を決定します。同じアクションが同じ値を受け取る間に各ルールが作成されます (実行のセットが同じ優先度値を持つ場合、実行順序は任意になります)。

重要

場合によっては回避不可能ですが、正しく動作させるために特定順序の実行に依存するルールは作成しないようにしてください。ルールを必須プロセスの手順として考慮しないでください。

注記

以前のバージョンの JBoss Rules はカスタムの競合解決ストラテジーをサポートしていました。この機能はバージョン 5 でも存在しますが、アプリケーションプログラミングインターフェースが公開されないようになりました。

3.3.4.2. AgendaGroup

AgendaGroup

図3.19 AgendaGroup

アジェンダグループ (CLIPS の用語では「モジュール」と呼ばれます) を使用して agenda 上のアクティベーションを分割します。常に 1 つのグループのみが「フォーカス」を持つことができ、そのグループに属するアクティベーションのみを有効にできます。

注記

特定状況 (処理の段階など) に適用するルールのサブセットを 1 つ以上定義し、これらのルールセットがいつ適用されるかを制御するために、Agenda groups は最も一般的に使用されます。
ルール内部または JBoss Rules アプリケーションプログラミングインターフェースを介してフォーカスを設定します (auto-focus を使用するようルールを設定する方法もあります。この方法では、agenda group が一致するとフォーカスされます)。
setFocus() が呼び出されるたびに、agenda groupスタック にプッシュされます。フォーカスグループが空である場合、スタックから削除され、次のフォーカスグループ (この時点で一番上のグループ) を評価することが許可されます。

注記

agenda group はスタックの複数の場所に表示できます。
ksession.getAgenda().getAgendaGroup( "Group A" ).setFocus();
デフォルトの agenda group グループは MAIN と呼ばれます。これがスタックの最初のグループで、最初にフォーカスを持ちます。agenda group のないルールは自動的にこのグループに置かれます。

3.3.4.3. アクティベーショングループ

ActivationGroup

図3.20 ActivationGroup

activation groupactivation-group ルール属性によってバインドされるルールのセットです。このグループでは 1 つのルールのみが実行できます。そのルールが実行した後、他のルールはすべてキャンセルされます。

注記

任意のタイミングで clear() メソッドを呼び出し、アクティベーションが実行する前にすべてのアクティベーションをキャンセルします。
ksession.getAgenda().getActivationGroup( "Group B" ).clear();

3.3.5. イベントモデル

event packagerule engine イベントの1つに通知します。これを使用して、アプリケーションの主な部分やルールから、ロギングおよび監査のアクティビティーを切り離します。
KnowledgeRuntimeEventManager インターフェースは KnowledgeRuntime クラスによって実装されます。このクラスは、WorkingMemoryEventManagerProcessEventManager の 2 つのインターフェースを提供します。

注記

本書では WorkingMemoryEventManager のみ取り上げます。
KnowledgeRuntimeEventManager

図3.21 KnowledgeRuntimeEventManager

WorkingMemoryEventManager を使用してリスナーを追加および削除します。リスナーを追加すると、working memory および agenda に影響するイベントを「リッスン」できます。
WorkingMemoryEventManager

図3.22 WorkingMemoryEventManager

次のコードは、簡単な agenda listener を宣言し、セッションにアタッチする方法を表しています。アクティベーションが実行された後に、アクティベーションを出力します。

例3.28 AgendaEventListener の追加

ksession.addEventListener( new DefaultAgendaEventListener() {
    public void afterActivationFired(AfterActivationFiredEvent event) {
        super.afterActivationFired( event );
        System.out.println( event );
    }
});
JBoss Rules は、デバッグ出力ステートメントと共に各メソッドを実装する DebugWorkingMemoryEventListener および DebugAgendaEventListener と呼ばれる 2 つのクラスも提供します。すべての working memory イベントを出力するには、これらリスナーの 1 つを追加します。

例3.29 新しい KnowledgeBuilder の作成

ksession.addEventListener( new DebugWorkingMemoryEventListener() );
イベント発生元より KnowledgeRuntime を読み出すには、KnowledgeRuntimeEvent インターフェースを使用します。
KnowledgeRuntimeEvent

図3.23 KnowledgeRuntimeEvent

サポートされるイベントは次の通りです。
ActivationCreatedEventActivationCancelledEvent
BeforeActivationFiredEventAfterActivationFiredEvent
AgendaGroupPushedEventAgendaGroupPoppedEvent
ObjectInsertEventObjectRetractedEvent
ObjectUpdatedEventProcessCompletedEvent
ProcessNodeLeftEventProcessNodeTriggeredEvent
ProcessStartEvent 

3.3.6. KnowledgeRuntimeLogger

アプリケーションが実行されると、毎回 KnowledgeRuntimeLoggerJBoss Rulesevent system を使用して監査ログを作成します。JBoss Rules IDEAudit Viewer などのツールを使用してこのログを調査します。
KnowledgeRuntimeLoggerFactory

図3.24 KnowledgeRuntimeLoggerFactory

例3.30 FileLogger

KnowledgeRuntimeLogger logger = 
    KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "logdir/mylogfile");
...
logger.close();
newFileLogger() メソッドを使用して、自動的にファイル拡張子 .log をファイルへ追加します。

3.3.7. StatelessKnowledgeSession

StatelessKnowledgeSessionStatefulKnowledgeSession をラッピングし、決定サービスタイプのシナリオに関連して使用されます。この存在により、dispose() の呼び出しが軽減されます。
ステートレスセッションの使用時に、繰り返し挿入を実行したり Java コードから fireAllRules() メソッドを呼び出したりすることはできません。 execute() メソッドは内部で StatefullKnowledgeSession をインスタンス化し、ユーザーデータをすべて追加してユーザーコマンドを実行します。その後、fireAllRules() および dispose() メソッドを呼び出します。
通常、BatchExecution コマンドよりこのクラスを使用します (CommandExecutor インターフェースによってサポートされます)。しかし、2 つの 簡便性 (convenience) メソッド も提供されています。これらのメソッドは、簡単なオブジェクト挿入が必要な場合のみ使用します (CommandExecutor および BatchExecution は独自の項で詳細に説明されています)。
StatelessKnowledgeSession

図3.25 StatelessKnowledgeSession

次の例は、Java オブジェクトのコレクションを実行するため、Convenience API を使用して stateless session を実行することを表しています。コレクションを繰り返し処理し、各要素を順に挿入します。

例3.31 コレクションを用いた簡単な StatelessKnowledgeSession の実行

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newFileResource( fileName ), ResourceType.DRL );
if (kbuilder.hasErrors() ) {
    System.out.println( kbuilder.getErrors() );
} else {
    KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
    kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
    StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
    ksession.execute( collection );
}
単一コマンドとして同じことを実行するには、次のコードを使用します。

例3.32 InsertElements コマンドを用いた簡単な StatelessKnowledgeSession の実行

ksession.execute( CommandFactory.newInsertElements( collection ) );
コレクションの繰り返し処理や要素の挿入を行わずにコレクション自体を挿入するには、CommandFactory.newInsert(collection) を使用します。
CommandFactory にはサポートされるコマンドの詳細が含まれています。これらのコマンドのいずれかをマーシャリングするには XStream および BatchExecutionHelper を使用します。 また、BatchExecutionHelper を使用して、使用される XML 形式の詳細について学びます。JBoss Rules Pipeline を使用して、自動的に BatchExecution および ExecutionResults をマーシャリングします。
StatelessKnowledgeSession はさまざまなやり方でグローバルをスコープ指定できるようにします。最初はコマンドではない方法です。コマンドは特定の実行呼び出しへスコープ指定されます (グローバルは 3 つの方法で解決されます)。
  • StatelessKnowledgeSessiongetGlobals() メソッドは Globals インスタンスを返します。名前の通り、このメソッドはセッションのグローバルへのアクセスを提供します。セッションのグローバルは すべての 実行呼び出しによって共有されます。

    警告

    実行呼び出しは異なるスレッドで同時に実行できるため、可変グローバル を扱う場合は注意が必要です。

    例3.33 セッションスコープグローバル

    StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
    // sets a global hibernate session, that can be used 
    // for DB interactions in the rules.
    ksession.setGlobal( "hbnSession", hibernateSession ); 
    // Execute while being able to resolve the "hbnSession" identifier.  
    ksession.execute( collection );
  • 委譲を使用してグローバル解決を実行する方法もあります。グローバルに値を割り当てると (setGlobal(String, Object) を使用)、値は内部コレクションに格納されます。これは、識別子を値へマッピングすることが目的です。これらの識別子は提供される委譲よりも優先されます。識別子が見つからない場合のみ委譲グローバル (存在する場合) が使用されます。
  • グローバルを解決する 3 つ目の方法は、 実行スコープグローバル を使用することです。この場合、グローバルを設定するコマンドは CommandExecutor へ渡されます。
また、CommandExecutor インターフェースは out パラメーターを用いてデータをエクスポートする機能も提供します。挿入されたファクト、グローバル、およびクエリの結果はすべて返すことが可能です。

例3.34 out 識別子

// Set up a list of commands
List cmds = new ArrayList();
cmds.add( CommandFactory.newSetGlobal( "list1", new ArrayList(), true ) );
cmds.add( CommandFactory.newInsert( new Person( "jon", 102 ), "person" ) );
cmds.add( CommandFactory.newQuery( "Get People" "getPeople" );

// Execute the list
ExecutionResults results =
  ksession.execute( CommandFactory.newBatchExecution( cmds ) );

// Retrieve the ArrayList
results.getValue( "list1" );
// Retrieve the inserted Person fact
results.getValue( "person" );
// Retrieve the query as a QueryResults instance.
results.getValue( "Get People" );

3.3.7.1. シーケンシャルモード

Rete はオブジェクトを徐々にアサートでき、ルールも追加および削除できるステートフルセッションを提供します。ただし、ステートフルセッションでは最初のデータセットが提供された後に、データをアサートしたり変更することはできず、ルールを追加したり削除することもできません。この場合、ルールを再評価する必要はなく、engine は簡素化された方法で稼働できます。以下の手順に従ってください。
  1. ルールセットの salience と position によりルールの順番を決定します (rule terminal ノードの sequence 属性を設定します)。
  2. 可能なルールアクティベーションごとに 1 つの要素を持つアレイを作成します。要素のポジションが実行順序を表します。
  3. right-input オブジェクトメモリー 以外の ノードメモリー をすべてオフにします。
  4. Left Input Adapter Node 伝播の接続を切断し、コマンドオブジェクトがオブジェクトとノードを参照できるようにします。後で実行するために、このコマンドオブジェクトは working memory のリストに追加されます。
  5. すべてのオブジェクトをアサートします。アサートが実行され、right-input ノードメモリーにデータが投入されると、コマンドリストを確認し、各項目を順番に実行します。
  6. ルールに対して決定されたシーケンス番号に従って、結果となるすべてのアクティベーションをアレイに格納します。繰り返し処理の範囲を縮小するため、最初と最後に投入された要素を記録します。
  7. アクティベーションのアレイを繰り返し処理し、投入された要素を順番に実行します。
  8. 許可される最大ルール実行数が存在する場合、アレイのルールをすべて実行するため、ネットワーク評価を早期に終了します。

注記

タプルの作成、オブジェクトの追加、およびタプルの伝播は LeftInputAdapterNode によって実行されないようになりました。代わりに、コマンドオブジェクトが作成され、working memory のリストに追加されるようになりました。このオブジェクトには、LeftInputAdapterNode と伝播されたオブジェクト両方への参照が含まれます。これにより、 挿入時に left-input 伝播が発生しないようにするため、left-input で結合を実行しようとする right-input 伝播はありません (よって、left-input メモリーが不必要になります)。
left-input タプルメモリーを含むノードのメモリーはほぼすべてオフになりますが、right-input オブジェクトメモリーは除外されます。そのため、挿入の伝播を記憶するノードは right-input オブジェクトメモリーのみになります。
すべてのアサートが終了し、その結果 right-input メモリーがすべて投入されたら、LeftInputAdapterNode コマンドオブジェクトを順に呼び出し、LeftInputAdapterNode コマンドオブジェクトのリストを繰り返し処理します。これらのコマンドオブジェクトはネットワークへ渡され、right-input オブジェクトと結合しようとしますが、right-input メモリーへアサートまたは伝播されるオブジェクトはこれ以上ないため、left-input には記録されません。

注記

タプルをスケジュールする優先度キューを持つ agenda はなくなりました。代わりに、ルールの数に対する簡単なアレイが存在します。RuleTerminalNode のシーケンス番号はアクティベーションを格納するアレイ内の要素を表します。
コマンドオブジェクトがすべて処理されると、各要素を順番にチェックし、アクティベーションを実行して (存在する場合) アレイを繰り返し処理します。

重要

パフォーマンスを向上するため、アレイの最初と最後に投入されたセルを記憶するようにしてください。各 RuleTerminalNode にシーケンス番号が割り当てられ、ネットワークが構築されます。この番号は、salience 番号とネットワークに追加された順序に基づいています。
オブジェクトを迅速に取り消しできるようにするため、right-input ノードメモリーは通常ハッシュマップになります。この場合、オブジェクトの取り消しがなく、オブジェクト値がインデックス化されないため、リストを使用します。

重要

インデックス化されたオブジェクトの多くは、ハッシュマップによってパフォーマンスが改善されます。しかし、オブジェクトタイプに少数のインスタンスしかない場合、インデックス化の利点はないため、リストが使用されます。
シーケンシャルモードは、ステートレスセッションでのみ使用可能で、デフォルトでは無効になっています。有効にするには、RuleBaseConfiguration.setSequential(true) を呼び出すか、ルールベース設定の drools.sequential プロパティーを true に設定します。

注記

SequentialAgenda.DYNAMIC を用いて setSequentialAgenda を呼び出し、シーケンシャルモードが動的アジェンダへフォールバックするようにします。また、drools.sequential.agenda プロパティーを sequential または dynamic に設定することもできます。

3.3.8. コマンドと CommandExecutor

JBoss Rules はステートフルセッションおよびステートレスセッションを使用します。ステートフルセッションは、徐々に 繰り返し 作業できる標準的な working memory を使用します。ステートレスセッションは、提供されたデータセットを用いて working memory を一度だけ実行します。結果がいくつか返される可能性があり、対話が繰り返し行われないようにするためセッションは最後に破棄されます。ステートレスセッションは、任意の結果を返す関数として rule engine を処理する方法であると考えてください。
CommandExecutor

図3.26 CommandExecutor

ExecutionResults

図3.27 ExecutionResults

CommandFactory はコマンドをステートフルおよびステートレスセッションで実行できるようにします (ステートレスナレッジセッションは破棄される前に fireAllRules() を最後に実行することが唯一の違いとなります)。現在サポートされているコマンドは次の通りです。
FireAllRulesGetGlobal
SetGlobalInsertObject
InsertElementsクエリ
StartProcessBatchExecution
名前の通り、InsertObject は任意の out 識別子を用いて単一オブジェクトを挿入します。InsertElements は繰り返し処理が可能なオブジェクトを確認し、各要素を挿入します。その結果、ステートレスナレッジセッションへオブジェクトを挿入するだけでなく、プロセスを開始したりクエリを実行したりして任意の順番でこれを実行できるようになります。

例3.35 insert コマンド

StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
ExecutionResults bresults =
  ksession.execute( CommandFactory.newInsert( new Cheese( "stilton" ), "stilton_id" ) );
Stilton stilton = bresults.getValue( "stilton_id" );
execute メソッドは常に ExecutionResults インスタンスを返します。これにより、上記の stilton_id などの out 識別子が指定されていると、すべてのコマンドの結果にアクセスできます。

例3.36 InsertElements コマンド

StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
Command cmd = CommandFactory.newInsertElements(
    Arrays.asList(new Object[] {
        new Cheese("stilton"), new Cheese("brie"), new Cheese("cheddar")}
));
                        
ExecutionResults bresults = ksession.execute( cmd );

重要

このメソッドは単一のコマンドのみを許可します。 BatchExecution は命令リストを取る複合コマンドで、これらの命令を順番に繰り返し処理し、実行します。そのため、オブジェクトをいくつか挿入してプロセスを開始し、fireAllRules を呼び出して単一の execute(...) 呼び出しでクエリを実行できるため、大変強力なコマンドになります。
ステートレスナレッジセッションは処理を終えると fireAllRules() メソッドを自動的に実行しますが、FireAllRules コマンドも許可されます。このコマンドを使用すると、最後に自動実行が無効になります。これは手動のオーバーライドです。
コマンドは out 識別子をサポートします。設定されるコマンドは、返される ExecutionResults インスタンスにその結果を追加します。次の例はこの仕組みを表しています。

例3.37 BatchExecution コマンド

StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
List cmds = new ArrayList();        
cmds.add( CommandFactory.newInsertObject( new Cheese( "stilton", 1), "stilton") );
cmds.add( CommandFactory.newStartProcess( "process cheeses" ) );
cmds.add( CommandFactory.newQuery( "cheeses" ) );
ExecutionResults bresults = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
Cheese stilton = ( Cheese ) bresults.getValue( "stilton" );
QueryResults qresults = ( QueryResults ) bresults.getValue( "cheeses" );
この例では、複数のコマンドが実行され、2 つのコマンドが ExecutionResults にデータを投入します。query コマンドはデフォルトではクエリ名と同じ識別子を使用しますが、異なる識別子へマッピングすることも可能です。
カスタマイズされた XStream マーシャラーを JBoss Rules Pipeline と共に使用すると XML スクリプトを提供できるため、サービスに最適です。以下は、BatchExecutionExecutionResults 向けの 2 つの簡単な XML の例になります。

例3.38 簡単な BatchExecution XML

<batch-execution>
   <insert out-identifier='outStilton'>
      <org.drools.Cheese>
         <type>stilton</type>
         <price>25</price>
         <oldPrice>0</oldPrice>
      </org.drools.Cheese>
   </insert>
</batch-execution>

例3.39 簡単な ExecutionResults XML

<execution-results>
   <result identifier='outStilton'>
      <org.drools.Cheese>
         <type>stilton</type>
         <oldPrice>25</oldPrice>        
         <price>30</price>
      </org.drools.Cheese>
   </result>
</execution-results>
パイプラインにより、複数の stage オブジェクトを使用できます。これらを組み合わせると、より簡単にデータをセッション内やセッション外で移動できます。
CommandExecutor インターフェースを実装する stage があります。これを使用して、パイプラインスクリプトをステートフルまたはステートレスセッションにします。次のように設定を行います。

例3.40 CommandExecutor のパイプライン

Action executeResultHandler = PipelineFactory.newExecuteResultHandler();

Action assignResult = PipelineFactory.newAssignObjectAsResult();

assignResult.setReceiver( executeResultHandler );

Transformer outTransformer = 
  PipelineFactory.newXStreamToXmlTransformer( 
    BatchExecutionHelper.newXStreamMarshaller() );
outTransformer.setReceiver( assignResult );

KnowledgeRuntimeCommand cmdExecution = 
    PipelineFactory.newCommandExecutor();
batchExecution.setReceiver( cmdExecution );

Transformer inTransformer = 
  PipelineFactory.newXStreamFromXmlTransformer( 
    BatchExecutionHelper.newXStreamMarshaller() );
inTransformer.setReceiver( batchExecution );

Pipeline pipeline = 
    PipelineFactory.newStatelessKnowledgeSessionPipeline( ksession );
pipeline.setReceiver( inTransformer );
BatchExecutionHelper を使用して、command のカスタムコンバーターと新しい BatchExecutor ステージを持つ、特別に設定された XStream を提供します。
pipeline を使用するには、ResultHandler の実装を提供します。これは、pipelineExecuteResultHandler ステージを実行する時に呼び出されます。
パイプライン ResultHandler

図3.28 パイプライン ResultHandler

例3.41 簡単なパイプライン ResultHandler

public static class ResultHandlerImpl implements ResultHandler {
    Object object;
    
    public void handleResult(Object object) {
       this.object = object;
    }

    public Object getObject() {
        return this.object;
    }
}

例3.42 パイプラインの使用

ResultHandler resultHandler = new ResultHandlerImpl();
pipeline.insert( inXml, resultHandler );
ここで、作成した BatchExecution を使用してオブジェクトを挿入し、クエリを実行します。以下の pipeline の例では XML 表現が使用されます。パラメーターはクエリに追加されています。

例3.43 XML へマーシャリングされた BatchExecution

<batch-execution>
  <insert out-identifier="stilton">
    <org.drools.Cheese>
      <type>stilton</type>
      <price>1</price>
      <oldPrice>0</oldPrice>
    </org.drools.Cheese>
  </insert>
  <query out-identifier='cheeses2' name='cheesesWithParams'>
    <string>stilton</string>
    <string>cheddar</string>
  </query>
</batch-execution>
CommandExecutorExecutionResults を返し、pipeline コードスニペットによって処理されます。
以下と似ている出力が <batch-execution> XML の例で生成されます。

例3.44 XML へマーシャリングされた ExecutionResults

<execution-results>
  <result identifier="stilton">
    <org.drools.Cheese>
      <type>stilton</type>
      <price>2</price>
    </org.drools.Cheese>
  </result>        
  <result identifier='cheeses2'>
    <query-results>
      <identifiers>
        <identifier>cheese</identifier>
      </identifiers>
      <row>
        <org.drools.Cheese>
          <type>cheddar</type>
          <price>2</price>
          <oldPrice>0</oldPrice>
        </org.drools.Cheese>
      </row>
      <row>
        <org.drools.Cheese>
          <type>cheddar</type>
          <price>1</price>
          <oldPrice>0</oldPrice>
        </org.drools.Cheese>
      </row>
    </query-results>
  </result>
</execution-results>
BatchExecutionHelper は事前設定された XStream を提供します。これを使用して一括実行のマーシャリングをサポートします (結果となる XML は上記の通り、メッセージ形式として使用できます)。Command Factory よりサポートされるコマンドのみに事前設定されたコンバーターが存在します。ユーザーオブジェクトに他のコンバーターを追加することもできます (特にサービスが関与する場合、ステートレスまたはステートフルナレッジセッションのスクリプティングに大変便利です)。
現在、検証をサポートする XML スキーマはありません。基本形式はここで説明されていますが、 drools-transformer-xstream モジュールには drools-transformer-xstream と呼ばれる単体テストがあります。ルート要素は <batch-execution> と命名され、任意の数の command 要素を含めることが可能です。

例3.45 ルート XML 要素

<batch-execution>
...
</batch-execution>
これには、コマンドを表現する要素のリストが含まれます。サポートされるコマンドは Command Factory によって提供されるコマンドに限定されます。最も基本的なものが <insert> 要素で、オブジェクトを挿入します。insert 要素の内容はユーザーオブジェクトで、XStream によって決まります。

例3.46 Insert

<batch-execution>
   <insert>
      ...<!-- any user object -->
   </insert>
</batch-execution>
insert 要素は out-identifier と呼ばれる属性を特徴とします。これは、挿入されたオブジェクトが結果ペイロードの一部として返されることを要求します。

例3.47 out 識別子コマンドを用いた挿入

<batch-execution>
   <insert out-identifier='userVar'>
      ...
   </insert>
</batch-execution>
<insert-elements> 要素を使用してオブジェクトのコレクションを挿入することも可能です。このコマンドは out-identifier をサポートしません (org.domain.UserClassXStream によるシリアライズが可能な例示のユーザーオブジェクトです)。

例3.48 Insert Elements コマンド

<batch-execution>
   <insert-elements>
      <org.domain.UserClass>
         ...
      </org.domain.UserClass>
      <org.domain.UserClass>
         ...
      </org.domain.UserClass>
      <org.domain.UserClass>
         ...
      </org.domain.UserClass>
   </insert-elements>
</batch-execution>
名前の通り、<set-global> 要素はセッションのグローバルを設定するために使用されます。

例3.49 Insert Elements コマンド

<batch-execution>
   <set-global identifier='userVar'>
      <org.domain.UserClass>
         ...
      </org.domain.UserClass>
   </set-global>
</batch-execution>
<set-global> は任意の属性である outout-identifier もサポートします。identifier 属性からの名前を使用して、ブール値 out の真値はグローバルを <batch-execution-results> ペイロードに追加します。out-identifierout のように挙動しますが、<batch-execution-results> ペイロードで使用される識別子をオーバーライドできます。

例3.50 Set Global コマンド

<batch-execution>
   <set-global identifier='userVar1' out='true'>
      <org.domain.UserClass>
         ...
      </org.domain.UserClass>
   </set-global>
   <set-global identifier='userVar2' out-identifier='alternativeUserVar2'>
      <org.domain.UserClass>
         ...
      </org.domain.UserClass>
   </set-global>
</batch-execution>
また、out-identifier 属性のみがあり、内容のない <get-global> 要素も存在します (<get-global> の唯一の目的は値を読み出すことであるため、out 属性は必要ありません)。

例3.51 Get Global コマンド

<batch-execution>
      <get-global identifier='userVar1' />
      <get-global identifier='userVar2' out-identifier='alternativeUserVar2'/>
      </batch-execution>
out 属性は、特定のインスタンスを結果ペイロードとして返すためだけに使用できます。実際のクエリの実行には他の方法が必要になります。クエリはパラメーターの有無に関係なくサポートされます。name 属性は呼び出されるクエリの名前で、out-identifier<execution-results> ペイロードのクエリ結果に使用される識別子になります。

例3.52 Query コマンド

<batch-execution>
   <query out-identifier='cheeses' name='cheeses'/>
   <query out-identifier='cheeses2' name='cheesesWithParams'>
      <string>stilton</string>
      <string>cheddar</string>
   </query>
</batch-execution>

注記

<start-process> コマンドは任意のパラメーターも許可します。

例3.53 Start Process コマンド

<batch-execution>
   <startProcess processId='org.drools.actions'>
      <parameter identifier='person'>
         <org.drools.TestVariable>
            <name>John Doe</name>
          </org.drools.TestVariable>
       </parameter>
   </startProcess>
</batch-execution

例3.54 Signal Event コマンド

<signal-event process-instance-id='1' event-type='MyEvent'>
   <string>MyValue</string>
</signal-event>

例3.55 Complete Work Item コマンド

<complete-work-item id='" + workItem.getId() + "' >
   <result identifier='Result'>
      <string>SomeOtherString</string>
   </result>
</complete-work-item>

例3.56 About Work Item コマンド

<abort-work-item id='21' />

注記

コマンドは徐々に追加される予定です。

3.3.9. マーシャリング

MarshalerFactory を使用して stateful knowledge sessions のマーシャリングおよびアンマーシャリングを行います。
MarshalerFactory

図3.29 MarshalerFactory

以下は MarshalerFactory を使用する最も簡単な方法になります。

例3.57 簡単なマーシャラーの例

// ksession is the StatefulKnowledgeSession
// kbase is the KnowledgeBase
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase );
marshaller.marshall( baos, ksession );
baos.close();
参照されたユーザーデータをマーシャリングする場合には柔軟性が必要となります。柔軟性を提供するため、ObjectMarshalingStrategy インターフェースが追加されています。このインターフェースの 2 つの実装が提供され、ユーザーは独自の実装を追加できます。提供されている 2 つの実装は次の通りです。
  • IdentityMarshalingStrategy
  • SerializeMarshalingStrategy
デフォルトは SerializeMarshalingStrategy です (上記の例で使用されています)。これは、ユーザーインスタンス上で Serializable または Externalizable メソッドを呼び出しします。
反対に、IdentityMarshalingStrategy は ID がストリームに書き込まれる間に、各ユーザーオブジェクトに対して整数識別番号を作成し、マップに格納します。アンマーシャリングが行われている間、IdentityMarshalingStrategy マップへアクセスし、インスタンスを読み出します (そのため、IdentityMarshalingStrategy が使用されると、Marshaller インスタンスが生存している間はステートフルになり、識別子を作成し、マーシャリングを行いたい各オブジェクトへの参照を保持します)。IdentityMarshalingStrategy に使用するコードは次の通りです。

例3.58 IdentityMarshallingStrategy

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectMarshallingStrategy oms = MarshallerFactory.newIdentityMarshallingStrategy()
Marshaller marshaller =
  MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[]{ oms } );
marshaller.marshall( baos, ksession );
baos.close();
柔軟性を向上するため、ObjectMarshalingStrategyAcceptor インターフェースも提供されています。各 Object Marshaling Strategy にはこのインターフェースが含まれています。マーシャラーは一連のストラテジーを持ち、ユーザーオブジェクトへ読み書きしようとすると、ストラテジーを繰り返し、ユーザーオブジェクトをマーシャリングする責任を受け入れるかどうか「依頼」します。提供される実装の 1 つは ClassFilterAcceptor と呼ばれます。これは、文字列とワイルドカードを使用してクラス名を照合できるようにします。デフォルトは *.* であるため、上記の例では使用される IdentityMarshalingStrategy にはデフォルトの *.* が含まれます。
各クラスバー 1 をシリアライズするには (ID ルックアップが使用されます)、以下を実行します。

例3.59 アクセプターを用いた IdentityMarshalingStrategy

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectMarshallingStrategyAcceptor identityAcceptor =
  MarshallerFactory.newClassFilterAcceptor( new String[] { "org.domain.pkg1.*" } );
ObjectMarshallingStrategy identityStrategy =
  MarshallerFactory.newIdentityMarshallingStrategy( identityAcceptor );
ObjectMarshallingStrategy sms = MarshallerFactory.newSerializeMarshallingStrategy();
Marshaller marshaller = 
    MarshallerFactory.newMarshaller( kbase, 
                                   new ObjectMarshallingStrategy[]{ identityStrategy, sms } );
marshaller.marshall( baos, ksession );
baos.close();

注記

許可を確認する順序は提供されるアレイの自然な順序になります。