Name: Hello World Main class: org.drools.examples.HelloWorldExample Type: java application Rules file: HelloWorld.drl Objective: demonstrate basic rules in use
The "Hello World" example shows a simple example of rules usage, and both the MVEL and Java dialects.
In this example it will be shown how to build knowledgebases and sessions and how to add audit logging and debug outputs, this information is ommitted from other examples as it's all very similar. KnowledgeBuilder is used to turn a drl source file into Package objects which the KnowledgeBase can consume, add takes a Resource interface and ResourceType as parameters. Resource can be used to retrieve a source drl file from various locations, in this case the drl file is being retrieved from the classpath using ResourceFactory; but it could come from the disk or a url. In this case we only add a single drl source file, but multiple drl files can be added. Drl files with different namespaces can be added, KnowledgeBuilder creates a package for each namespace. Multiple packages of different namespaces can be added to the same KnowledgeBase. When all the drl files have been added we should check the builder for errors; while the KnowledgeBase will validate the package it will only have access to the error information as a String, so if you wish to debug the error information you should do it on the builder instance. Once we know the builder is error free get the Package collection, instantiate a KnowledgeBase from the KnowledgeBaseFactory and add the package collection.
Example 8.1. HelloWorld example: Creating the KnowledgeBase and Session
final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); // this will parse and compile in one step kbuilder.add(ResourceFactory.newClassPathResource("HelloWorld.drl", HelloWorldExample.class), ResourceType.DRL); // Check the builder for errors if (kbuilder.hasErrors()) { System.out.println(kbuilder.getErrors().toString()); throw new RuntimeException("Unable to compile \"HelloWorld.drl\"."); } // get the compiled packages (which are serializable) final Collection<KnowledgePackage> pkgs = kbuilder.getKnowledgePackages(); // add the packages to a knowledgebase (deploy the knowledge packages). final KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(pkgs); final StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
Drools has an event model that exposes much of what's happening internally, two default debug listeners are supplied DebugAgendaEventListener and DebugWorkingMemoryEventListener which print out debug event information to the err console, adding listeners to a session is trivial and shown below. The KnowledgeRuntimeLogger provides execution auditing which can be viewed in a graphical viewer; it's actually a specialised implementation built on the agenda and working memory listeners, when the engine has finished executing logger.close() must be called.
Most of the examples use the Audit logging features of Drools to record execution flow for later inspection.
Example 8.2. HelloWorld example: Event logging and Auditing
// setup the debug listeners ksession.addEventListener( new DebugAgendaEventListener() ); ksession.addEventListener( new DebugWorkingMemoryEventListener() ); // setup the audit logging KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "log/helloworld");
The single class used in this example is very simple, it has two fields: the message, which is a String and the status which can be either the int HELLO or the int GOODBYE.
Example 8.3. HelloWorld example: Message Class
public static class Message { public static final int HELLO = 0; public static final int GOODBYE = 1; private String message; private int status; ... }
A single Message object is created with the message "Hello World" and status HELLO and then inserted into the engine, at which point fireAllRules() is executed. Remember all the network evaluation is done during the insert time, by the time the program execution reaches the fireAllRules() method it already knows which rules are fully matches and able to fire.
Example 8.4. HelloWorld example: Execution
final Message message = new Message(); message.setMessage("Hello World"); message.setStatus(Message.HELLO); ksession.insert(message); ksession.fireAllRules(); logger.close(); ksession.dispose();
To execute the example from Java.
Open the class org.drools.examples.HelloWorldExample in your Eclipse IDE
Right-click the class an select "Run as..." -> "Java application"
If we put a breakpoint on the fireAllRules() method and select the ksession variable we can see that the "Hello World" view is already activated and on the Agenda, showing that all the pattern matching work was already done during the insert.
The may application print outs go to to System.out while the debug listener print outs go to System.err.
Example 8.6. HelloWorld example: Console.err
==>[ActivationCreated(0): rule=Hello World; tuple=[fid:1:1:org.drools.examples.HelloWorldExample$Message@17cec96]] [ObjectInserted: handle=[fid:1:1:org.drools.examples.HelloWorldExample$Message@17cec96]; object=org.drools.examples.HelloWorldExample$Message@17cec96] [BeforeActivationFired: rule=Hello World; tuple=[fid:1:1:org.drools.examples.HelloWorldExample$Message@17cec96]] ==>[ActivationCreated(4): rule=Good Bye; tuple=[fid:1:2:org.drools.examples.HelloWorldExample$Message@17cec96]] [ObjectUpdated: handle=[fid:1:2:org.drools.examples.HelloWorldExample$Message@17cec96]; old_object=org.drools.examples.HelloWorldExample$Message@17cec96; new_object=org.drools.examples.HelloWorldExample$Message@17cec96] [AfterActivationFired(0): rule=Hello World] [BeforeActivationFired: rule=Good Bye; tuple=[fid:1:2:org.drools.examples.HelloWorldExample$Message@17cec96]] [AfterActivationFired(4): rule=Good Bye]
The LHS (when) section of the rule states that it will be activated for each Message object inserted into the working memory whose status is Message.HELLO. Besides that, two variable binds are created: "message" variable is bound to the message attribute and "m" variable is bound to the object matched pattern itself.
The RHS (consequence, then) section of the rule is written using the MVEL expression language, as declared by the rule's attribute dialect. After printing the content of the message bound variable to the default console, the rule changes the values of the message and status attributes of the m bound variable; using MVEL's 'modify' keyword which allows you to apply a block of setters in one statement, with the engine being automatically notified of the changes at the end of the block.
Example 8.7. HelloWorld example: rule "Hello World"
rule "Hello World" dialect "mvel" when m : Message( status == Message.HELLO, message : message ) then System.out.println( message ); modify ( m ) { message = "Goodbyte cruel world", status = Message.GOODBYE }; end
We can add a break point into the DRL for when modify is called during the execution of the "Hello World" consequence and inspect the Agenda view again. Notice this time we "Debug As" a "Drools application" and not a "Java application".
Open the class org.drools.examples.FibonacciExample in your Eclipse IDE
Right-click the class an select "Debug as..." -> "Drools application"
Now we can see that the other rule "Good Bye" which uses the java dialect is activated and placed on the agenda.
The "Good Bye" rule is similar to the "Hello World" rule but matches Message objects whose status is Message.GOODBYE instead, printing its message to the default console, it specifies the "java" dialect.
Example 8.8. HelloWorld example: rule "Good Bye"
rule "Good Bye" dialect "java" when Message( status == Message.GOODBYE, message : message ) then System.out.println( message ); end
If you remember at the start of this example in the java code we used KnowledgeRuntimeLoggerFactory.newFileLogger to create a KnowledgeRuntimeLogger and called logger.close() at the end, this created an audit log file that can be shown in the Audit view. We use the audit view in many of the examples to try and understand the example execution flow. In the view below we can see the object is inserted which creates an activation for the "Hello World" rule, the activation is then executed which updated the Message object causing the "Good Bye" rule to activate, the "Good Bye" rule then also executes. When an event in the Audit view is select it highlights the origin event in green, so below the Activation created event is highlighted in greed as the origin of the Activation executed event.