这个例子简要说明如下:
通过jbpm-4.4的<on>元素和org.jbpm.api.listener.EventListener接口来处理活动结点<state>,对每个结点的状态进行监听,从而进行处理;
在例子中流程中,对每一个转移<transition>需要进行条件判断,使用<decision>元素及其子元素<handler>来进行处理。
该例子的流程定义,如图所示:
对应的流程定义文件如下所示:
<?xml version="1.0" encoding="UTF-8"?> <process name="MyExample" xmlns="http://jbpm.org/4.4/jpdl"> <on event="start"> <event-listener class="com.umpay.workflow.jbpm.listener.StartupListener"> <field name="status"> <string value="startup check..."/> </field> </event-listener> </on> <start g="354,6,48,48"> <transition g="-102,-16" name="to start decision" to="start decision"> <event-listener class="com.umpay.workflow.jbpm.listener.InitializationListener"> <field name="initialized"> <string value="initialize..."/> </field> </event-listener> </transition> </start> <decision g="413,107,48,48" name="start decision"> <handler class="com.umpay.workflow.jbpm.decision.StartDecision" /> <transition g="-83,-17" name="to check user" to="check user"/> <transition g="-48,-25" name="to error" to="error"/> </decision> <state g="216,183,104,52" name="check user"> <on event="start"> <event-listener class="com.umpay.workflow.jbpm.listener.CheckUserListener"> <field name="state"> <string value="Check user state..."/> </field> </event-listener> </on> <transition g="-128,-8" name="to decide check user" to="decide check user result"/> </state> <decision g="359,271,48,48" name="decide check user result"> <handler class="com.umpay.workflow.jbpm.decision.CheckUserDecision" /> <transition g="-95,-17" name="to check mobile" to="check mobile"/> <transition g="-41,14" name="to error" to="error"/> </decision> <state g="215,349,104,52" name="check mobile"> <on event="start"> <event-listener class="com.umpay.workflow.jbpm.listener.CheckMobileListener"> <field name="online"> <string value="Check mobile number..."/> </field> </event-listener> </on> <transition g="-146,-6" name="to decide check mobile" to="decide check mobile result"/> </state> <decision g="337,435,48,48" name="decide check mobile result"> <handler class="com.umpay.workflow.jbpm.decision.CheckMobileDecision" /> <transition g="-98,-21" name="to do transaction" to="do transaction"/> <transition g="-39,9" name="to error" to="error"/> </decision> <state g="217,516,112,52" name="do transaction"> <on event="start"> <event-listener class="com.umpay.workflow.jbpm.listener.DoTransactionListener"> <field name="operation"> <string value="Do transaction..."/> </field> </event-listener> </on> <transition g="-101,-17" name="to last decision" to="last decision"/> </state> <decision g="312,599,48,48" name="last decision"> <handler class="com.umpay.workflow.jbpm.decision.DoTransactionDecision" /> <transition g="-41,-17" name="to end" to="end"/> <transition g="-41,-1" name="to error" to="error"/> </decision> <end-error g="475,675,48,48" name="error"/> <end g="242,675,48,48" name="end"> <on event="start"> <event-listener class="com.umpay.workflow.jbpm.listener.ShutdownHookListener"> <field name="saveThings"> <string value="S:shutdown..."/> </field> </event-listener> </on> </end> </process>
有关流程定义中相关元素的说明,可以参考jBPM-4.4用户指南,不再累述。
我们将<event-listener>对应的处理类放到包com.umpay.workflow.jbpm.listener里面,对应的实现类,分别如下所示:
package com.umpay.workflow.jbpm.listener; import org.jbpm.api.listener.EventListener; import org.jbpm.api.listener.EventListenerExecution; public class StartupListener implements EventListener { String status; public void notify(EventListenerExecution execution) { System.out.println("StartupListener->status = " + status); } }
package com.umpay.workflow.jbpm.listener; import org.jbpm.api.listener.EventListener; import org.jbpm.api.listener.EventListenerExecution; public class InitializationListener implements EventListener { String initialized; public void notify(EventListenerExecution execution) { System.out.println("InitializationListener->initialized = " + initialized); } }
package com.umpay.workflow.jbpm.listener; import org.jbpm.api.listener.EventListener; import org.jbpm.api.listener.EventListenerExecution; public class CheckUserListener implements EventListener { String state; public void notify(EventListenerExecution execution) { System.out.println("CheckUserListener->state = " + state); } }
package com.umpay.workflow.jbpm.listener; import org.jbpm.api.listener.EventListener; import org.jbpm.api.listener.EventListenerExecution; public class CheckMobileListener implements EventListener { String online; public void notify(EventListenerExecution execution) { System.out.println("CheckMobileListener->online = " + online); } }
package com.umpay.workflow.jbpm.listener; import org.jbpm.api.listener.EventListener; import org.jbpm.api.listener.EventListenerExecution; public class DoTransactionListener implements EventListener { String operation; public void notify(EventListenerExecution execution) { System.out.println("DoTransactionListener->operation = " + operation); } }
package com.umpay.workflow.jbpm.listener; import org.jbpm.api.listener.EventListener; import org.jbpm.api.listener.EventListenerExecution; public class ShutdownHookListener implements EventListener { String saveThings; public void notify(EventListenerExecution execution) { System.out.println("ShutdownHookListener->saveThings = " + saveThings); } }
我们把<decision>的<handler>处理类放在com.umpay.workflow.jbpm.decision包里面,上面流程对应的处理类如下所示:
package com.umpay.workflow.jbpm.decision; import org.jbpm.api.jpdl.DecisionHandler; import org.jbpm.api.model.OpenExecution; public class StartDecision implements DecisionHandler { public String decide(OpenExecution execution) { System.out.println("StartDecision<- /"to check user/""); return "to check user"; } }
package com.umpay.workflow.jbpm.decision; import org.jbpm.api.jpdl.DecisionHandler; import org.jbpm.api.model.OpenExecution; public class CheckUserDecision implements DecisionHandler { public String decide(OpenExecution execution) { System.out.println("CheckUserDecision<- /"to check mobile/""); return "to check mobile"; } }
package com.umpay.workflow.jbpm.decision; import org.jbpm.api.jpdl.DecisionHandler; import org.jbpm.api.model.OpenExecution; public class CheckUserDecision implements DecisionHandler { public String decide(OpenExecution execution) { System.out.println("CheckUserDecision<- /"to check mobile/""); return "to check mobile"; } }
package com.umpay.workflow.jbpm.decision; import org.jbpm.api.jpdl.DecisionHandler; import org.jbpm.api.model.OpenExecution; public class DoTransactionDecision implements DecisionHandler { public String decide(OpenExecution execution) { System.out.println("DoTransactionDecision<- /"to end/""); return "to end"; } }
下面,是我们测试上述流程执行的用例,直接使用jBPM封装的JUnit测试库,测试代码如下所示:
package com.umpay.workflow.jbpm.process; import org.jbpm.api.Execution; import org.jbpm.api.ProcessInstance; import org.jbpm.test.JbpmTestCase; public class MyProcessTest extends JbpmTestCase { String deploymentId; protected void setUp() throws Exception { super.setUp(); deploymentId = repositoryService .createDeployment() .addResourceFromClasspath( "com/umpay/workflow/jbpm/process/process.jpdl.xml") .deploy(); } protected void tearDown() throws Exception { repositoryService.deleteDeploymentCascade(deploymentId); super.tearDown(); } public void testMyProcess() { // start a process instance ProcessInstance processInstance = executionService .startProcessInstanceByKey("MyExample"); // state : check user assertEquals("check user", processInstance.findActiveActivityNames() .iterator().next()); Execution execution = processInstance .findActiveExecutionIn("check user"); // state : check mobile processInstance = this.executionService.signalExecutionById(execution .getId()); execution = processInstance.findActiveExecutionIn("check mobile"); assertEquals("check mobile", processInstance.findActiveActivityNames() .iterator().next()); // state : do transaction processInstance = this.executionService.signalExecutionById(execution .getId()); execution = processInstance.findActiveExecutionIn("do transaction"); assertEquals("do transaction", processInstance .findActiveActivityNames().iterator().next()); processInstance = this.executionService.signalExecutionById(execution .getId()); assertEquals(true, processInstance.findActiveActivityNames().isEmpty()); // ended assertEquals(Execution.STATE_ENDED, processInstance.getState()); } }
上述流程的执行,是通过测试类来控制的。每次执行到一个活动(<state>元素对应的),需要手动ExecutionService服务的signalExecutionById()方法来发送一个信号,推进流程实例的向前执行,最终执行到<end>活动,流程结束。
如果配置没有问题的话,并且使用jBPM默认的配置,则会使用HSQLDB内存数据库来存储流程数据。当然,我们也可以根据自己的需要修改配置,使用其他的Hibernate支持数据库来存储流程数据。