SeamFramework.orgCommunity Documentation

Capitolo 14. Seam e JBoss Rules

14.1. Installazione delle regole
14.2. Utilizzo delle regole da un componente SEAM
14.3. Utilizzo delle regole da una definizione di processo jBPM

Seam facilita le chiamate alle regole di JBoss Rules (Drools) dai componenti Seam o dalle definizioni di processo jBPM.

Il primo passo è creare un'istanza di org.drools.RuleBase disponibile in una variabile del contesto di Seam. Per i test Seam fornisce un componente interno che compila un set statico di regole dal classpath. Si può installare questo componente tramite components.xml:


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

Questo componente compila le regole da un set di file DRL (.drl) o tabelle di decisione (.xls) e mette in cache un'istanza di org.drools.RuleBase nel contesto APPLICATION di Seam. Notare che è abbastanza probabile che in un'applicazione guidata dalle regole occorra installare altre basi di regole.

Se si vuole utilizzare una Drool DSL, devi specificare la definizione DSL:


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

E' disponibile il supporto a Drools RuleFlow ed è possibile aggiungere un .rf o .rfm come parte dei file delle regole:



        <drools:rule-base name="policyPricingRules" rule-files="policyPricingRules.drl, policyPricingRulesFlow.rf"/>
        

Si noti che quando si usa il formato Drools 4.x RuleFlow (.rfm) occorre specificare la proprietà di sistema -Ddrools.ruleflow.port=true all'avvio del server. Questa è una funzionalità sperimentale e si consiglia l'uso del formato Drools5 (.rf) se possibile.

Se si vuole registrare un handler personalizzato per le eccezioni tramite RuleBaseConfiguration, occorre scrivere l'handler, per esempio:

@Scope(ScopeType.APPLICATION)

@Startup
@Name("myConsequenceExceptionHandler")
public class MyConsequenceExceptionHandler implements ConsequenceExceptionHandler, Externalizable {
   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
   }
   public void writeExternal(ObjectOutput out) throws IOException {
   }
   public void handleException(Activation activation,
                               WorkingMemory workingMemory,
                               Exception exception) {
       throw new ConsequenceException( exception,
                                       activation.getRule() );
   }
}

e registrarlo:


<drools:rule-base name="policyPricingRules" dsl-file="policyPricing.dsl" consequence-exception-handler="#{myConsequenceExceptionHandler}">
    <drools:rule-files>
        <value
>policyPricingRules.drl</value>
    </drools:rule-files>
</drools:rule-base
>

Nella maggior parte delle applicazioni guidate dalle regole, le regole devono essere dinamicamente deployabili, e quindi un'applicazione in produzione dovrà usare un Drools RuleAgent per gestire la RuleBase. Il RuleAgent può connettersi al server di regole Drool (BRMS) od eseguire l'hot deploy dei pacchetti di regole dal repository locale. La RuleBase gestita dal RulesAgen è configurabile in components.xml:


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

Il file delle proprietà contiene proprietà specifiche per RulesAgent. Ecco un file di configurazione d'esempio proveniente dalla distribuzione 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

E' anche possibile configurare le opzioni derettamente sul componente, bypassando il file di configurazione.


<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" />

Successivamente occorre rendere disponibile ad ogni conversazione un'istanza di org.drools.WorkingMemory. (Ogni WorkingMemory accumula fatti relativi alla conversazione corrente.)


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

Notare che è stato dato a policyPricingWorkingMemory un riferimento alla base di regole tramite la proprietà di configurazione ruleBase.

Si può anche aggiungere gli strumenti per essere notificati degli eventi rule engine, inclusi l'avvio delle regole, gli oggetti da asserire, ecc. aggiungendo event listener alla WorkingMemory.


<drools:managed-working-memory name="policyPricingWorkingMemory" auto-create="true" rule-base="#{policyPricingRules}">
        <drools:event-listeners>
            <value
>org.drools.event.DebugWorkingMemoryEventListener</value>
        <value
>org.drools.event.DebugAgendaEventListener</value>
        </drools:event-listeners>
</drools:managed-working-memory
>

Ora è possibile iniettare la WorkingMemory in un qualsiasi componente di Seam, asserire i fatti e lanciare le regole:

@In WorkingMemory policyPricingWorkingMemory;


@In Policy policy;
@In Customer customer;
public void pricePolicy() throws FactException
{
        policyPricingWorkingMemory.insert(policy);
        policyPricingWorkingMemory.insert(customer); 
        // if we have a ruleflow, start the process
        policyPricingWorkingMemory.startProcess(startProcessId)
    policyPricingWorkingMemory.fireAllRules();
}

Si può anche consentire alla base di regole di agire come action handler di jBPM, decision handler, o assignment handler — sia in una definizione di pageflow sia in un processo di business.


<decision name="approval">
         
    <handler class="org.jboss.seam.drools.DroolsDecisionHandler">
        <workingMemoryName
>orderApprovalRulesWorkingMemory</workingMemoryName>
        <!-- if a ruleflow was added -->
        <startProcessId
>approvalruleflowid</startProcessId>
        <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
>

L'elemento <assertObjects> specifica le espressioni EL che restituiscono un oggetto od una collezione di oggetti da asserire come fatti nella WorkingMemory.

L'elemento <retractObjects> specifica le espressioni EL che restituiscono un oggetto od una collezione di oggetti da Rritrarre dalla WorkingMemory.

Esiste anche il supporto per l'uso di Drools per le assegnazioni dei task in jBPM:


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

Alcuni oggetti sono consultabili dalle regole come Drools globals, chiamate Assignable in jBPM, come assignable ed oggetto Decision in Seam, come decision. Le regole che gestiscono le decisioni dovrebbero chiamare decision.setOutcome("result") per determinare il risultato della decisione. Le regole che eseguono assegnazioni dovrebbero impostare l'actor id usando Assignable.

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

Attenzione

Seam viene fornito con dipendenze Drools sufficienti per implementare alcune regole semplici. Per aggiungere ulteriori funzionalità a Drools occorre scaricare la distribuzione completa ed aggiungere le dipendenze necessarie.