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.
This example demonstrates how to build Knowledge Bases and Sessions.
Also, audit logging and debug outputs are shown, which is ommitted
from other examples as it's all very similar. A KnowledgeBuilder
is used to turn a DRL source file into Package
objects which
the Knowledge Base can consume. The add method takes a Resource
interface and a Resource Type as parameters. The Resource
can be
used to retrieve a DRL source file from various locations; in this case the
DRL file is being retrieved from the classpath using a
ResourceFactory
, but it could come from a disk file or a URL.
Here, we only add a single DRL source file, but multiple DRL files can be
added. Also, DRL files with different namespaces can be added, where
the Knowledge Builder creates a package for each namespace. Multiple
packages of different namespaces can be added to the same Knowledge Base.
When all the DRL files have been added, we should check the builder for
errors. While the Knowledge Base 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 KnowledgeBuilder
instance. Once you 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: 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 System.err
stream displayed
in the Console window. Adding listeners to a
Session is trivial, as shown below. The KnowledgeRuntimeLogger
provides execution auditing, the result of which can be viewed in a
graphical viewer. The logger is 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: 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 one
of the two integers HELLO
or 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 text "Hello World" and the status HELLO
and then
inserted into the engine, at which point fireAllRules()
is executed. Remember that all the network evaluation is done
during the insert time, so that by the time the program execution reaches the
fireAllRules()
method call the engine already knows which rules
are fully matches and able to fire.
Example 8.4. HelloWorld: 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 as a Java application:
Open the class org.drools.examples.HelloWorldExample in your Eclipse IDE
Right-click the class and select "Run as..." and then "Java application"
If we put a breakpoint on the fireAllRules()
method
and select the ksession
variable, we can see that the
"Hello World" rule is already activated and on the Agenda, confirming
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: System.err in the Console window
==>[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 (after <kw>when</kw>) 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 bindings are created: the variable message
is bound
to the message
attribute and the variable m
is bound to the matched Message
object itself.
The RHS (after <kw>then</kw>) or consequence part of the rule is
written using the MVEL expression language, as declared by
the rule's attribute dialect
. After printing the content of
the bound variable message
to System.out
,
the rule changes the values of the message
and
status
attributes of the Message
object
bound to m
. This is done MVEL's <kw>modify</kw> statement,
which allows you to apply a block of assignments in one statement, with the
engine being automatically notified of the changes at the end of the
block.
Example 8.7. HelloWorld: 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 set a breakpoint into the DRL, on the <kw>modify</kw> call, and inspect the Agenda view again during the execution of the rule's consequence. This time we start the execution via "Debug As" and "Drools application" and not by running a "Java application":
Open the class org.drools.examples.HelloWorld
in your
Eclipse IDE.
Right-click the class and select "Debug as..." and then "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, which specifies the "java" dialect, is similar
to the "Hello World" rule except that it matches Message
objects whose status is Message.GOODBYE
.
Example 8.8. HelloWorld: rule "Good Bye"
rule "Good Bye" dialect "java" when Message( status == Message.GOODBYE, message : message ) then System.out.println( message ); end
Remember the Java code where we used the
KnowledgeRuntimeLoggerFactory
method 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 demostrate the example execution flow. In the view screen shot
below we can see that the object is inserted, which creates an activation
for the "Hello World" rule; the activation is then executed which updates
the Message
object causing the "Good Bye" rule to
activate; finally the "Good Bye" rule also executes. Selecting an event in
the Audit view highlights the origin event in green; therefore the
"Activation created" event is highlighted in green as the origin of the
"Activation executed" event.