Mule 3 has many routing processors and expression evaluators that can be used to implement routing logic. However, sometimes business rules may be too complex. For example, one of our customers is a large logistics company which uses Mule for their warehouse routing. To handle their complex set of rules, they decided to use Mule with jBPM and Drools.
This example illustrates use of Drools and jBPM inside Mule, by implementing very simple order sorting and warehouse routing use case. In this scenario all orders with weight greater than 50lbs should be routed to the warehouse A, and orders with weight equal to 50lbs or less should be routed to the warehouse B.
The sample orders are randomly generated and dispatched to the UnsortedOrders JMS queue. The jBPM process consumes unsorted orders and invokes Drools to make a decision on which warehouse this order should be routed to.
Since our Mule application uses both Drools and jBPM, the following declarations must be placed on top of the config:
Global definitions also include JMS connector and global endpoints:
The OrdersGenerator flow uses Quartz to generate a new event every 2 seconds. Then scripting component creates an instance of the Order class and randomly populates it with merchant and weight values. Finally, Order object is sent to the UnsortedOrders JMS queue.
Using jBPM with Mule consists of a few things:
- Configuring jBPM
- Configuring Hibernate and the database used to store process state
- Declaring jBPM as the BPMS to use in your Mule configuration
- Interacting with Mule from your process definition
The default configuration file for jBPM is called jbpm.cfg.xml. You will need to include this file as part of your Mule application. If defaults are ok for you, then it could be as simple as the following:
Note that you need to define the MuleMessageService within <process-engine-context> otherwise jBPM will not be able to “see” Mule.
jBPM uses Hibernate to persist the state of your processes, so you will need to provide a database supported by Hibernate and include any client jars as part of your Mule application. You also need to provide the file jbpm.hibernate.cfg.xml with the appropriate Hibernate settings for your database.
For example, a simple in-memory Derby database might use these settings:
while an Oracle database might use these settings:
One very important Hibernate setting to pay attention to is hibernate.hbm2ddl.auto. If this is set to create, Hibernate will automatically create the DB schema for jBPM at startup if it does not yet exist in your database. If it is set to create-drop, the schema will also be deleted at shutdown, which is useful in test environments.
The jBPMProcess flow consumes messages from UnsortedOrders JMS queue and invokes the jBPM process defined in the warehouse-routing-process.jpdl.xml. During the processing, jBPM invokes the DroolsFlow flow by sending Mule message to the DroolsEndpoint VM endpoint.
The DroolsFlow flow receives message on inbound VM endpoint and invokes the rules defined in the routingRules.drl file. The object returned by the rules engine is an instance of org.drools.common.EventFactHandle, so we need to extract the actual Order object by calling EventFactHandle.getObject() method.
Mule provides two custom elements for jBPM’s process definition language (jPDL). You can use these in your process definition along with other standard jPDL elements such as <state>, <java>,<script>, <decision>.
|<mule-send>||<mule-send expr=”” endpoint=”” exchange-pattern=”” var=”” type=””>||Activity which sends a message with the payload expr to the Mule endpoint. If exchange-pattern = request-response (the default value), the send will block and the response message will be stored into var. If the message is not of type, an exception will be thrown. expr can be a literal value or an expressionwhich references process variables.||The only mandatory attributes are expr and endpoint, the rest are optional.|
|<mule-receive>||<mule-receive var=”” endpoint=”” type=””>||Wait state which expects a message to arrive from the Mule endpoint and stores it into var. If the message is not of type, an exception will be thrown. <mule-receive> can replace <start> as the first state of a process and this way you can store the message which initiated the process into a variable.||The attributes are all optional.|
Receive message from UnsortedOrders JMS endpoint into the order variable:
Send message to DroolsEndpoint which will invoke the Drools rules engine:
Make a decision based on data returned by Drools:
The decision invokes either sendToWarehouseA or sendToWarehouseB. These are <mule-send> process steps that invoke Mule endpoint:
- Incoming Mule messages are asserted as new facts in Drools’ working memory.
- Mule messages can be generated as a result of Rules firing.
- In CEP mode, Mule messages can be received as an event stream and used to trigger complex operations such as temporal reasoning and pattern detection.
The Drools libraries are bundled with the Mule distribution. As of Mule 3.2, Drools 5.0 is the latest supported version.
Drools rules file
Download the complete example here.