第11章 Seam と JBoss Rules

Seam では、Seam コンポーネントあるいは、 jBPM プロセス定義から JBoss ルール (Drools) を容易に呼び出せます。

11.1. ルールの初期化

最初のステップは、Seam コンテキスト変数で org.drools.RuleBase インスタンスを有効化することです。 多くのルール駆動型アプリケーションでは、 ルールは、動的にデプロイ可能である必要があります。 従って、ルールのデプロイと Seam での有効化を可能とするソリューションを実装する必要があるでしょう。 (将来版の Drools は、この問題を解決するルールサーバを提供するでしょう。) テスト目的で、Seam はクラスパスから静的なルール一式をコンパイルする、組み込みコンポーネントを提供しています。 このコンポーネントは、components.xml によりインストール可能です。

<drools:rule-base name="policyPricingRules">
    <drools:rule-files>
        <value>policyPricingRules</value>
    </drools:rule-files>
</drools:rule-base>

このコンポーネントは、.drl ファイル一式からルールをコンパイルし、 Seam アプリケーションコンテキスト中に org.drools.RuleBase をキャッシュします。 複数のルールベースをルール駆動型アプリケーションにインストールする必要もあり得ることに留意してください。

Drools DSLを利用するのであれば、DSL定義を指定しなければなりません:

<drools:rule-base name="policyPricingRules" dsl-file="policyPricing.dsl">
    <drools:rule-files>
        <value>policyPricingRules</value>
    </drools:rule-files>
</drools:rule-base>

次に、各対話に対して org.drools.WorkingMemory インスタンスを有効化する必要があります。 (各 WorkingMemory は、現在の対話に関連する fact を蓄積します。)

<drools:managed-working-memory name="policyPricingWorkingMemory" auto-create="true" rule-base="#{policyPricingRules}"/>

policyPricingWorkingMemory に、 ruleBase 設定プロパティにより、 ルールベースへの参照を与えていることに留意してください。

11.2. Seam コンポーネントからのルールの使用

WorkingMemory を、 任意の Seam コンポーネントにインジェクトし、 fact をアサートし、そしてルールを実行することができます。

@In WorkingMemory policyPricingWorkingMemory;

@In Policy policy;
@In Customer customer;

public void pricePolicy() throws FactException
{
    policyPricingWorkingMemory.assertObject(policy);
    policyPricingWorkingMemory.assertObject(customer);
    policyPricingWorkingMemory.fireAllRules();
}

11.3. jBPM プロセス定義からルール使用

ルールベースが jBPM アクションハンドラとして、あるいはデシジョンハンドラ、割り当てハンドラなどとして動作するようにさせることも可能です — ページフローまたはビジネスプロセス定義のどちらでも可。

<decision name="approval">
         
    <handler class="org.jboss.seam.drools.DroolsDecisionHandler">
        <workingMemoryName>orderApprovalRulesWorkingMemory</workingMemoryName>
        <assertObjects>
            <element>#{customer}</element>
            <element>#{order}</element>
            <element>#{order.lineItems}</element>
        </assertObjects>
    </handler>
    
    <transition name="approved" to="ship">
        <action class="org.jboss.seam.drools.DroolsActionHandler">
            <workingMemoryName>shippingRulesWorkingMemory</workingMemoryName>
            <assertObjects>
                <element>#{customer}</element>
                <element>#{order}</element>
                <element>#{order.lineItems}</element>
            </assertObjects>
        </action>
    </transition>
    
    <transition name="rejected" to="cancelled"/>
    
</decision>

<assertObjects> 要素は、 WorkingMemory 中に、fact としてアサーションされるオブジェクト、 または、オブジェクトのコレクションを返す EL 式を指定します。

jBPM タスク割り当てのために Drools の使用もサポートしています。

<task-node name="review">
    <task name="review" description="Review Order">
        <assignment handler="org.jboss.seam.drools.DroolsAssignmentHandler">
            <workingMemoryName>orderApprovalRulesWorkingMemory</workingMemoryName>
            <assertObjects>
                <element>#{actor}</element>
                <element>#{customer}</element>
                <element>#{order}</element>
                <element>#{order.lineItems}</element>
            </assertObjects>
        </assignment>
    </task>
    <transition name="rejected" to="cancelled"/>
    <transition name="approved" to="approved"/>
</task-node>

あるオブジェクトは、ルールでは Drools グローバルとして扱われます。 すなわち、 jBPM Assignableassignable として 、 そしてSeam Decision オブジェクトは decision として扱われます。 デシジョンを扱うルールは、デシジョンの結果を決定するために、 decision.setOutcome("result") を呼ぶ必要があります。 割り当てを実行するルールは、 Assignable を使ってアクターIDを設定する必要があります。

package org.jboss.seam.examples.shop

import org.jboss.seam.drools.Decision

global Decision decision

rule "Approve Order For Loyal Customer"
  when
    Customer( loyaltyStatus == "GOLD" )
    Order( totalAmount <= 10000 )
  then
    decision.setOutcome("approved");
end
package org.jboss.seam.examples.shop

import org.jbpm.taskmgmt.exe.Assignable

global Assignable assignable

rule "Assign Review For Small Order"
  when
    Order( totalAmount <= 100 )
  then
    assignable.setPooledActors( new String[] {"reviewers"} );
end