How do I program using Drools?

So, I’ve done it, I’ve convinced you that your application needs Drools. Luckily installing it isn’t too difficult if you already have Eclipse installed. 
 
 I recommend using Eclipse itself to download the Drools plugin. The internet already has as many installation guides as they need so I won’t bother adding another. There is an excellent set of instructions on the Drools website, that I would highly recommend to anyone wanting to install Drools.

So, let’s get into the nitty-gritty. First things first we’re going to look at what every programmer looks at when they want to learn a new concept: “Hello World”.

Generating Hello World for Drools is really easy, so easy in fact Eclipse does it for you. Let me show you how do to it:

Now that we have generated the Hello World example let’s look at how this all fits together. We are going to look at the Rules based approach to Drools, so in order to do that we will open the DroolsTest.java file. We can see a main method, and an internal class representing the Message object. Message contains the following code:

public static class Message
{
public static final int HELLO = 0;
public static final int GOODBYE = 1;
   private String message;
   private int status;
   //Getters and Setters
}

The main method contains the following code:

public static final void main(String[] args)
{
try
{
// load up the knowledge base
   KieServices ks = KieServices.Factory.get();
   KieContainer kContainer = ks.getKieClasspathContainer();
   KieSession kSession = kContainer.newKieSession(“ksession-rules”);
   // go !
   Message message = new Message();
   message.setMessage(“Hello World”);
   message.setStatus(Message.HELLO);
   kSession.insert(message);
   kSession.fireAllRules();
}
catch (Throwable t)
{
t.printStackTrace();
}

Let’s examine what this code does:

  • KieServices is an interface for the rest of the Kie software.
  • KieContainer holds are the resources that will be compiled and deployed during the execution of this system. This allows us to access the contents of the Kie system during runtime.
  • KieSession is where we link to the rule files themselves. If you look at the declaration of the KieSession object, the container is passed an argument, “ksession-rules”. This argument points the system to a specific package to look for Drool files.

The next thing the code does is instantiate a Message object, set the message to “Hello World”, and the status to Hello.

Then we get into the meat of the rule engine. The Message object is “inserted” into the KieSession, which allows the rule engine to evaluate the Message object against the rules in the session. Then the KieSession “fires” the rules. 
 
 Let’s look at what the rule does:

package com.sample
import com.sample.DroolsTest.Message;
rule “Hello World”
   when
      m : Message( status == Message.HELLO, myMessage : message )
   then
      System.out.println( myMessage );
      m.setMessage( “Goodbye cruel world” );
      m.setStatus( Message.GOODBYE );
      update( m );
   end
rule “GoodBye”
   when
      Message( status == Message.GOODBYE, myMessage : message )
   then
      System.out.println( myMessage );
   end

The first lines of code act much like they would in a regular Java program. We have a package declaration, and an import. Nothing new to seasoned Java developers. Then things get hairy. Each of these paragraphs represent a rule in our system. Each rule is started with:

Rule “rule name”

That tells the system that we are creating a rule, and we give it a name that is unique to this package.

We then determine the firing condition. We say “Keep an eye out for the following conditions, and act when you notice it.”

We are going to break down that when condition.

m : Message

This line of code takes the message object being evaluated, and creates a pointer towards it, that we can use for the rest of the rule. Generally best practice is to assign a $ to the front of any pointer we create, so this declaration should read $m : Message.

( status == Message.HELLO

This line of code looks for any Message type object, with the status of “HELLO”. The next portion of that line of code is:

myMessage : message )

We are creating another pointer object here, in particular we are pointing to the String attribute contained in the Message object.

So far, our rule has created two pointers, to the Message, and to the String contained in it. We also have a condition for this rule to fire under, that is any rule with the status “HELLO”. So what happens when this condition is met? The “then” portion of the code is executed:

then
System.out.println( myMessage );
   m.setMessage( “Goodbye cruel world” );
   m.setStatus( Message.GOODBYE );
   update( m );

The then keyword tells the system, “do the following when the above condition is met”.

In our case, the beginning should be fairly clear:

  • We use that pointer that we created earlier to print out the string contained in the Message that was fired.
  • Then using the pointer to the Message object, we change the String to “Goodbye cruel world”.
  • We then change the status to GOODBYE.
  • Then we use the update keyword. This keyword tells the rules engine that the data being evaluated has changed, and therefore should be reevaluated.
     
     Doesn’t seem to terrible, right? Let’s speed through the second one.
rule “GoodBye”
when
      Message( status == Message.GOODBYE, myMessage : message )
   then
      System.out.println( myMessage );
   end

We create a rule named goodbye, that searches for a message with the status “GOODBYE”, and when found:

  • It prints out the String contained within the Message.
  • The rule doesn’t create a pointer object to the Message object, because it doesn’t need to change the values in the Message. It only needs a pointer to the String contained within.

So, what does the output of this code look like?

Well, let’s look back on the main method contained in this application.

Message message = new Message();
message.setMessage(“Hello World”);
message.setStatus(Message.HELLO);
kSession.insert(message);
kSession.fireAllRules();
  • We create a Message object with the String “Hello World”, then we set its status to “HELLO”, and tell the rule engine to evaluate it.
  • If you recall, our first rule looked for a Message object with the status of “HELLO”. So, it will execute, change the String, and status of our message to “GOODBYE” and send it back on its way through the system.
  • The system is also looking out for a Message object with the status “GOODBYE”, so that rule will then fire, printing out the changed String.
  • This means our output should be the initial String(“Hello World”), and then the changed String(“Goodbye cruel world”). What do we get?
Hello World
Goodbye cruel world

Success!