Mule 3.3 – jBPM Model Part 2

In the previous post I spoke about how create a business model process using jBPM engine in Eclipse.

In this post I’ll show you how integrate the business process with Mule flow.

You need some files to complete the configuration of our Business process. One of these files is jbpm.cfg.xml


<?xml version="1.0" encoding="UTF-8"?>

<jbpm-configuration>

    <import resource="jbpm.default.cfg.xml" />
    <import resource="jbpm.jpdl.cfg.xml" />
    <import resource="jbpm.tx.hibernate.cfg.xml" />

    <process-engine-context>
        <object />
    </process-engine-context>

</jbpm-configuration>

The above file include the hibernate definition.


<?xml version="1.0" encoding="WINDOWS-1251"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "<a href="http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd</a>">

<!--
NOTE: This file is essentially the same as the default one that comes
with jbpm. However, because hibernate defaults derby blob columns to be
only 255 bytes, jbpm tests fail because the column is too short.

The only difference is the following:

    Original version:
    <property name="blob" type="blob"><column name="BLOB_VALUE_"/></property>

    New version:
    <property name="blob" type="blob"><column name="BLOB_VALUE_" length="10000000"/></property>
-->

<hibernate-mapping package="org.jbpm.pvm.internal.model" default-access="field">

  <!-- ### TYPEDEFS ####################################################### -->
  <typedef name="converter">
    <param name="org.jbpm.pvm.internal.type.converter.BooleanToStringConverter"    >bool-str</param>
    <param name="org.jbpm.pvm.internal.type.converter.ByteToLongConverter"         >byte-long</param>
    <param name="org.jbpm.pvm.internal.type.converter.CharacterToStringConverter"  >char-str</param>
    <param name="org.jbpm.pvm.internal.type.converter.DateToLongConverter"         >date-long</param>
    <param name="org.jbpm.pvm.internal.type.converter.DateToStringConverter"       >date-str</param>
    <param name="org.jbpm.pvm.internal.type.converter.DoubleToStringConverter"     >double-str</param>
    <param name="org.jbpm.pvm.internal.type.converter.FloatToDoubleConverter"      >float-double</param>
    <param name="org.jbpm.pvm.internal.type.converter.FloatToStringConverter"      >float-str</param>
    <param name="org.jbpm.pvm.internal.type.converter.IntegerToLongConverter"      >int-long</param>
    <param name="org.jbpm.pvm.internal.type.converter.SerializableToBytesConverter">ser-bytes</param>
    <param name="org.jbpm.pvm.internal.type.converter.ShortToLongConverter"        >short-long</param>
  </typedef>

  <!-- ### EXECUTION ############################################# -->
  <class name="ExecutionImpl"
         table="JBPM4_EXECUTION"
         discriminator-value="pvm">
    <id name="dbid" column="DBID_">
      <generator />
    </id>
    <discriminator><column name="CLASS_" /></discriminator>
    <version name="dbversion" column="DBVERSION_" />
   
    <property name="activityName" column="ACTIVITYNAME_" />
    <property name="processDefinitionId" column="PROCDEFID_" />

    <property name="hasVariables" column="HASVARS_" />
    <map name="variables"
         cascade="all-delete-orphan">
      <key foreign-key="FK_VAR_EXECUTION">
         <column name="EXECUTION_" index="IDX_VAR_EXECUTION"/>
      </key>
      <map-key type="string" column="KEY_" />
      <one-to-many />
    </map>
    <map name="systemVariables"
         cascade="all-delete-orphan">
      <key foreign-key="FK_VAR_EXESYS">
         <column name="EXESYS_" index="IDX_VAR_EXESYS"/>
      </key>
      <map-key type="string" column="KEY_" />
      <one-to-many />
    </map>
   
   
    <property name="name" column="NAME_" />
    <property name="key" column="KEY_" />
    <property name="id" column="ID_" unique="true" />
    <property name="state" column="STATE_" />
    <property name="suspendHistoryState" column="SUSPHISTSTATE_" />

    <property name="priority" column="PRIORITY_" />
    <property name="historyActivityInstanceDbid" column="HISACTINST_" />

    <list name="executions"
          cascade="all-delete-orphan"
          inverse="false"
          lazy="false">
      <key column="PARENT_" foreign-key="FK_EXEC_PARENT" />
      <list-index column="PARENT_IDX_" />
      <one-to-many />
    </list>
   
    <map name="swimlanes"
         cascade="all-delete-orphan">
      <key foreign-key="FK_SWIMLANE_EXEC">
         <column name="EXECUTION_" index="IDX_SWIMLANE_EXEC"/>
      </key>
      <map-key type="string" column="NAME_" />
      <one-to-many />
    </map>

    <many-to-one name="parent"
                 column="PARENT_"
                
                 foreign-key="FK_EXEC_PARENT"
                 index="IDX_EXEC_PARENT"
                 lazy="false" />

    <many-to-one name="processInstance"
                
                 column="INSTANCE_"
                 foreign-key="FK_EXEC_INSTANCE"
                 index="IDX_EXEC_INSTANCE"
                 lazy="false" />

    <many-to-one name="superProcessExecution"
                 column="SUPEREXEC_"
                
                 foreign-key="FK_EXEC_SUPEREXEC"
                 index="IDX_EXEC_SUPEREXEC" />
                
    <many-to-one name="subProcessInstance"
                 column="SUBPROCINST_"
                
                 foreign-key="FK_EXEC_SUBPI"
                 index="IDX_EXEC_SUBPI" />
                
  </class>

  <!-- ### VARIABLE ####################################################### -->
  <class name="org.jbpm.pvm.internal.type.Variable" abstract="true" discriminator-value=" " table="JBPM4_VARIABLE">
    <!-- discriminator values:
    date   : org.jbpm.pvm.internal.type.variable.DateVariable
    double : org.jbpm.pvm.internal.type.variable.DoubleVariable
    hibl   : org.jbpm.pvm.internal.type.variable.HibernateLongVariable
    long   : org.jbpm.pvm.internal.type.variable.LongVariable
    hibs   : org.jbpm.pvm.internal.type.variable.HibernateStringVariable
    string : org.jbpm.pvm.internal.type.variable.StringVariable
    null   : org.jbpm.pvm.internal.type.variable.NullVariable
    blob   : org.jbpm.pvm.internal.type.variable.BlobVariable
    clob   : org.jbpm.pvm.internal.type.variable.ClobVariable
    -->
 
    <id name="dbid" column="DBID_">
      <generator />
    </id>
    <discriminator column="CLASS_"/>
    <version name="dbversion" column="DBVERSION_" />
   
    <property name="key" column="KEY_"/>
    <property name="converter" type="converter" column="CONVERTER_" />
    <property name="isHistoryEnabled" column="HIST_" />
   
    <many-to-one name="execution"
                 column="EXECUTION_"
                
                 foreign-key="none"/>
    <many-to-one name="task"
                 column="TASK_"
                
                 foreign-key="none"/>
  </class>

  <subclass name="org.jbpm.pvm.internal.type.variable.BlobVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="blob">
    <many-to-one name="lob"
                 column="LOB_"
                 cascade="all"
                
                 foreign-key="FK_VAR_LOB"
                 index="IDX_VAR_LOB" />
  </subclass>
 
  <subclass name="org.jbpm.pvm.internal.type.variable.DateVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="date">
    <property name="date" column="DATE_VALUE_" type="timestamp"/>
  </subclass>
 
  <subclass name="org.jbpm.pvm.internal.type.variable.DoubleVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="double">
    <property name="d" column="DOUBLE_VALUE_" type="double"/>
  </subclass>
 
  <subclass name="org.jbpm.pvm.internal.type.variable.HibernateLongVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="hib-long">
    <any name="hibernatable" id-type="long">
      <column name="CLASSNAME_"/>
      <column name="LONG_VALUE_"/>
    </any>
  </subclass>
 
  <subclass name="org.jbpm.pvm.internal.type.variable.HibernateStringVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="hib-string">
    <any name="hibernatable" id-type="string">
      <column name="CLASSNAME_"/>
      <column name="STRING_VALUE_"/>
    </any>
  </subclass>
 
  <subclass name="org.jbpm.pvm.internal.type.variable.LongVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="long">
    <property name="l" column="LONG_VALUE_" type="long"/>
  </subclass>
 
  <subclass name="org.jbpm.pvm.internal.type.variable.NullVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="null">
  </subclass>
 
  <subclass name="org.jbpm.pvm.internal.type.variable.StringVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="string">
    <property name="string" column="STRING_VALUE_" type="string"/>
  </subclass>
 
  <subclass name="org.jbpm.pvm.internal.type.variable.TextVariable" extends="org.jbpm.pvm.internal.type.Variable" discriminator-value="text">
    <property name="text" column="TEXT_VALUE_" type="text"/>
  </subclass>
 
  <!-- ### LOB ############################################################ -->
  <class name="org.jbpm.pvm.internal.lob.Lob" table="JBPM4_LOB">
    <id name="dbid" column="DBID_">
      <generator />
    </id>
    <version name="dbversion" column="DBVERSION_" />
    <property name="blob" type="blob"><column name="BLOB_VALUE_" length="10000000" /></property>
    <!--
    should only be re-introduced if there comes a concrete need for it.
    <property name="bytes" type="binary" column="BINARY_VALUE_"/>
    <property name="clob" type="clob" column="CLOB_VALUE_" />
    <property name="text" type="text" column="TEXT_VALUE_"/>
    -->
  </class>
 
  <class name="org.jbpm.pvm.internal.job.JobImpl" table="JBPM4_JOB" discriminator-value="Job">
    <id name="dbid" column="DBID_">
      <generator />
    </id>
    <discriminator column="CLASS_" />
    <version name="dbversion" column="DBVERSION_" />

    <property name="dueDate" column="DUEDATE_" type="timestamp" index="IDX_JOBDUEDATE"  />
    <property name="state" column="STATE_" />
    <property name="isExclusive" column="ISEXCLUSIVE_" />
    <property name="lockOwner" column="LOCKOWNER_" />
    <property name="lockExpirationTime" column="LOCKEXPTIME_" index="IDX_JOBLOCKEXP" />
    <property name="exception" column="EXCEPTION_" type="text" />
    <property name="retries" column="RETRIES_" index="IDX_JOBRETRIES" />
   
    <many-to-one name="processInstance"  
                  
                 column="PROCESSINSTANCE_"
                 cascade="none"
                 foreign-key="none"
                 index="IDX_JOB_PRINST"
                 lazy="false"/>

    <many-to-one name="execution"
                  
                 column="EXECUTION_"
                 cascade="none"
                 foreign-key="none"
                 index="IDX_JOB_EXE"/>

    <many-to-one name="configurationBytes"
                 column="CFG_"
                 cascade="all"
                
                 foreign-key="FK_JOB_CFG"
                 index="IDX_JOB_CFG" />

    <subclass name="org.jbpm.pvm.internal.job.MessageImpl" discriminator-value="Msg">
      <subclass name="org.jbpm.pvm.internal.model.op.ExecuteActivityMessage" discriminator-value="ExeAct" />
      <subclass name="org.jbpm.pvm.internal.model.op.ExecuteEventListenerMessage" discriminator-value="ExeEvtLsnr" />
      <subclass name="org.jbpm.pvm.internal.job.CommandMessage" discriminator-value="Cmd" />
    </subclass>
   
    <subclass name="org.jbpm.pvm.internal.job.TimerImpl" discriminator-value="Timer">
      <property name="signalName" column="SIGNAL_" />
      <property name="eventName" column="EVENT_" />
      <property name="repeat" column="REPEAT_" />
     
      <subclass name="org.jbpm.pvm.internal.job.StartProcessTimer" discriminator-value="PeriodicStartProcess" />
   
    </subclass>
   
  </class>

  <!-- ### HibernatePvmDbSession QUERIES ################################## -->

  <query name="findTimers">
    <![CDATA[
     select t
     from org.jbpm.pvm.internal.job.TimerImpl as t
     order by dueDate asc
    ]]>
  </query>

  <query name="findMessages">
    <![CDATA[
     select m
     from org.jbpm.pvm.internal.job.MessageImpl as m
    ]]>
  </query>

  <query name="findJobsWithException">
    <![CDATA[
     select job
     from org.jbpm.pvm.internal.job.JobImpl as job
     where job.retries = 0
     order by dueDate asc
    ]]>
  </query>

  <!-- ### HibernateJobDbSession QUERIES ################################## -->
  <query name="findFirstAcquirableJob">
    <![CDATA[
     select job
     from org.jbpm.pvm.internal.job.JobImpl as job
     where (job.lockExpirationTime is null or job.lockExpirationTime <= :now)
       and (job.dueDate is null or job.dueDate <= :now)
       and job.retries > 0
       and job.state != 'suspended'
     order by job.dueDate asc
    ]]>
  </query>

  <query name="findExclusiveJobs">
    <![CDATA[
     select job
     from org.jbpm.pvm.internal.job.JobImpl as job
     where job.lockOwner is null
       and job.processInstance = :processInstance
       and job.isExclusive = true
       and job.retries > 0
       and job.state != 'suspended'
       and (job.dueDate is null or job.dueDate <= :now)
     order by job.dueDate asc
    ]]>
  </query>
 
  <query name="findFirstDueJob">
    <![CDATA[
     select job
     from org.jbpm.pvm.internal.job.JobImpl as job
     where job.lockOwner is null
       and job.retries > 0
       and job.state != 'suspended'
     order by job.dueDate asc
    ]]>
  </query>
 
  <!-- ### HibernatePvmDbSession QUERIES ############################################# -->
  <query name="findExecutionById">
    <![CDATA[
     select execution
     from org.jbpm.pvm.internal.model.ExecutionImpl as execution
     where execution.id = :id
    ]]>
  </query>

  <query name="findProcessInstanceById">
    <![CDATA[
     select processInstance
     from org.jbpm.pvm.internal.model.ExecutionImpl as processInstance
     where processInstance.id = :processInstanceId
       and processInstance.parent is null
       and processInstance.state != 'suspended'
    ]]>
  </query>

  <query name="findProcessInstanceByIdIgnoreSuspended">
    <![CDATA[
     select processInstance
     from org.jbpm.pvm.internal.model.ExecutionImpl as processInstance
     where processInstance.id = :processInstanceId
       and processInstance.parent is null
    ]]>
  </query>

  <query name="findProcessInstanceIds">
    <![CDATA[
     select processInstance.id
     from org.jbpm.pvm.internal.model.ExecutionImpl as processInstance
     where processInstance.processDefinitionId = :processDefinitionId
       and processInstance.parent is null
    ]]>
  </query>
