Jboss Drools Facthandle Example
Hello Readers, in this article we will take a look on what is the FactHandle and how this works inside a drools engine implementing a example of this to ilustrate this feautre. Before starting, check the requirements related to technologies and frameworks used to this example below:
- Maven 3.3.9
- Jboss Studio 10.3
- Drools Engine 7.0
- JDK 1.8.0_71
1. Introduction
Before continuing with the FactHandle Example implementation, we need to understand how this works and which is the use of this feature inside a drools rule program. General speaking the fact handle inside the drools engine is an identification or ID that represents the inserted object (fact) within WorkingMemory
. Below we’ll see how this feature works on the different drools operations:
- Insertion
- Retraction
- Update
2. Setting Up The Environment
To have the deveploment environment setting up, please refer to my previous drools post (backward chaining) on the section 2 “Configure Necessary Tools” and uses the name drools-facthandle
for the new maven drools project used on this example.
3. FactHandle Example Implementation
Well, now in this section, we’ll start to implement our first agendaEventListener on a drools rule project. Below we see the steps that we’ll follow to achieve this.
- Model creation class to wrap the data that will be evaluated by the rule.
- Rule file with some example rule, in order to add a new agendaEventListener.
- Add rule configuration to the
kmodule.xml
file, in order to get our rule on a drools session. - Test class creation, to put all together and see how the FactHandle works.
3.1 Model Class Creation
The model class is a representation of the data that will be evaluated by the rule. On this example we will use a class called Person. To create it please follow the next steps. Go to the drools-agenda-facthandle
(created on the step 2) maven project on the jboss developer studio and create a new package named com.sample.model
. Inside this package create a new class named Person with the below structure:
Person.java
package com.sample.model; /** * POJO class to wrap the example data * that will be evaluated by the rule * */ public class Person { private int id; private String name; public Person(int id, String name) { super(); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3.2 Rule File Creation
The rule file will have our test rule that allows validate the data model when this is invoked and will allow to trigger our event listener. On the drools-facthandle
maven project, inside the src/main/resources create a new folder named facthandle.
Below this folder create a new Rule file named FactHandle
with the below structure:
FactHandle.drl
package com.sample import com.sample.model.Person /** When this rule matched, will be fired and a FactHandle object will be returned */ rule "facthandletest" when Person( id == 12467, name == "carlos" ) then System.out.println( "Fact handle Example" ); end
3.3 Add Rule Configuration
In order to get our rule program working and see how the fact handle works, it’s necessary to configure the drools session on the file kmodule.xml
file inside src/main/resources/META-INF folder. See below the configuration for this example:
kmodule.xml
<?xml version="1.0" encoding="UTF-8"?> <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"> <kbase name="facthandle" packages="facthandle"> <ksession name="ksession-facthandle"/> </kbase> </kmodule>
3.4 Test Class Creation
Now, we are ready to add our new FactHandle Test class in order to see how fact handle works on drools operations: insertion, retraction and update. On the drools-facthandle
maven project, under the package com.sample
create a new class named FactHandleTest
with the below structure:
FactHandleTest.java
package com.sample; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; public class FactHandleTest { public static void main(String[] args) { try { KieServices ks = KieServices.Factory.get(); KieContainer kContainer = ks.getKieClasspathContainer(); //drools session base on the xml configuration kmodule.xml KieSession kSession = kContainer.newKieSession("ksession-facthandle"); } catch (Throwable t) { t.printStackTrace(); } } }
3.5 Fact Insertion
The fact in the drools project concept context, is each object that is inserted on a drools engine using a drools session, this is when you do kSession.insert(myObject);
, when you insert a object (fact), it is examined for matches against the rules. In that moment the engine decides about firing or not a rule during fact insertion. but you have other option to made this, calling kSession.fireAllRules();
method on the drools engine session in order to execute all the rules.
A common misunderstood on fact insertion is thinks that the evaluation of the facts inside the engine occurs when the fireAllRules method is executed, actually this happens when is inserted into the engine, on drools context the evaluation is called Assertion too, lets take a look on how to get a FactHandle on insertion operation also called Assertion and how the evaluation occurs.
FactHandleTest.java
package com.sample; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; public class FactHandleTest { public static void main(String[] args) { try { KieServices ks = KieServices.Factory.get(); KieContainer kContainer = ks.getKieClasspathContainer(); //drools session base on the xml configuration kmodule.xml KieSession kSession = kContainer.newKieSession("ksession-facthandle"); //fact creation (model pojo class) Person person = new Person(12467, "carlos"); //we obtain the fact handle and at this moment the evaluation against the rule happens FactHandle factHandle = kSession.insert(person); //here we print the fact representation of this object inside the rules engine System.out.println(factHandle.toExternalForm()); //here the rule is fired kSession.fireAllRules(); } catch (Throwable t) { t.printStackTrace(); } } }
The output of this program is:
0:1:1760401098:1760401098:1:DEFAULT:NON_TRAIT:com.sample.model.Person //The string representation of the ID or FactHandle inside the engine Fact handle Example //This is printing when the rule match
The FactHandle is also used for interactions with the current working memory data inside the rules engine in cases that is necessary retract or update a object(fact), in the previous output, you see the ID or FactHandle of the inserted object inside the rules engine and the example text that is printed when the rule’s condition match with the object.
3.6 Fact Retraction
The next operation that use the fact handle is retraction, the retraction is the way that drools engine allows to remove a object(fact) on the working memory , this means that this fact will not longer track and match, so any rules that are active and depends of the removed fact (object) will be cancelled. Retraction is done using the FactHandle object obtained from the insertion operation. See the code example below.
FactHandleTest.java
package com.sample; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; public class FactHandleTest { public static void main(String[] args) { try { KieServices ks = KieServices.Factory.get(); KieContainer kContainer = ks.getKieClasspathContainer(); //drools session base on the xml configuration kmodule.xml KieSession kSession = kContainer.newKieSession("ksession-facthandle"); //fact creation (model pojo class) Person person = new Person(12467, "carlos"); //we obtain the fact handle and at this moment the evaluation against the rule happens FactHandle personFactHandle = kSession.insert(person); //here we remove the fact from the current working memory kSession.retract(personFactHandle); //the representation still there but the rules associated to this fact will be cancelled System.out.println(personFactHandle.toExternalForm()); /*here the rule for this example "facthandletest" never execute the print statement, because the fact was already removed from current working memory so is cancelled*/ kSession.fireAllRules(); } catch (Throwable t) { t.printStackTrace(); } } }
The output of this program is:
0:1:1760401098:1760401098:1:DEFAULT:NON_TRAIT:com.sample.model.Person //The string representation of the ID or FactHandle inside the engine
The previous output shows just the ID or fact handle of the removed fact but never prints the rule message because the rule is cancelled after the retraction operation.
3.7 Fact Update
The next operation that use the fact handle is update, the update is the way that drools engine allows to be notified when a object(fact) is modified on the working memory, so that fact can be reprocessed by the engine again, internally the engine remove the fact from the current working memory and inserts again with the new values. The drools engine update method receive, the FactHandle of the object that will be updated and the instance of the object that will be modified. See the code example below.
FactHandleTest.java
package com.sample; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; public class FactHandleTest { public static void main(String[] args) { try { KieServices ks = KieServices.Factory.get(); KieContainer kContainer = ks.getKieClasspathContainer(); //drools session base on the xml configuration kmodule.xml KieSession kSession = kContainer.newKieSession("ksession-facthandle"); //fact creation (model pojo class), that will not match with the current rule Person person = new Person(1, "carlos"); //we obtain the fact handle and at this moment the evaluation against the rule happens FactHandle personFactHandle = kSession.insert(person); //here the rule is fired kSession.fireAllRules(); System.out.println("Nothing is printing by the rule"); //modification fact in order to match this fact with the rule person.setId(12467);that //here we use the FactHandle obtained by the insertion operation and the modified fact in order to notifies to the engine and get the rule reprocessed kSession.update(personFactHandle, person); //here the rule is fired again kSession.fireAllRules(); } catch (Throwable t) { t.printStackTrace(); } } }
The output of this program is:
Nothing by the rule printing //This is when the fact not match with the rules Fact handle Example //This is printing by the rule after the fact modification was done in order to match with the rule and the update operation is invoked
4. Conclusions
In this article we learned about what is a FactHandle inside the drools engine, how this works and in which scenarios are used on a rules project. We also saw some examples that show how to get a FactHandle and how to use it on a different scenarios.
To summarize this article, we can say that the FactHandle is a ID that is assigned to a object or fact inside the drools engine when this is inserted, this ID allows to identified a object or fact inside the engine in order to perform the different operations supported by the engine, like insertion, retraction and update, you can make a analogy between the FactHandle and data base record ID that allows identified a record inside a table on a data base engine and perform some operations on that record.
5. Download the Eclipse Project
This was a Drools FactHandle example with Jboss developer studio
You can download the full source code of this example here: FactHandleExample
Drools rule are blocked thread dump in case of concurrent request how to hand such kind of scenarios