Help

I was born in Nis, Serbia and lived in Berlin, Germany for seven years before moving to Atlanta, GA where I received my M.SC. in Computer Science from Georgia State university in 2005.

Currently employed by Red Hat as Engineer on the Drools team.

Location: Atlanta, GA
Occupation: Senior Software Engineer at Red Hat
Archive

Before I dig into the a Fusion example, I wanted to show current integration with Drools5 Templates. Rule templates are helpful when you have a number of rules which follow some sort of pattern(s). In addition you can use templates when you have reoccurring hard-coded values in your rule patterns or actions. The Seam numberguess example is not the best example for rule templates however is good enough for a simple example.

If we look at base numberguess.drl DRL, we can see some hard-coded values, for example the guessCount is set to 9, the guess increment value is 1 and we also see hard-coded values for win and loose, all of which we want to externalize from our rule resource. This is what our new rule template can look like. If we look at rule Lose we can see some relevant changes:

rule Lose
   when 
      Game(guessCount == @{guesscount} )
   then
      if ( decision.getOutcome()==null )
      {
         decision.setOutcome("@{losetext}");
      }
end

Please follow the Drools documentation on further explanation on the template syntax.

In order to expand our template, we must provide a data source. With Seam this expansion is driven by custom Seam components which implements the TemplateDataProvider interface that defines a single method:

   public Collection<Map<String,Object>> getTemplateData();

For this simple example we implement a template data provider with hard-coded values:

@Name("numberGuessTemplateDataProvider")
public class NumberGuessTemplateDataProvider implements TemplateDataProvider
{
   Collection<Map<String, Object>> templateData = new ArrayList<Map<String,Object>>();
   
   @Create
   public void init()
   {
      //  We use a Map which provides the values for substituting template parameters.
      // It should have a (String) key set matching all of the parameter names. 
      // Values can be from any class, as long as they provide a good toString() method
      Map<String, Object> m1 = new HashMap<String, Object>();
      m1.put("wintext", "win");  // substitutes the @{wintext} template parameter
      m1.put("losetext", "lose"); // substitutes the @{losetext} template parameter
      m1.put("guesscount", 9); // substitutes the @{guesscount} template parameter
      m1.put("increment", 1); // substitutes the @{increment} template parameter
      
      templateData.add(m1);
   }
   
   // getters and setters
}

Now all that is left is configuration in components.xml. First we define our KnowledgeBase:

<drools:knowledge-base name="kbase" knowledge-builder-config="kbuilderconfig.properties" knowledge-base-config="kbaseconfig.properties">
    	<drools:rule-resources>
    		<value>classpath;numberguesstemplate.drl;DRL;numberGuessTemplateDataProvider</value>
    	</drools:rule-resources>	
    	<drools:event-listeners>
    		<value>org.drools.event.knowledgebase.DefaultKnowledgeBaseEventListener</value>
    	</drools:event-listeners>
</drools:knowledge-base>

Note here that we have only added the name of our template data provider to the rule-resource string...that's it. Last thing to do is to define our StatefulKnowledgeSession as shown in the previous post.

The Seam Drools5 Branch contains additions to Seam for interactions with the Drools5 API. Here I will show how the existing numberguess example was changed to use Drools5:

1) components.xml

We first define the org.drools.KnowledgeBase and add a single rule resource of type DRL (.drl). This new style of adding resources allows us to add any type of rule resources to the KnowledgeBase (which was not previously possible) and also follows the Drools5 API style (kbuilder.add(ResourceFactory.newClassPathResource("numberguess.drl"), ResourceType.DRL);)

<drools:knowledge-base name="kbase" knowledge-builder-config="kbuilderconfig.properties" knowledge-base-config="kbaseconfig.properties">
    	<drools:rule-resources>
    		<value>classpath;numberguess.drl;DRL</value>
    	</drools:rule-resources>	
    	<drools:event-listeners>
    		<value>org.drools.event.knowledgebase.DefaultKnowledgeBaseEventListener</value>
    	</drools:event-listeners>

 </drools:knowledge-base>

We then create the org.drools.runtime.StatefulKnowledgeSession passing in the reference to our kbase:

<drools:stateful-knowledge-session name="ksession" knowledge-base="#{kbase}" knowledge-session-config="ksessionconfig.properties"
    audit-log="/home/tsurdilo/Desktop/ksession">
    	<drools:event-listeners>
    		<value>org.drools.event.rule.DebugAgendaEventListener</value>
    		<value>org.drools.event.rule.DebugWorkingMemoryEventListener</value>
    	</drools:event-listeners>
 </drools:stateful-knowledge-session>

The pageflow definition stays the same:

<bpm:jbpm>
        <bpm:pageflow-definitions>
            <value>pageflow.jpdl.xml</value>
        </bpm:pageflow-definitions>
  </bpm:jbpm>

2) pageflow.jpdl.xml

We have to change the handler here to a handler which knows how to work with org.drools.runtime.StatefulKnowledgeSession:

<handler class="org.jboss.seam.drools.KnowledgeDecisionHandler">

And that's it, the numberguess example works as before. It is important to mention one more change made:

the Drools5 API no longer exposes the setGlobalResolver method on org.drools.runtime.StatefulKnowledgeSession and org.drools.runtime.StatelessKnowledgeSession. This is mainly so that other APIs would not abuse this. Instead we now have to add a delegate, for example:

ksession = knowledgeBase.getValue().newStatefulKnowledgeSession(ksessionconfig, null);
ksession.getGlobals().setDelegate(new SeamDelegate());

Next I will show an example using Drools Fusion

Showing 6 to 7 of 7 blog entries