jbpm学习笔记(七) fork-join活动详解以及示例,对处理流程的一点想法

   今天继续学习jbpm活动元素之 fork-join(分支/聚合活动)

   当我们需要流程并发(concurrency)执行的时候,就需要使用到fork-join活动组合,fork活动可以使流程在一条主干上出现并行的分支,join活动则可以使流程的并行分支聚合成一条主干。
Fork活动仅具有jbpm活动的最基本特征,即具有1个name属性和n个流出转移元素。
相关jpdl如下:
<?xml version="1.0" encoding="UTF-8"?>

<process name="forkAndJoin" xmlns="http://jbpm.org/4.4/jpdl">
	<start>
		<transition to="fork" />
	</start>

	<!-- 流程在此产生 3个并行的分支 -->
	<fork name="fork">
		<transition to="pingpang" />
		<transition to="football" />
		<transition to="basketball" />
	</fork>

   
	<state name="pingpang">
		<transition to="to playball" /><!-- 就是打一般的球 -->
	</state>

    <!-- 足球和篮球属于大球  会join到to play bigball活动上去-->
	<state name="football">
		<transition to="to play bigball" />
	</state>

	<state name="basketball">
		<transition to="to play bigball" />
	</state>
	

	<!-- 在此定义to play bigball的join活动  -->
	<join name="to play bigball">
		<transition to="play bigball" /> <!-- 开始打大球 -->
	</join>

	<state name="play bigball">
		<transition to="to playball" /><!-- 其实是一起去打普通的球 -->
	</state>
	
	
	<join name="to playball">
		<transition to="play over" /><!-- 打球马上结束了 -->
	</join>
	
	<end name="play over"/>
	
	
</process>


编写单元测试代码执行上面的流程定义

package org.test;

import java.util.HashSet;
import java.util.Set;

import org.jbpm.api.ProcessInstance;
import org.jbpm.test.JbpmTestCase;

public class ForkAndJoinTest extends JbpmTestCase {

	String deploymentId;

	@Override
	public void setUp() throws Exception {
		super.setUp();
		deploymentId = repositoryService.createDeployment()
				.addResourceFromClasspath("org/test/forkAndJoin.jpdl.xml")
				.deploy();
	}

	@Override
	public void tearDown() throws Exception {
		repositoryService.deleteDeploymentCascade(deploymentId);
		super.tearDown();
	}

	public void testForkAndJoin() {
		// 发起forkAndJoin流程实例
		ProcessInstance pi = executionService
				.startProcessInstanceByKey("forkAndJoin");
		String pid = pi.getId();

		// 构造一个活动名称集合以验证分支。设置3个分支活动的名称
		Set<String> ballsName = new HashSet<String>();
		ballsName.add("pingpang");
		ballsName.add("football");
		ballsName.add("basketball");

		// 断言当前活动即为产生的3个分支
		assertEquals(ballsName, pi.findActiveActivityNames());

		// 发出执行信号通过 "pingpang" 活动,这时候,流程会在最后的聚合活动"play"上等待其他分支的到来
		String pingpangExecuId = pi.findActiveExecutionIn("pingpang").getId();
		pi = executionService.signalExecutionById(pingpangExecuId);
		// 在活动名称集合中排除 "pingpang"活动
		ballsName.remove("pingpang");

		// 此时,仍然可以断言另外2个分支还在等待
		assertNotNull(pi.findActiveExecutionIn("football"));
		assertNotNull(pi.findActiveExecutionIn("basketball"));

		// 发出执行信号通过剩下的其中一个分支--football活动
		String footballExecuId = pi.findActiveExecutionIn("football").getId();
		pi = executionService.signalExecutionById(footballExecuId);
		// 在活动名称集合中排除 "football"活动
		ballsName.remove("football");

		// 发出执行信号通过剩下的第二个分支--basketball活动
		String basketballExecuId = pi.findActiveExecutionIn("basketball")
				.getId();
		pi = executionService.signalExecutionById(basketballExecuId);
		// 在活动名称集合中排除"basketball"活动
		ballsName.remove("basketball");

		// size应该是0
		System.out.println("ballsName.size(): " + ballsName.size());

		// 断言通过了第一个聚合活动 "to play bigball",到达了"play bigball"活动
		assertNotNull(pi.findActiveExecutionIn("play bigball"));
		
		//发出执行信号通过"play bigball"活动
		String playBigBallExecuId=pi.findActiveExecutionIn("play bigball").getId();
		pi=executionService.signalExecutionById(playBigBallExecuId);
		
		//最终的聚合活动"play over"等到了它的最后一个流入转移后,流向了end活动,所以流程实例结束
		
		//因此可以断言此流程已经不存在了.
		assertNull("execution"+pid+"应该不存在了",executionService.findExecutionById(pid));
		System.out.println("结束了");
	}

}

     Fork-join活动看似其实不难,但是当流程变多的时候,我感觉在写代码的时候容易弄混淆,比如,流程在某个阶段执行到哪儿了,该怎样启动下一个流程,甚至有时候感觉有的state根本不需要,不知道其他人是否这样的感觉,但是我要说的是,假如真的能够体会你自己业务的每一步骤的话,就不会出现这种混乱的思想,举个简单的例子:假如有这样一个逻辑,某一个订单在发货后,1,客户要接收,2厂家要收款。这两个活动都完成了,那么才能结束流程,首先,你应该这样去考虑它们的步骤:发订单——》客户接收——客户打钱——厂家收款——销账(完成)。假如把这个过程再细化的话,首先发完订单,客户处于待接收状态,货到后客户可以接收,就变成待打钱状态,此时厂家就处于待收款状态,厂家收款后,销账完成。而这个细化的过程即基于每个状态点(如待接收状态),然后激起流程转移的动作(如接收),使我们真正在处理流程的过程。由于篇幅原因,下一张再介绍end等活动。

你可能感兴趣的:(xml,活动,jbpm,单元测试)