Event Driven Business Process Management in jBPM5
Leveraging the power of jBPM5 and Drools Fusion
Introduction
jBPM5 introduces a very tight and powerful integration model for business rules, events and process like no other framework in the open source market. This post aims to show these integration capabilities with an example and to shed some light a new concept like Event Driven Business Process Management (ED-BPM).
ED-BPM besides from being the latest buzzword is also an extremely powerful concept to mimic how business processes interact in the real world: driven by business events. Traditionally BPM packages whether commercial or open source focused exclusively in processes, making difficult to create more complex applications that combine other components. jBPM5 makes it easier to express and implement these complex application using the integration approach discussed earlier.
So, first we’ll take a look at what jBPM5 provides as building blocks for developing ED-BPM oriented applications and then we’ll assemble an example to taste the new features for later use within your own applications. It is useful to have previous Drools experience to make the most from the example but it is in no way necessary.
What is ED-BPM?
This new concept was born from the combination of two disciplines: Business Process Management (BPM) and Event Driven Architecture (EDA). It is based on a close integration between the business processes or activities and the business events or relevant happenings inside or outside the processes. In the real world they interact with each other, for example: an event can trigger a process (an accident triggers an insurance payment process) and process send different kinds of stimuli in form of events (when they start, end or something important happens). These kinds of interactions can change business procedures or responses.
For example, as a business process starts (imagine a loan application by a client) it sends a business event with the relevant data (applicant name, amount request, etc), that event in turn can be consumed by other business processes (like a customer service process to assure customer representative quality). This is an example where the process emits events as relevant things occur (in this case it sends one when it starts, but it can be anywhere, or also when it ends).
The reverse approach is possible, where the business events create or modify the behavior of a business process. Imagine a fraud detection application in the finance industry, where the Complex Event Processing (CEP) engine has to consume thousands of transaction events per second, as soon as a threshold value is achieved (a number of doubtful transactions on behalf of a particular client); a process for analyzing the possible fraud case is generated for that client.
Another use of ED-BPM oriented applications is to adjust or relax constraints of the business processes due to work overload, spikes on the demand, or employee absences. For example, if there’s two or more loan department employees on sick leave and a typical loan application is manually inspected if it is over a certain amount, this restriction can be softened, thus the minimum value raised,due to this unusual situation. This way service level agreements can be respected without human intervention, thus automating some management decisions about the allocation of resources.
jBPM5 ED-BPM Building Blocks:
- Knowledge Sessions
- ProcessEventListeners
- Processes
- Rules and Events
After understanding the basic building blocks for a ED-BPM we’ll proceed to create some KnowledgeSessions, write a custom ProcessEventListener, model a business process and author a rule that fires upon an event-based condition. Don’t worry as we’ll explain them all ! Finally we’ll integrate all of these components to create a ED-BPM based application so you will grasp the potential of this new concept.
Knowledge Sessions
It is essential to understand the concept of the Knowledge Session (KS). The KS is where the interesting things happen: new information enters the engine (facts) and it does its job: match rule patterns to facts. We are not going to describe how the rule engine works here, but instead we can show you an excellent resource that does so.
One way to approach a ED-BPM applications inside jBPM5 is to use a KS for processes (from now on known as PKS) as usual and to dedicate another specific KS to the event processing (EKS) with its own rules. This way we separate processes logic and rules from the event processing ones. This allow a nice decoupling for building some kind of process “hypervisor” rules, that sit on top of any process.
Also we need a way to bridge the PKS and the EKS. jBPM5 has a very powerful concept for this: a Process Event Listener. This listener receives every relevant process related event from the engine. This way we can create our own listener (by implementing that Java interface) that captures the process engine events that we want to expose as business events and send them to the EKS. This design is illustrated in Figure 1:
Figure 1. One approach to a jBPM5 ED-BPM architecture
Note that you must not confuse this kind of internal engine event from the business ones. In our example the EKS will make use of the process engine events to alert of any spike in the demand of that process, that is, when too many are created at around the same time and thus very difficult to handle by the employees and possibly jeopardizing the customer service agreement levels and satisfaction.
Also we implement a CustomProcessEventListener to feed the EKS with the revelant PKS information.
Processes
Processes in jBPM5 are modelled in BPMN2 format. This is an standard notation for business processes model interoperability and diagramming. In our example the process is defined in this format in the loan.bpmn file in the example distribution. So our example process has 4 simple activities depicted in Figure 2 below:
Figure 2. Loan Application Example Process
- Start Node (Green Dot): Every jPBM5 process has it (as it is mandatory) and signals the start of every process. Under the hood, this node calls all the ProcessEventListeners with the ProcessStartedEvent object along with the process instance information contained inside it.
- Analyze Credit Score: Ideally here we should have a human task (if manually verified) or an automated rule with the business logic associated to approve or reject an application. For the sake of simplicity of the example this is a dummy step that only prints out a text line to the console.
- Send Result to Customer: This final node send an email to the applicant telling the result of the application: Accepted or Rejected. As in the previous node this is a dummy activity to simplify the example.
- End Node (Red Dot): It serves to signal the process engine that the process instance has ended. It has no use in this example, but it is useful for further extensions to the ProcessEventListener due to the events that it emits.
Rules and Events
Rules are represented with a bunch of conditions and a consequence to fire if the conditions are all true based on real world information: also known as facts. We won’t discuss the rules concept or syntax, for a great overview of the capabilities of the engine, read the introductory chapter of the Drools documentation.
So Drools can treat facts (information entering the engine) as plain facts or as events, simply by declaring a Java POJO as one. The difference in treatment lies in the temporal dimension of the event and the lack of thereof in the facts. Additionally, the engine offers a few temporal operators to inspect how events relate in time and between each other. In a nutshell you can use the whole range of rules expressions with events as they are facts with a little bit more attitude.
In the example we’ll define our event related rule in the EventRules.drl file. In the next snippet you can take a look at the demo’s only but meaningful rule:
import org.drools.event.process.ProcessStartedEvent; declare ProcessStartedEvent @role( event ) end dialect "mvel" rule "Spike alert: More than 100 processes started in less than one hour " when Number( nbProcesses : intValue > 100 ) from accumulate( e: ProcessStartedEvent( processInstance.processId == "com.plugtree.jbpm5.edbpm.demo.LoanProcess" ) over window:size(1h), count(e) ) then System.err.println( "WARNING: Number of Loan applications in the last hour above 100: " + nbProcesses ); end
Code Snippet 1. Example Drools Fusion rule
The snippet (actually the whole DRL file) starts by declaring the facts of type ProcessStartedEvent as events and exposing the engine to it (using an import declaration). That is they will be treated with the temporal dimension in mind (and other aspects like memory management as well, but these are out of the scope of this post).
Following the declaration, we define a rule that uses a Drools accumulator function to count all the occurrences of the event (with the process name LoanProcess ) and when this count reaches 100 within the scope of 1 hour it will activate. The activation only prints a line to the system console.
Of course, the possibilities are limitless as you can use any Java code in the consequence, for example you can send an email, SMS or any other form of alert medium to tell the users about this irregular situation.
Example’s code walkthrough
Let’s our hands dirty! Our example uses a EDBPMTestCase class to initialize the Drools engine by creating two separated KS, as explained earlier. The first one uses the process from the loan.bpmn file, while the later uses the rules stored in the EventRules.drl. Then a key line happens:
ksession.addEventListener(new CustomProcessEventListener(eventKsession));
This adds our CustomProcessEventListener as a ProcessEventListener to the PKS. It receives a KnowledgeSession as its constructor parameter, this is the EKS used by the listener to inject the process engine internal events as facts.
Then it starts 101 loan process and finally it ends as there is no node in the wait state:
ksession.addEventListener(new CustomProcessEventListener(eventKsession));
However one of the most relevant piece of code is the CustomProcessEventListener one:
….
public class CustomProcessEventListener implements ProcessEventListener {
private StatefulKnowledgeSession eventKsession;
public CustomProcessEventListener(StatefulKnowledgeSession ksession){
eventKsession = ksession;
}
public void beforeProcessStarted(ProcessStartedEvent event) {
eventKsession.insert(event);
eventKsession.fireAllRules();
}
….
This class has a constructor that receives the EKS as a parameter, and you can see the beforeProcessStarted method taking a ProcessStartedEvent instance as a parameter from the engine. This method is called before the engine executes any node in the process.
Running the example
You can run the example by executing the following command (assuming you have Apache Maven 3 installed in your machine and available in your PATH environment variable):
mvn test
After running the example class your console will spit out a bunch of lines with the LoanProcess own System.out messages and after creating the 100th process instance a line will appear in the console stating that:
WARNING: Number of Loan applications in the last hour above 100: 101
That’s it. Easy isn’t it?
Extending the example
You can download the example files from www.github.com/plugtree/edbpm-demo using Git. Also if you need more information about Drools and jBPM5 both have plenty of documentation that you can download from their website.
If you feel like doing so you can extend the example further by using other process engine events like afterProcessCompleted() or afterNodeTriggered() to feed the EKS and add other time based alerts or event correlation rules to for example check for out of range SLA’s.
Summary
By now you should be able to grasp the true potential of integrating events and processes into your user’s problem domain. It has tremendous uses for an intuitive integration between processes too. Now you only need to find your killer application inside your domain, usually the business problems appear as soon as you ask your business managers how you can make their life easier when it comes to processes.
In the next few weeks I’ll post another example of ED-BPM related to this one extending the use of the listener to other real world use cases, so stay tuned by subscribing to our RSS Feed or newsletter!
JBPM5 professional services
Plugtree LLC offers enterprise services for jBPM5 and Drools 5: custom training suited to your company’s needs, a variety of consulting topics from architecture reviews, best practices and performance tuning, and an all encompassing production support with SLAs according to your needs. We’ve helped dozens of clients to adopt the Drools and jBPM technologies across a variety of industries and you can be one of them too. Contact us: info@plugtree.com
Related posts:



Hi PlugTree Team,
I’m a beginner to Jpbm n Jboss n Drools n all…
I’ve tried the above Example n it worked fine. Thanks for the great help first….
now I’ve to control the jpbm process flow based on the rools decision. I’ve tried Like this…
i added an decision control before send result and added another script as “send error to customer” on other side of the decision. then added a variable on class loan boolean deliverystatus.
now i cant unable to access the class loan in drools file (drl file). I’ve added the class object using insert command to that session.
im able to get access the ProcessStartedEvent class only in drl file.
Help me please…
Thanks in advance…
Hi…
I successfully fixed the issue and the program has been executed.
I’ve uploaded the results and the way i proceed at
https://sites.google.com/site/jpbmexample/home/my-first-event-base-example
just check this.. and guide me…
Thanks…
Hi!
First: thanks for good example.
But I found a bug in the rule:
over window:size(1h),
window:size doesn’t work. I fixed it to:
over window:time(1h),
Excellent article!
I created my own listener and logged the run of one of my working processes. I was shocked by the output. It appears that the listener runs on the SAME thread (as seen in the log) and yet the logging is out of order, even the “afterProcessCompleted” event. Am I doing something wrong?
I use jBPM5.2 with Drools 5.3 on Jboss App Server 7.1 final.
Thank you for any insight you can offer.
Line 278: 11:53:01,726 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeProcessStarted
Line 280: 11:53:01,742 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 281: 11:53:01,742 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 282: 11:53:01,757 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 291: 11:53:01,757 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 292: 11:53:01,757 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 295: 11:53:01,773 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 296: 11:53:01,773 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 297: 11:53:01,773 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 298: 11:53:01,773 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
Line 299: 11:53:01,773 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 300: 11:53:01,773 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
Line 301: 11:53:01,788 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 302: 11:53:01,788 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
Line 303: 11:53:01,788 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 304: 11:53:01,788 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterProcessStarted
Line 306: 11:53:01,804 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 307: 11:53:01,804 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 312: 11:53:01,804 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 313: 11:53:01,804 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 3976: 11:53:10,806 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 3977: 11:53:10,806 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 3978: 11:53:10,806 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 3979: 11:53:10,806 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 4079: 11:53:10,946 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 4080: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeTriggered
Line 4081: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeNodeLeft
Line 4082: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) beforeProcessCompleted
Line 4083: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterProcessCompleted
Line 4084: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
Line 4085: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 4086: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
Line 4087: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 4088: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
Line 4089: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 4090: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
Line 4091: 11:53:10,962 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 4092: 11:53:10,977 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
Line 4093: 11:53:10,977 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeTriggered
Line 4094: 11:53:10,977 INFO [FrameworkEventMonitor] (http--0.0.0.0-8080-2) afterNodeLeft
The BPMN is as follows.
try
{
MonitorUtil.monitor(kcontext) ;
// prepare the feed for the decision table
AnIMSFile projectFile =null ;
try {
projectFile = imsFileNoun.find(projectName) ;
} catch (Exception e) { System.out.println ("noun!!!!!!!!!!!") ; e.printStackTrace(); }
Boolean foundIt = (projectFile != null) ;
//global String projectUID
projectUID = "" ;
if (foundIt) { projectUID= projectFile.getFileUID(); }
kcontext.setVariable ("projectUID",projectUID);
kcontext.setVariable ("found", foundIt) ;
//System.out.println (projectName + projectUID + " " + foundIt) ;
//System.out.println ("------------------------------------------------------FOUND----------------- " + foundIt) ;
}catch (Exception e) { e.printStackTrace(); }
_20_userNameInput
_20_projectNameInput
_20_DueDateInput
_20_ListNameInput
_20_AssignedToInput
_20_TitleInput
_20_serviceResultsOutput
userName
_20_userNameInput
projectName
_20_projectNameInput
_20_DueDateInput
TODO
_20_DueDateInput
_20_ListNameInput
Tasks for IBE Developers
_20_ListNameInput
_20_AssignedToInput
Lillian Andres
_20_AssignedToInput
_20_TitleInput
check project - may need to add to the database
_20_TitleInput
_20_serviceResultsOutput
serviceResults
try
{
//System.out.println("Gather Work Packages from Active Detail Tasks");
MonitorUtil.monitor(kcontext) ;
filteredOutputTasks.getWorkPkgsFromActiveTasks(); // sets workPkds
//System.out.println("DONE Gather Work Packages from Active Detail Tasks");
} catch (Exception e) { e.printStackTrace(); }
try
{
MonitorUtil.monitor(kcontext) ;
String forLog = filteredOutputTasks.myScriptDisplayTask(rangeInDays, statusDate, "\n");
System.out.println("=======================================");
System.out.println (forLog) ;
System.out.println("=======================================");
MonitorUtil.stopMonitorProcess(kcontext) ;
} catch (Exception e) { e.printStackTrace(); }
System.out.println("user name is " + userName ) ;
System.out.println("statusDate is " + statusDate) ;
System.out.println("range in days " + rangeInDays) ;
System.out.println("project name is " + projectName) ;
MonitorUtil.monitor(kcontext) ;
try
{
MonitorUtil.monitor(kcontext) ;
//System.out.println (projectName + " = " + projectUID) ;
//System.out.println ("filteredOutputTasks = " + filteredOutputTasks) ;
try {
filteredOutputTasks.fillRulePassedTasks (projectUID) ;
} catch (Exception e) { e.printStackTrace(); }
filteredOutputTasks.myScriptGetActiveAndActiveNearTermTasks(rangeInDays, statusDate);
} catch (Exception e) { e.printStackTrace(); }
Boolean foundIt = (Boolean) kcontext.getVariable("found") ;
System.out.println ("in XOR with found having value " + foundIt) ;
return !foundIt ;
Boolean foundIt = (Boolean) kcontext.getVariable("found") ;
System.out.println ("in XOR with found having value " + foundIt) ;
return foundIt ;