<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">

<chapter id="drools">
    <title>Seam and JBoss Rules</title>
    
    <para>
        Seam makes it easy to call JBoss Rules (Drools) rulebases from Seam
        components or jBPM process definitions.
    </para>
    
    <section>
        <title>Installing rules</title>
        
        <para>
            The first step is to make an instance of <literal>org.drools.RuleBase</literal>
            available in a Seam context variable. For testing purposes, Seam provides a built-in component
            that compiles a static set of rules from the classpath. You can install
            this component via <literal>components.xml</literal>:
        </para>

        <programlisting role="XML"><![CDATA[<drools:rule-base name="policyPricingRules">
    <drools:rule-files>
        <value>policyPricingRules.drl</value>
    </drools:rule-files>
</drools:rule-base>]]></programlisting>

         <para>
             This component compiles rules from a set of <literal>.drl</literal>
             files and caches an instance of <literal>org.drools.RuleBase</literal>
             in the Seam <literal>APPLICATION</literal> context. Note that it is 
             quite likely that you will need to install multiple rule bases in a 
             rule-driven application.
         </para>
         
         <para>
             If you want to use a Drools DSL, you alse need to specify the DSL
             definition:
         </para>
         
        <programlisting role="XML"><![CDATA[<drools:rule-base name="policyPricingRules" dsl-file="policyPricing.dsl">
    <drools:rule-files>
        <value>policyPricingRules.drl</value>
    </drools:rule-files>
</drools:rule-base>]]></programlisting>

        <para>
        In most rules-driven applications,
            rules need to be dynamically deployable, so a production application will want to use a
            Drools RuleAgent to manage the RuleBase.  The RuleAgent can connect to a Drools rule server (BRMS) 
            or hot deploy rules packages from a local file repository.  The RulesAgent-managed RuleBase is
            also configurable in <literal>components.xml</literal>:
        </para>
        
                <programlisting role="XML"><![CDATA[<drools:rule-agent name="insuranceRules" 
                    configurationFile="/WEB-INF/deployedrules.properties" />]]></programlisting>
        
        <para>The properties file contains properties specific to the RulesAgent. Here is an example configuration file from the
        Drools example distribution.</para>
        
                <programlisting>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</programlisting>
        
        
        <para>It is also possible to configure the options on the component directly, bypassing the configuration file.</para>

       <programlisting role="XML"><![CDATA[<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" />]]></programlisting>
        
         <para>
             Next, we need to make an instance of <literal>org.drools.WorkingMemory</literal>
             available to each conversation. (Each <literal>WorkingMemory</literal>
             accumulates facts relating to the current conversation.)
         </para>
        
         <programlisting role="XML"><![CDATA[<drools:managed-working-memory name="policyPricingWorkingMemory" auto-create="true" rule-base="#{policyPricingRules}"/>]]></programlisting>

         <para>
             Notice that we gave the <literal>policyPricingWorkingMemory</literal> a
             reference back to our rule base via the <literal>ruleBase</literal>
             configuration property.
         </para>
         
     </section>
     
     <section>
         <title>Using rules from a Seam component</title>
         
         <para>
             We can now inject our <literal>WorkingMemory</literal> into any Seam component,
             assert facts, and fire rules:
         </para>
         
         <programlisting role="JAVA"><![CDATA[@In WorkingMemory policyPricingWorkingMemory;

@In Policy policy;
@In Customer customer;

public void pricePolicy() throws FactException
{
    policyPricingWorkingMemory.assertObject(policy);
    policyPricingWorkingMemory.assertObject(customer);
    policyPricingWorkingMemory.fireAllRules();
}]]></programlisting>
     
     </section>
     
     <section>
         <title>Using rules from a jBPM process definition</title>
         
         <para>
             You can even allow a rule base to act as a jBPM action handler, decision
             handler, or assignment handler&#8212;in either a pageflow or business
             process definition.
         </para>
         
         <programlisting role="XML"><![CDATA[<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>]]></programlisting>

         <para>
             The <literal>&lt;assertObjects&gt;</literal> element specifies EL expressions that
             return an object or collection of objects to be asserted as facts into the 
             <literal>WorkingMemory</literal>.
         </para>
         
         <para>
             There is also support for using Drools for jBPM task assignments:
         </para>
         
         <programlisting role="XML"><![CDATA[<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>]]></programlisting>

         <para>
             Certain objects are available to the rules as Drools globals, namely
             the jBPM <literal>Assignable</literal>, as <literal>assignable</literal>
             and a Seam <literal>Decision</literal> object, as <literal>decision</literal>.
             Rules which handle decisions should call <literal>decision.setOutcome("result")</literal>
             to determine the result of the decision. Rules which perform assignments should
             set the actor id using the <literal>Assignable</literal>.
         </para>
         
         <programlisting><![CDATA[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]]></programlisting>

         <programlisting><![CDATA[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]]></programlisting>

     </section>
     
</chapter>
