Chapter 12. Seam和JBoss规则

Seam简化了在Seam组件或jBPM过程定义中对JBoss Rules(Drools)规则库的调用。

12.1. 安装规则

第一步是使一个 org.drools.RuleBase 的实例在Seam的上下文变量中可用。 基于测试目的,Seam提供了一个内置组件用来编译来自class搜索路径的一组静态规则。你可以通过 components.xml 文件安装此组件:

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

这个组件编译来自一组 .drl 文件中的规则并在Seam的 APPLICATION 上下文 中缓存一个 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>

在大多数规则驱动的应用程序中,规则需要是可被动态部署的,所以一个生产环境应用程序会需要用Drools规则代理来管理规则库。 规则代理可以连接一个Drools规则服务器(BRMS)或者热部署来自本地文件仓库的规则包。规则代理管理的规则库也在 components.xml 中配置:

<drools:rule-agent name="insuranceRules"
                    configurationFile="/WEB-INF/deployedrules.properties" />

属性文件包含有规则代理RulesAgent所特有的属性。这里是一个来自Drools范例发型中的配置文件例子。

newInstance=true
url=http://localhost:8080/drools-jbrms/org.drools.brms.JBRMS/package/org.acme.insurance/fmeyer
localCacheDir=/Users/fernandomeyer/projects/jbossrules/drools-examples/drools-examples-brms/cache
poll=30
name=insuranceconfig

绕过配置文件,直接配置组件的选项也是可行的。

<drools:rule-agent name="insuranceRules"
                   url="http://localhost:8080/drools-jbrms/org.drools.brms.JBRMS/package/org.acme.insurance/fmeyer"
                   local-cache-dir="/Users/fernandomeyer/projects/jbossrules/drools-examples/drools-examples-brms/cache"
                   poll="30"
                   configuration-name="insuranceconfig" />

接下来,我们需要使 org.drools.WorkingMemory 实例对每个对话都可用。 (每个 WorkingMemory 累积与当前对话相关的fact。)

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

请注意,我们通过 ruleBase 配置属性给了 policyPricingWorkingMemory 一个指回规则库的引用。

12.2. 在Seam组件中使用规则

现在可以将我们的 WorkingMemory 注入进任意的Seam组件中了,进行判断并执行规则:

@In WorkingMemory policyPricingWorkingMemory;

@In Policy policy;
@In Customer customer;

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

12.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> 元素指定了用来返回要被作为fact设给 WorkingMemory 的对象或者对象集合的EL表达式。

除此之外,Seam还支持在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 global提供给规则,即jBPM Assignable 对象(assignable)和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