Reading Time: 9 minutes

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.

latest report
Learn why we are the Leaders in API management and iPaaS

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.

Mule config

Since our Mule application uses both Drools and jBPM, the following declarations must be placed on top of the config:
<bpm:jbpm />
<bpm:drools /> 
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.

Note that the above snippet embeds Groovy script to create an Order. I did this for visibility, however, you may prefer to write this code in Java, or python or JavaScript for that matter.

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.

For more configuration options, refer to the jBPM documentation and/or Hibernate documentation.

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.

jBPM process

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>.

ElementUsageDescriptionRequired Attributes
<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:

<mule-receive name="unsortedOrder" 
          endpoint="UnsortedOrders" 
          type="com.yusen.mule.droolsbpmexample.Order" 
          var="order">
    <transition to="sendToDrools" />
</mule-receive>

Send message to DroolsEndpoint  which will invoke the Drools rules engine:

<mule-send name="sendToDrools" 
           expr="#{order}" 
           endpoint="DroolsEndpoint" 
           exchange-pattern="request-response" 
           var="order">
    <transition to="sendToWarehouse" />
</mule-send>

Make a decision based on data returned by Drools:

<decision name="sendToWarehouse">
        <transition to="sendToWarehouseA">
            <condition expr="#{order.destination == 'WAREHOUSE_A'}" />
        </transition>
        <transition to="sendToWarehouseB">
            <condition expr="#{order.destination == 'WAREHOUSE_B'}" />
        </transition>

        <transition to="routingFailed" />
</decision>

The decision invokes either sendToWarehouseA or sendToWarehouseB. These are <mule-send> process steps that invoke Mule endpoint:

    <mule-send name="sendToWarehouseA"
          expr="#{order}" endpoint="WarehouseA" exchange-pattern="one-way">
        <transition to="routingSuccessful" />
    </mule-send>
    
    <mule-send name="sendToWarehouseB"
          expr="#{order}" endpoint="WarehouseB" exchange-pattern="one-way">
        <transition to="routingSuccessful" />
    </mule-send>

Using Drools 

  • 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.