jBPM是由JBoss开发的工作流和业务流程管理引擎,可以用于创建不同人、不同应用程序、不同服务之间交互的业务流程。jBPM还提供了一个可视化的业务流程设计器。jBPM包含下列组件:运行时引擎(一个POJO库),图形化设计器(一个Eclipse插件),基于Hibernate的持久化,基于JSF的web控制台,BPEL扩展等。
Hello World示例
流程定义是一个可管理的包含了节点和节点间交付件的流程图。Hello World示例流程包含三个节点。为了查看节点间如何相互配合,将不使用任何设计工具来定义一个简单的流程。下图显示了Hello World示例流程的流程图定义:
Hello World示例流程图
public void testHelloWorldProcess() { ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state>" + " <transition to='s' />" + " </start-state>" + " <state name='s'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>" ); ProcessInstance processInstance = new ProcessInstance(processDefinition); Token token = processInstance.getRootToken(); assertSame(processDefinition.getStartState(), token.getNode()); token.signal(); assertSame(processDefinition.getNode("s"), token.getNode()); token.signal(); assertSame(processDefinition.getNode("end"), token.getNode()); }
数据库示例
jBPM基本特性之一是能够在jBPM数据库中持久化执行过程中处于等待状态的流程。数据库示例将展示如何在jBPM数据库中存储一个流程实例。该示例可能涉及到jBPM上下文。为不同的用户代码创建Separate方法。举例来说,webapplication中的一段用户代码开始一个流程并在数据库中持久化。之后,一个消息驱动Bean(MDB)加载该流程实例继续执行流程。
public class HelloWorldDbTest extends TestCase { static JbpmConfiguration jbpmConfiguration = null; static { jbpmConfiguration = JbpmConfiguration.parseXmlString( "<jbpm-configuration>" + " <jbpm-context>" + " <service name='persistence' " + " factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />" + " </jbpm-context>" + " <string name='resource.hibernate.cfg.xml' " + " value='hibernate.cfg.xml' />" + " <string name='resource.business.calendar' " + " value='org/jbpm/calendar/jbpm.business.calendar.properties' />" + " <string name='resource.default.modules' " + " value='org/jbpm/graph/def/jbpm.default.modules.properties' />" + " <string name='resource.converter' " + " value='org/jbpm/db/hibernate/jbpm.converter.properties' />" + " <string name='resource.action.types' " + " value='org/jbpm/graph/action/action.types.xml' />" + " <string name='resource.node.types' " + " value='org/jbpm/graph/node/node.types.xml' />" + " <string name='resource.varmapping' " + " value='org/jbpm/context/exe/jbpm.varmapping.xml' />" + "</jbpm-configuration>" ); } public void setUp() { jbpmConfiguration.createSchema(); } public void tearDown() { jbpmConfiguration.dropSchema(); } public void testSimplePersistence() { deployProcessDefinition(); processInstanceIsCreatedWhenUserSubmitsWebappForm(); theProcessInstanceContinuesWhenAnAsyncMessageIsReceived(); } public void deployProcessDefinition() { ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition name='hello world'>" + " <start-state name='start'>" + " <transition to='s' />" + " </start-state>" + " <state name='s'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>" ); JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { jbpmContext.deployProcessDefinition(processDefinition);
} finally { jbpmContext.close(); } } public void processInstanceIsCreatedWhenUserSubmitsWebappForm() { JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { GraphSession graphSession = jbpmContext.getGraphSession(); ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition("hello world"); ProcessInstance processInstance = new ProcessInstance(processDefinition); Token token = processInstance.getRootToken(); assertEquals("start", token.getNode().getName()); token.signal(); assertEquals("s", token.getNode().getName()); jbpmContext.save(processInstance); } finally { jbpmContext.close(); } } public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() { JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext(); try { GraphSession graphSession = jbpmContext.getGraphSession(); ProcessDefinition processDefinition = graphSession.findLatestProcessDefinition("hello world"); List processInstances = graphSession.findProcessInstances(processDefinition.getId()); ProcessInstance processInstance = (ProcessInstance) processInstances.get(0); processInstance.signal(); assertTrue(processInstance.hasEnded()); jbpmContext.save(processInstance); } finally { jbpmContext.close(); } } }
上下文示例:流程变量
流程变量包含了流程执行期间的上下文信息。流程变量类似一个java.util.Map类型的名称/值对,并且是java对象。流程变量是流程实例的组成部分。以免事件复杂化,该示例仅仅演示处理流程变量的API,没有包括持久化处理。
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition>" + " <start-state>" + " <transition to='s' />" + " </start-state>" + " <state name='s'>" + " <transition to='end' />" + " </state>" + " <end-state name='end' />" + "</process-definition>" );
ProcessInstance processInstance = new ProcessInstance(processDefinition); ContextInstance contextInstance = processInstance.getContextInstance(); contextInstance.setVariable("amount", new Integer(500)); contextInstance.setVariable("reason", "i met my deadline"); processInstance.signal(); assertEquals(new Integer(500), contextInstance.getVariable("amount")); assertEquals("i met my deadline", contextInstance.getVariable("reason"));
任务分配示例
任务分配示例演示如何给用户分配任务。因为分离jBPM工作流引擎和组织模型,处理参与者的表现语言始终受到很多限制。因此,你必须实现一个包含处理任务参与者的任务分配器。
public void testTaskAssignment() { ProcessDefinition processDefinition = ProcessDefinition.parseXmlString( "<process-definition name='the baby process'>" + " <start-state>" + " <transition name='baby cries' to='t' />" + " </start-state>" + " <task-node name='t'>" + " <task name='change nappy'>" + " <assignment class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' />" + " </task>" + " <transition to='end' />" + " </task-node>" + " <end-state name='end' />" + "</process-definition>" ); ProcessInstance processInstance = new ProcessInstance(processDefinition); Token token = processInstance.getRootToken(); token.signal(); assertSame(processDefinition.getNode("t"), token.getNode()); TaskInstance taskInstance = (TaskInstance)processInstance .getTaskMgmtInstance() .getTaskInstances() .iterator().next(); assertEquals("papa", taskInstance.getActorId() ); taskInstance.end(); assertSame(processDefinition.getNode("end"), token.getNode()); }