Lesson 1 : Core concepts

What is a rule in drools?

In the previously created project, we are going to add a new drl file (drl = drools rule language) to do so, select src/test/rules and first create a package called lesson1 and the a rule file called "lesson1".
and the select rule Drools/Rule Resource
Enter a rule name and package and press the Finish button.
the following element is then displayed: lesson1.drl
Let's analyze the rule elements:
  1. 1.
    For every Java object, we are going to use, we need to import classes
  2. 2.
    It is possible to define global variables
  3. 3.
    Unique rule name
  4. 4.
    Rule conditions sometimes called LHS=Left Hand Side as it is on the left side of the RETE algorithm which is included in drools
  5. 5.
    Rule action is triggered when the rule conditions are met. It's possible to use pure Java code, this is even known as Right Hand Side (RHS).

Adding a simple condition to a rule

As any plugin in eclipse, the drools plugin allows auto-completion (ctrl+space)
We create a rule the has a condition just a fact of type Account. If the rule is fired, then we shall show the message "The account exists" in the console. Notice that the then part is just pure java.
Create a Junit test called "testLesson1"
And then modify the test case to obtain this
and in src/main/resources/META-INF modify kmodule.xml
Here we defined a session called "ksession-rules" (that we use in the test to initialize the session) and where to find the rule files here in package "lesson1". Now you can run the test in TestLesson1 and you should see this:
It is the message that we have put in the rule "Your first rule"
Let us add some logging to facilitate the output

Using a Global variable to log information

In the code we just did, we wrote the code System.out.println("blabla"). This is fine but let us imagine you want to log somewhere else, it is not possible. One good practice is to use global variables for that purpose. We first define a java class called OutputDisplay that we shall create in the util package in src/main/java
Now we shall update the lesson1.drl file
The keyword global is used and then a normal java declaration. Here the global is of type OutputDisplay and the variable is called showResults. This variable can now be used in the "them" part of the rule as here. To initialize the global variable, we shall use the method "setGlobal" on the session we create as shown here in our test :
When running the Junit test, the console should look like this :

Using callback to log activity in drools runtime

Up to known, we only defined one rule. It runs or not and if yes we added a method that shows us something to see if the rule was executed. When working on bigger projects, adding logging code to each rule is not a good practice. This will complexify the writing of rules and furthermore, we are pushing drools to be a business tool for a business analyst and they have to write technical code. Drools offer a pattern to implement that functionality that is called session callbacks.
Drools can be viewed in a synthetic picture like this :
The production memory contains all the rule definitions (in our case the drl for the moment). The working memory which created with the session and we can add facts to it with the method insert. The agenda contains all the rules that can be fired. The Pattern Matcher is the algorithm that is used to match the rules on the facts given. In Drools latest version, there are many different algorithms that is used (The main one is the rete algorithm).
On each of those parts, it is possible to add a callback when we create a Session.
Each time a fact is inserted, updated, or retracted we shall log the event and show it on the console. Here we are using the toString method of the java instance given (event.getObject().toString()).
We shall add a toString method to all our POJO classes Account, AccountingPeriod, and CashFlow. To do so we shall let eclipse generate it for us by right-clicking in the source code
Then you should add the following unit test to the TestLesson1 java class
And in the console you should see this :
The first line is generated by the first test. To be able to see the difference when a new test is started, we can add the following code to our JUnit test case :
and now the console should look like this :
The first test is passed and we see the output generated when the rule is fired. The second test first inserts an object, then updates it the retract it. To update an object, you first have to memorize the fact handle :
FactHandle handlea = sessionStatefull.insert(a);
and then you have to use that fact handle to tell drools the object was updated :
a.setBalance(12.0);
sessionStatefull.update(handlea, a);
and the same applies when you want to retract (now called delete in drools 6) :
sessionStatefull.delete(handlea);
as we call the "fireAllRules()" method after we retract the only fact that was in the working memory, the rule "Your First Rule revisited" is not fired.

When and how is a rule fired?

Let us take an example :
We insert an Account, call FireAllRules, and then call a second-time fireAllRules on the same session. What shall happen? How many times the rule "Your First Rule revisited" shall be fired?
Here is the result :
The rule is fired only once. Maybe it is because we did not modify the Account object? Let us do another example that modifies the account object we pass to the session.
Here is the result :
The rule is still not fired a second time. Just modifying the object does not do the job.
Let us modify the example like this by telling the rule engine we modified the fact :
Before calling the second fireAllRules, we tell drools that the fact we inserted before was updated. In our case, we did not modify its data. Here is the result :
The rule was executed a second time.
Here is what is happening when the FireAllRules method is called on a stateful session :
  • drools will look at all rules that can apply and put it in its agenda.
  • drools will execute the rule that is on top of its agenda
  • Once fired, the rule will be deactivated
  • We have to tell drools of a state change in one of the facts in the when part (lhs) to make him reconsider the rule.
  • A state change can be an insert, update, or delete (retract).
In the last example, we tell drools that a fact has been updated
sessionStatefull.update(handle, a);
So, therefore, considering the previously inserted fact has been updated, drools reconsider the rule. As in the rule "Your First Rule revisited" there is no condition on the attributes, the rule is then fired.
But we can also do that in the then (RHS) part of a rule: insert, update, retract.
Here is the test case :
Here are the concerned rules.
in the first rule, in the then part we create a new instance of time AccountingPeriod and we use the keyword insert to tell drools to create a new fact. As a consequence, the second rule will be executed as the only condition is there is an AccountingPeriod in the working memory.
We see in the logs
  • two first lines : an object of type CashFlow was inserted. We did that from the Junit test with the code FactHandle handlea = sessionStatefull.insert(a);
  • the third line is generated in the then part of the rule "Your First Rule revisited AccountingPeriod".
  • The fourth and fifth line: an object of type AccountingPeriod was inserted. This was done in the then part of the rule "Your First Rule revisited AccountingPeriod"
AccountingPeriod newPeriod = new AccountingPeriod();
insert (newPeriod);
  • the last line is coming from the then part of the rule "Rule on AccountingPeriod that are inserting". Meaning the inserted object AccountingPeriod we inserted in the previous rule triggered the second rule.

Summary

This ends the first lesson where we learned the core concepts needed when working with drools : 1. What is a rule 2. A rule with a simple condition 3. How to log what is happening in the rule engine 4. What triggers a rule execution and how to interact with the rule engine for fact handling.