</hibernate-mapping>

As Last you have to configure the jbpm.hibernate.cfg.xml file. I’m using derbyDB in memory mode.


<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "<a href="http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd</a>">

<hibernate-configuration>
  <session-factory>

     <property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
     <property name="hibernate.connection.driver_class">org.apache.derby.jdbc.EmbeddedDriver</property>
     <property name="hibernate.connection.url">jdbc:derby:memory:muleEmbeddedDB;create=true</property>
     <property name="hibernate.hbm2ddl.auto">create-drop</property>
     <property name="hibernate.format_sql">true</property>
     <!-- This is a tweaked version of Hibernate's DriverManagerConnectionProvider which works with Mule's hot deployment -->
     <property name="hibernate.connection.provider_class"> org.hibernate.connection.SimpleConnectionProvider</property>

     <!-- This property improves thread contention with Mule services a bit -->
     <property name="hibernate.transaction.flush_before_completion">true</property>
     <!--
     <property name="hibernate.cache.use_second_level_cache">false</property>
    -->

     <!-- Standard jBPM mappings -->
     <mapping resource="jbpm.repository.hbm.xml" />
     <mapping resource="jbpm.history.hbm.xml" />
     <mapping resource="jbpm.task.hbm.xml" />
     <mapping resource="jbpm.identity.hbm.xml" />

     <!-- Hibernate defaults Derby's BLOB columns to be too small -->
     <mapping resource="jbpm.execution.derby.hbm.xml" />

  </session-factory>
