Seam and Drools Fusion example

Posted by    |       Seam

Drools Fusion is the module responsible for adding event processing capabilities into the Drools5 platform. It defines a set of goals for support of Complex Event Processing:

  • Support Events, with their propper semantics, as first class citizens.
  • Allow detection, correlation, aggregation and composition of events.
  • Support processing of Streams of events.
  • Support temporal constraints in order to model the temporal relationships between events.
  • Support sliding windows of interesting events.
  • Support a session scoped unified clock.
  • Support the required volumes of events for CEP use cases.
  • Support to (re)active rules.
  • Support adapters for event input into the engine (pipeline).

Seam integration with Drools5 aims to provide full integration with Drools5 Fusion as well as provide Seam-specific convenient ways of interacting with the Fusion module.

In order to show an example of this integration, again, we are going to be dealing with the Numberguess example. This Numberguess example is depicted through a game where users have nine tries to guess a random number between 1 and 100. Each guess triggers a pageflow which in turns calls upon Drools to make a decision (win, lose, or keep guessing) until either the correct number is guessed or nine tries are reached upon which the game ends.

For the Fusion example, we are going to change the game a little. Instead of having nine tries to guess the correct number, the users are going to have one minute to make the right guess. So let's get started:

1. The first change to integrate Fusion in our Numberguess example is in the rules themselves. The GameCount rule is the focal point of the changes and needs to be looked at:

rule GameCount
   when
   	  gameStart : GameStart() from entry-point "Guess Stream" 
	  Guess( time after[1m,*] gameStart.time ) from entry-point "Guess Stream" 
   then
      decision.setOutcome("lose");
      game.setMessage("Game time of 1 minute exceeded.");
end

The rule predicate pattern matches if the following is true:

a) there exists an event of type GameStart from the Guess Stream entry point (An entry point is for Drools a gate from which facts come, you can read much more about this in the docs)

and

b) there exists an event of type Guess where the temporal distance between the time of the event is over one minute of the time of the GameStart event (this basically means if the user makes a guess after 1 minute of the initial game start).

If the pattern is matched we set the game decision to lose and provide an appropriate message to the user on why they have lost the game.

2. Now that we have our rule, we are back in our Seam code and need to put it all together. As always first we need to declare our KnowledgeBase in components.xml:

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

Note the attribute knowledge-base-config which points to kbaseconfig.properties. Drools has two processing modes, namely CLOUD and STREAM. The CLOUD processing mode is the default processing mode and should be familiar to all Drools users. The STEAM processing mode is the mode used when the application needs to process streams of events which is what we need for this example and we tell the engine that we want to use it by defining the property drools.eventProcessingMode in our properties file and setting it to stream.

Once this is done we need to create the StatefulKnowledgeSession:

<drools:stateful-knowledge-session name="ksession" knowledge-base="#{kbase}" knowledge-session-config="ksessionconfig.properties"
    audit-log="/home/tsurdilo/Desktop/ksessionlogs/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>

Note the attribute knowledge-session-config which points to ksessionconfig.properties. Drools Fusion provides two clock implementations out of the box, namely Real Time Clock and Pseudo Clock. Pseudo clock is used for testing and the real time clock internally uses the system clock which we need for our example. We set this in our properties file by setting the property drools.clockType to realtime.

If you are still reading at this point you remember that in our GameCount rule we say that our events come from the Guess Stream entry point. So now we need to define this entry point into which we are going to feed all of our user guess events into:

<drools:working-memory-entry-point name="guessEntryPoint" 
       ksession="#{ksession}" entry-point-name="Guess Stream"/>    

The WorkingMemoryEntryPoint component is something we added for the Fusion integration with Seam and provides a convenient way to get a hold of a Drools entry point.

Last things to do now is to put it all together in our pageflow definition:

<decision name="drools">
      <handler class="org.jboss.seam.drools.KnowledgeDecisionHandler">
         <workingMemoryName>ksession</workingMemoryName>
         <entryPointName>guessEntryPoint</entryPointName>
         <assertObjects>
            <element>#{gameStart}</element>
            <element>#{guess}</element>
         </assertObjects>
      </handler>
....

The new thing here is the ability to pass an entry point to KnowledgeDecisionHandler who knows to inserts events into this entry point. Currently I am working on adding support for multiple entry points to KnowledgeDecisionHandler which is useful when you have multiple event streams feeding events into the rule engine at the same time.

And that's it, with these changes users now have one minute to guess the right number...and it uses Drools Fusion :)


Back to top