Getting started with Drools Flow
Today I will present my latest discovery called JBoss Drools and Drools Flow in particular. I am completely new to the drools framework and because I couldn’t find myself a quick and simple intro to the framework I will post it myself. Presented example is completely useless from the business perspective and it doesn’t describe any real world scenario.
According to the Drools Flow website itself:
Drools Flow provides workflow or (business) process capabilities to the Drools platform. A business process or workflow describes the order in which a series of steps need to be executed, using a flow chart. This makes it much easier to describe a complex composition of various tasks. Processes are especially useful in describing state-based, long-running processes. Drools Flow allows end users to specify, execute and monitor (a part of) their business logic using these processes. The Drools Flow process framework is easily embeddable into any Java application (as a simple Java component) or can run standalone in a server environment.
First of all you need to prepare your development environment. You will need the following:
- Eclipse IDE
- Drools Binaries v.5.1
- Drools Eclipse 3.5 Workbench
For the purpose of this tutorial that’s enough, you can try to download full Drools stack using the installer (including JBoss AS, Eclipse IDE, Birt reporting, Guvnor etc) but I didn’t have any luck with this installer and I guess you will be better off once you do install everything by hand as you learn.
Unpack drools binaries somewhere on your machine and Drools Eclipse workbench into eclipse folder. Restart your IDE and you should be able to create new Drools projects by now.
Select File -> New Project from the Eclipse file menu:
Provide descriptive name for your project:
Un-click all the proposed examples which eclipse plugin wants to generate for you, you can do that later if you want to learn more on drools.
Select Drools runtime, if you have no runtime configured, click ‘Configure Workspace settings’ and point to the directory where you have downloaded your binaries.
After you click finish, you should have a basic Drools project structure created for you:
Let’s create our application entry point with the main method we can execute to test our flow.
You should end up with a simple java class and single main method:
public class SPDroolsFlowExample {
/**
* @param args
*/
public static void main(String[] args) {
}
}
Now lets create our Flow file for the Drools Flow engine, select New -> Other on the project node and under the Drools folder select ‘Flow File’:
Select the name for your flow file:
The last step when creating your flow file is to select the runtime compatibility with the drools engine:
Once your flow file is created make sure its under src/main/rules while in the package explorer window, this will ensure that we can find it easily on our class-path while executing our test application.
Make sure you are in the ‘Drools Perspective’, open the rules file (*.rf) and drop the following onto the designer window:
Assuming you have a start event already placed in your flow (green cirle)
- 1 Gateway [diverge]
- 3 Logs (found under ‘service tasks’)
- 1 Gateway [converge]
- 1 End event
Once you do that, place them on the screen similary to this screenshot below and connect all together using ‘Sequence Flow’ arrow found at the top of the flow toolbox.
When you have your diagram ready, click on the whitespace anywhere on the diagram designer and under the properties tab provide the ID attribute, for this example we use ‘com.softwarepassion.droolsflowexample’:
Now on the designer select the first Gateway (diverge) and under properties tab set its type to ‘OR’:
For the second Gateway provide the type ‘XOR’, this ensures that we have to get the flow only from one of the nodes to proceed, selecting ‘AND’ for the second gateway would require two branches to be executed but we want to execute just one, either top or bottom log.
Once you select OR for the first gateway you can set constraints describing what exactly has to happen to go to the top branch or the bottom branch.
Click ‘…’ on the Constraints row (inside properties tab):
Select ‘Edit’ button for the top branch (‘To node Log Top’), change its type to ‘java’, dialect to ‘java’ and type in:
Similarly, for the other branch set the condition to return false:
Hardcoding ‘true’ and ‘false’ values is just for now, we will learn later on, how to insert some object into the flow and read its state inside a flow task.
Just for debugging purposes provide descriptive messages to our Log events, you can do that either from the Properties tab or by double clicking the node on the diagram itself.
Because we are using Log events all of them have the name ‘Log’.
Now lets do some wiring. Create a simple handler for our work items, ‘executeWorkItem’ method will be called every time the ‘Log’ task is executed within our workflow.
import org.drools.runtime.process.WorkItem;
import org.drools.runtime.process.WorkItemHandler;
import org.drools.runtime.process.WorkItemManager;
public class SimpleWorkItemHandler implements WorkItemHandler{
@Override
public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
System.out.println("Executing work item " + workItem);
manager.completeWorkItem(workItem.getId(), null);
}
@Override
public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
// Do nothing here
}
}
Wiring it all together, we end up with the following code in our main class:
import org.drools.KnowledgeBase;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.runtime.StatefulKnowledgeSession;
public class SPDroolsFlowExample {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
KnowledgeBase knowledgeBase = readKnowledgeBase();
StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
SimpleWorkItemHandler handler = new SimpleWorkItemHandler();
ksession.getWorkItemManager().registerWorkItemHandler("Log", handler);
ksession.startProcess("com.softwarepassion.droolsflowexample", null);
ksession.fireAllRules();
}
private static KnowledgeBase readKnowledgeBase() throws Exception {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("droolsflowexample.rf"), ResourceType.DRF);
return kbuilder.newKnowledgeBase();
}
}
Click on the class and select ‘Run as..’ -> ‘Java Application’, this will should print something similar to the following messages:
Source for the flow file at this stage of the tutorial is listed below:
<process xmlns="http://drools.org/drools-5.0/process"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://drools.org/drools-5.0/process drools-processes-5.0.xsd"
type="RuleFlow" name="flow" id="com.softwarepassion.droolsflowexample" package-name="com.softwarepassion" >
<header>
</header>
<nodes>
<start id="1" name="Start" x="72" y="206" width="48" height="48" />
<end id="7" name="End" x="802" y="196" width="48" height="48" />
<split id="8" name="Gateway" x="203" y="205" width="49" height="49" type="3" >
<constraints>
<constraint toNodeId="10" toType="DROOLS_DEFAULT" name="constraint" priority="1" type="code" dialect="java" >return true;</constraint>
<constraint toNodeId="11" toType="DROOLS_DEFAULT" name="constraint" priority="1" type="code" dialect="java" >return false;</constraint>
</constraints>
</split>
<join id="9" name="Gateway" x="537" y="197" width="49" height="49" type="2" />
<workItem id="10" name="Log Top" x="352" y="157" width="100" height="48" >
<work name="Log" >
<parameter name="Message" >
<type name="org.drools.process.core.datatype.impl.type.StringDataType" />
<value>Message from log top...</value>
</parameter>
</work>
</workItem>
<workItem id="11" name="Log Bottom" x="354" y="251" width="100" height="48" >
<work name="Log" >
<parameter name="Message" >
<type name="org.drools.process.core.datatype.impl.type.StringDataType" />
<value>Message from log bottom..</value>
</parameter>
</work>
</workItem>
<workItem id="12" name="Log End" x="657" y="196" width="100" height="48" >
<work name="Log" >
<parameter name="Message" >
<type name="org.drools.process.core.datatype.impl.type.StringDataType" />
<value>Message from log end</value>
</parameter>
</work>
</workItem>
</nodes>
<connections>
<connection from="12" to="7" />
<connection from="1" to="8" />
<connection from="11" to="9" />
<connection from="10" to="9" />
<connection from="8" to="10" />
<connection from="8" to="11" />
<connection from="9" to="12" />
</connections>
</process>
If all is fine and working we can continue to the next part of our tutorial showing you how to add data to our workflow which can be read/modified by the workflow tasks.
For this example we will create a very simple POJO which we will pass from one task to the other and based on the properties contained within that POJO we will direct our flow to one of the two branches created earlier in the tutorial.
public class SimpleTO {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
As you can see this is really simple java class :). Now let’s create an instance of it and add it to the workflow parameters, inside our class with the main method add the following:
KnowledgeBase knowledgeBase = readKnowledgeBase();
StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
Map<String, Object> parameterMap = new HashMap<String, Object>();
SimpleTO st = new SimpleTO();
st.setMsg("BOTTOM");
parameterMap.put("st", st);
SimpleWorkItemHandler handler = new SimpleWorkItemHandler();
ksession.getWorkItemManager().registerWorkItemHandler("Log", handler);
ksession.startProcess("com.softwarepassion.droolsflowexample", parameterMap);
ksession.fireAllRules();
}
Setting the ‘msg’ field to ‘TOP’ will cause to execute our top branch and ‘BOTTOM’ our bottom branch respectively.
For all this to work we need to add a variable to our workflow and change our constraints in the first gateway.
Click somwhere on the workflow to get the properties, select the ‘variables’ row and add a single variable called ‘st’:
Note that we have added our object using the key with the same name as the variable we are defining above. Once our variable is ready to be used in the workflow we can reference it in the Constraints dialogs of our diverging gateway:
Top constraint:
Bottom constraint:
Now you can test the application, changing the property of our injected object will cause going into one of the branches.
I hope it helps anyone trying to get started with the drools flow.
Enjoy!
Something is missing here, for example droolsflowexample.rf file.
Look closely, the file listing is there.
Where, I cannot find the code listing for the droolsflowexample.rf file in this page?
Its right under ‘Source for the flow file at this stage of the tutorial is listed below:’, but its not a final one though, you would have to follow the tutorial to create the final version of it.
Oh, I see now…sorry. But, how you translated bpmn into this rf xml file?
I found it, you used drools 5.0, but I choosed 5.1 and it created bpmn file instead of rf.
Krzysztof Grajek – Thank You…very useful.
I am looking for a way to slice DB data using Business Rules defined in Guvnor. I don’t want to do it per object basis. Would really appreciate if you can give some pointers on how to achieve it.
Good example. I am working on a similar example our project is using the Drools server as a service on another server. Do you know how I can add the pamameterMap so that it is available when we invoke the rules server?
hello,
I want to know the procedure to connect bpmn and drools. Is there any way to do this??
Thankyou
Very nice straightforward tutorial. Thanks for making the effort to put it down and share it with everyone. Works perfectly.
love it. thanks very much.
would be interested in bpmn tutorial aswell…
Thanks ! this is quite simple and easy to understand tutorial
Very good step by step example for someone beginning to learn jbpm also. Since everything is almost same except for using a bpmn2 file, it worked great.
I only had to change this line in
readKnowledgeBase() method
—————————
kbuilder.add(ResourceFactory.newClassPathResource(“sample.bpmn”), ResourceType.BPMN2);
—————————
Hi,
Thanks for such a easy and straight forward collection of steps.
Can you please describe about “How integrate Rules Flow with Drools Guvnor”.
Regards
mds
Thanks a bunch for sharing this with all folks you actually recognise what you’re speaking about! Bookmarked. Please also discuss with my site =). We will have a hyperlink change contract among us
I Tried the same sample. but i am getting the following error. some one please help me out on this
Exception in thread “main” java.lang.RuntimeException: Unable to get LastModified for ClasspathResource
Using Drools 5.4.0 in Eclipse
I am getting “invalid package name”.
Package for rf is: com.softwarepassion
Id is: com.softwarepassion.droolsflowexample
The stacktrace is:
org.drools.RuntimeDroolsException: invalid package name
at org.jbpm.compiler.ProcessBuilderImpl.buildProcess(ProcessBuilderImpl.java:173)
at org.jbpm.compiler.ProcessBuilderImpl.addProcessFromXml(ProcessBuilderImpl.java:252)
at org.drools.compiler.PackageBuilder.addProcessFromXml(PackageBuilder.java:652)
at org.drools.compiler.PackageBuilder.addKnowledgeResource(PackageBuilder.java:685)
at org.drools.builder.impl.KnowledgeBuilderImpl.add(KnowledgeBuilderImpl.java:45)
at org.drools.builder.impl.KnowledgeBuilderImpl.add(KnowledgeBuilderImpl.java:34)
at com.softwarepassion.droolsflow.SPDroolsFlowExample.readKnowledgeBase(SPDroolsFlowExample.java:29)
at com.softwarepassion.droolsflow.SPDroolsFlowExample.main(SPDroolsFlowExample.java:17)
[5,13]: [ERR 102] Line 5:13 mismatched input ‘true’ in rule “RuleFlow-Split-com.softwarepassion.droolsflowexample-2-7-DROOLS_DEFAULT”
[12,13]: [ERR 102] Line 12:13 mismatched input ‘false’ in rule “RuleFlow-Split-com.softwarepassion.droolsflowexample-2-8-DROOLS_DEFAULT”
[0,0]: Parser returned a null Package
ProcessLoadError: unable to parse xml : Exception class org.drools.RuntimeDroolsException : invalid package name
Exception in thread “main” java.lang.IllegalArgumentException: Could not parse knowledge.
at org.drools.builder.impl.KnowledgeBuilderImpl.newKnowledgeBase(KnowledgeBuilderImpl.java:73)
at com.softwarepassion.droolsflow.SPDroolsFlowExample.readKnowledgeBase(SPDroolsFlowExample.java:30)
at com.softwarepassion.droolsflow.SPDroolsFlowExample.main(SPDroolsFlowExample.java:17)
Its like you read my mind! You appear to grasp so much approximately this,
such as you wrote the e book in it or something. I think that you simply can do with a few p.c.
to pressure the message house a bit, however other than that, that
is excellent blog. A fantastic read. I’ll certainly be back.