</hibernate-configuration>

I know what you’re thinking: Can I avoid using a persistence system? The answer, at last for me, is not.

I have never found any solution for it. Anyway, you have to think that we are talking about Memory database.

Once you have concluded this part it’s time to understand how mule can comunicate with business process. This is possible by two connector inside orderprocess.jpdl.xml file.

<mule-receive> : Wait state which expects a message to arrive from the Mule endpoint.

<mule-send>: Activity which sends a message with the payload to the Mule endpoint.

This two tags are the start and the end point of our business process model. Unfortunately there aren’t a graphic rappresentations of in eclipse plugin. So, you can see it only through the source code.

The mule config file accepts an input by the user and run the process:


<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
	xmlns:stdio="http://www.mulesoft.org/schema/mule/stdio"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:bpm="http://www.mulesoft.org/schema/mule/bpm"
      xmlns:vm="http://www.mulesoft.org/schema/mule/vm"
      xsi:schemaLocation="
      	  http://www.mulesoft.org/schema/mule/stdio http://www.mulesoft.org/schema/mule/stdio/3.3/mule-stdio.xsd
          http://www.mulesoft.org/schema/mule/bpm http://www.mulesoft.org/schema/mule/bpm/3.3/mule-bpm.xsd
          http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.3/mule.xsd
          http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/3.3/mule-vm.xsd">

<bpm:jbpm />
<stdio:endpoint name="toOrderprocess" system="IN" />
<stdio:endpoint name="fromOrderprocess" system="OUT" />

<stdio:connector name="stdio" promptMessage="Order Number: " messageDelayTime="1000"/>
	<flow name="echo">
		<stdio:inbound-endpoint ref="toOrderprocess"/>
		<bpm:process processName="orderprocess" processDefinition="orderprocess.jpdl.xml"/>
		<stdio:outbound-endpoint ref="fromOrderprocess"/>
	</flow>

</mule>

The user inserts the order number id and the process search for this order.
Once find it, the process decides if accept or refuse the order. The output of this is given to output endpoint mule connector.

Very important definition are the global endpoint “toOrderprocess” and “fromOrderprocess”. They are used even in process model definition.

The output will be:

Order Number: AZ-1265
orderId: AZ-1265 quantity: 100 amount: 2011.9 response:Accepted
INFO 2012-06-08 14:35:17,424 [echo.stage1.02] org.mule.module.bpm.Process: New process started, ID = orderprocess.32
execution[orderprocess.32]

Order Number: AZ-6522
orderId: AZ-6522 quantity: 10 amount: 115.9 response:Refused
INFO 2012-06-08 14:35:28,486 [echo.stage1.02] org.mule.module.bpm.Process: New process started, ID = orderprocess.44
execution[orderprocess.44]
Order Number:

Summary

I’ve found a bit of confusion among bpm implementations. Even Mule is partecipating in Activiti project and, probably, Mule will give more integration on this direction rather than other implementation (this version implements BPMN 2.0).

Be careful when you use the diagram designer because, sometimes, I’ve found the cutted code when I switched from design to source code.

I hope I’ve given to you a little guide to start using BPM in your project. As usual, my suggestion is to spend time to learn it.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.