打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Hello World 例子---jbpm(摘抄)

第三章. 讲座

这个讲座将展示如何建造一个jpdl和如何使用API的方法来管理运行时的执行.

这个讲座的方式是解释一系列的例子. 每个例子将集中关注特别的主题和额外的说明. 这些例子可以在jBPM包的examples目录下找到.

最好的方法就是学着来建立一个Project实验所给的例子.

eclipse 用户注意:下载jbpm-3.0-[version].zip并且解压缩到系统. 然后从菜单 "File" --> "Import..." --> "Existing Project into Workspace". 点 "Next" 然后浏览jBPM 根目录然后点击 "Finish". 现在你的有了jbpm 3 project了. 你可以发现这个讲座目录在目录 src/java.examples/... . 你打开这些例子后,可以运行它们"Run" --> "Run As..." --> "JUnit Test"

jBPM 包括一个图形设计器来产生例子中的XML. 你可以从这里下载和学习有关图形设计器的说明  节 2.1, “下载一览”

3.1. Hello World 例子

一个流程 是有一个定向图(directed graph)来定义,由节点和变换组成 . hello world 流程有3个节点.如下看如何组合起来, 我们先开始一个简单的流程不使用图形设计器. 下面的图形表示hello world 流程:

Figure 3.1.  hello world 流程图

public void testHelloWorldProcess() {        // 这个方法展现流程定义和流程执行的定义        // 流程定义有3个节点.         // 一个未命名的开始状态start-state,一个状态 's'   // 一个结束状态名字为'end'.         // 下面行解析一个xml text为一个ProcessDefinition对象(流程定义)     // ProcessDefinition 把流程定义形式描述为java对象 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>");         // 下一行建立了一个流程执行定义.         //在构造后,流程执行有一个主要的执行路径  // (=    root token 根令牌) 此时位置在start-state处ProcessInstance processInstance =new ProcessInstance(processDefinition);        // 在构造后流程执行有一个主要的执行路径// (=   roottoken 根令牌) .Token token = processInstance.getRootToken();        // 构造后, 位置处于流程定义执行路径start-state的位置assertSame(processDefinition.getStartState(), token.getNode());      // 现在开始流程执行,离开start-state 结束默认的转换(transition) token.signal();      // 这个signal方法将会阻塞直到流程执行进入 wait 状态        // 流程执行在状态's' 进入第一个 等待状态         // 因此执行主路径现在位置在 状态's' assertSame(processDefinition.getNode("s"), token.getNode());       // 我们再送另外一个信号signal. 这将继续执行离开状态's' 结束默认的转换(transition) token.signal();       // 现在信号signal方法将返回,因为流程实例到达了end-state 结束状态 assertSame(processDefinition.getNode("end"), token.getNode());}

3.2. 数据库例子

jBPM一个基本的特性是当流程处于等待状态时候可以把流程执行 永久化到数据库中 . 下一个例子想你展示了如何存储一个流程实例到jBPM数据库中. 例子给出一个将会发生的上下文.分开的方法用来建立不同部分的用户代码. 比如一部分用户代码在web 应用程序中开始一个流程并永久化执行到数据库中.然后,message drive bean从数据库中载入流程实例并继续它的执行

jBPM 永久化的更多内容可以参看  第六章, 永久化.

public class HelloWorldDbTest extends TestCase {          // 我们在每个应用程序中需要一个JbpmSessionFactory. 因此我们把它放在一个静态变量中        // JbpmSessionFactory 在test 方法中来建立一个      JbpmSession's.static JbpmSessionFactory jbpmSessionFactory =JbpmSessionFactory.buildJbpmSessionFactory();static {         // 因为HSQLDBin-memory数据库是干净的数据库,            // 在我们开始测试前,我们需要建立table.// The next line creates the database tables and foreign key // constraints. jbpmSessionFactory.getJbpmSchema().createSchema();}public void testSimplePersistence() {           // 在3个方法调用下面方法中间,所有数据被写入数据库            // 在单元测试中,这3个方法被正确执行在每个方法之后           // 因为我们想完成测试流程场景        // 但在实际中这些方法代表着server不同的请求            // 因为我们开始的数据库是个干净的数据库,我们需要首先发布流程在里面             // 在真实中,这个是由流程开发人员完成的 deployProcessDefinition();        // 假定我们想开始流程实例(= 流程执行)         // 当用户提交一个Web表单的时候.processInstanceIsCreatedWhenUserSubmitsWebappForm();        // 然后,到达的异步消息将继续执行 theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();}public void deployProcessDefinition() {//定义一个流程,包括三个及点,一个未命名的start-state,一个状态's'//一个结束状态 end-state名字'end'.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>);     // 打开新的永久层会话JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();        // 并且在永久层会话上开启事务jbpmSession.beginTransaction();      // 保存流程定义到数据库中 jbpmSession.getGraphSession().saveProcessDefinition(processDefinition);  // 提交事务jbpmSession.commitTransaction();   // 关闭会话.jbpmSession.close();}public void processInstanceIsCreatedWhenUserSubmitsWebappForm() {       // 这个方法里的代码可以放在structs action或JSF管理bean 里      // 打开一个新的永久层会话JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();        // 启动事务.jbpmSession.beginTransaction();           // 查询数据库得到我们在上面步骤发布的流程定义 ProcessDefinition processDefinition =jbpmSession.getGraphSession().findLatestProcessDefinition("hello world");         // 有了从数据库中的得到的processDefinition,                 //我们就可以建立流程执行定义比如hello world 例子(它没有永久化).ProcessInstance processInstance =new ProcessInstance(processDefinition);Token token = processInstance.getRootToken();assertEquals("start", token.getNode().getName());    // 开始流程执行token.signal();       // 流程在状态's'.assertEquals("s", token.getNode().getName());          // 流程实例被保存在数据库            // 所以当前流程执行的状态被保存进数据库  .  jbpmSession.getGraphSession().saveProcessInstance(processInstance);// The method below will get the process instance back out // of the database and resume execution by providing another // external signal.          // web应用程序动作结束出,事务被提交.jbpmSession.commitTransaction();   // 关闭jbpmSession.jbpmSession.close();}public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() {           // 这个代码可以包含在message driven bean中.     // 打开新的永久性的会话.JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();        // 永久化会话上开始事务           // 说明它也可能使用应用服务器的DataSource的JDBC连接 jbpmSession.beginTransaction();GraphSession graphSession = jbpmSession.getGraphSession();// First, we need to get the process instance back out of the database.// There are several options to know what process instance we are dealing // with here.  The easiest in this simple test case is just to look for // the full list of process instances.  That should give us only one // result.  So let's look up the process definition.ProcessDefinition processDefinition =graphSession.findLatestProcessDefinition("hello world");          // 现在,我们搜索这个流程定义的所有流程实例.List processInstances =graphSession.findProcessInstances(processDefinition.getId());// We know that in the context of this unit test there is // only one execution.  In real life, the processInstanceId can be // extracted from the content of the message that arrived or from // the user making a choice.ProcessInstance processInstance =(ProcessInstance) processInstances.get(0);// 我们可以继续执行. 说明流程实例委托信号到执行主路径(=         the root token)processInstance.signal();       // 在singal后, 我们知道流程执行应该到 end-state assertTrue(processInstance.hasEnded());           // 现在我们可以更新执行状态到数据库中graphSession.saveProcessInstance(processInstance);        // MDB结束, 事务被提交.jbpmSession.commitTransaction();    // jbpmSession被关闭.jbpmSession.close();}}

3.3. 上下文例子: 流程变量

在流程执行时候流程变量包含上下文信息. 流程变量同java.util.Map相似映射名字到值,值可能是个java对象 . 流程变量被永久化作为流程实例的一部分. 为了让事情简单,这个例子中我们仅仅展示使用变量的API而没有永久化.

关于变量的更多信息可以参看 第8章 上下文

      // 这个例子也是从hello world 流程开始.    // 甚至没有修改.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();      // 在开始之前流程离开了start-state,          // 我们准备设置一些流程变量在流程实例上下文中      .contextInstance.setVariable("amount", new Integer(500));contextInstance.setVariable("reason", "i met my deadline");        // 从现在开始,这些变量同流程实例关联         // 流程变量可以从用户代码中通过下面展示的API来访问             // 可可以在动作Action和节点的实现中访问         // 流程变量也作为流程实例的一部分保存进数据库             .processInstance.signal();      // 访问变量通过contextInstance. assertEquals(new Integer(500),contextInstance.getVariable("amount"));assertEquals("i met my deadline",contextInstance.getVariable("reason"));

3.4. 任务分派例子

在下个例子里我们将要展示你怎么才能分派一个任务给一个用户.因为jBPM工作流引擎和组织模型是分开的,一种用来计算参与者表达语言总是受限的. 因此,你不得不指定AssignmentHandler的实现来计算任务的参与者.

public void testTaskAssignment() {        // 这个流程展示基于hello world 流程.          // 状态节点被task-node代替.task-node在JPDL中是表示一个等待状态并且            // 产生一个在流程继续执行前要完成的任务 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();       // 开始流程执行,完整默认的转换后离开start-state     .token.signal();       // signal 方法将被阻塞知道流程执行进入等待状态.             // 在这个case中是指task-node.assertSame(processDefinition.getNode("t"), token.getNode());       // 当执行到达task-node, 任务'change nappy'// 被建立并且NappyAssignmentHandler 被调用来决定任务将分派给睡         //NappyAssignmentHandler 返回'papa'          // 在真实环境中, 任务将会从数据库中获取,通过or       g.jbpm.db.TaskMgmtSession.         // 因此这个例子中我们不想包括复杂的永久化          // 我们只是得到这个流程实例的第一个task-实例    (we know there is only one in this test// 我们知道在这个测试场景中这里只有一个).TaskInstance taskInstance = (TaskInstance)processInstance.getTaskMgmtInstance().getTaskInstances().iterator().next();          // 现在,我们检查taskInstance实际分配给了'papa'.assertEquals("papa", taskInstance.getActorId() );             //现在,我们期望'papa'完成了他的任务并且标记任务是完成的 taskInstance.end();            // 因为这是最后(唯一的)要做的任务,这个任务的完成触发        // 流程实例的继续执行.assertSame(processDefinition.getNode("end"), token.getNode());}

3.5. 客户化动作例子

动作action是绑定你自己的定制java代码和jBPM流程的一种机制. 动作可以同它自己的节点关联起来 (如果它们在流程图表示中相关). 动作也可以放在事件event上比如. taking a transition, leaving a node 或者 entering a node.在这个case ,动作不是图表的一部分,但是它们在流程执行产生事件的时候,也会被执行.

我们将用一个例子: MyActionHandler 来观察动作的实现.这个动作handler实现不是什么非常特别的事情.它只是设置boolean变量 isExecuted 为 true . 变量 isExecuted 是静态的因此它可以在action handler内部被访问.

关于动作action的内容可以参看  7.4节, “动作”

     // MyActionHandler 就是一个class可以在jBPM流程执行时候在某些用户代码里被执行 public class MyActionHandler implements ActionHandler {      // 在测试之前, isExecuted 被设置为      false.public static boolean isExecuted = false;       // 动作将设置true 因此 当动作被执行        // unit test 将会展示public void execute(ExecutionContext executionContext) {isExecuted = true;}}
       // 每次测试开始都要设置MyActionHandler 的成员static isExecuted 为      false.public void setUp() {MyActionHandler.isExecuted = false;}

我们将要在转换时开始一个动作

public void testTransitionAction() {// The next process is a variant of the hello world process.// We have added an action on the transition from state 's' // to the end-state.  The purpose of this test is to show // how easy it is to integrate java code in a jBPM process.ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition>" +"  <start-state>" +"    <transition to='s' />" +"  </start-state>" +"  <state name='s'>" +"    <transition to='end'>" +"      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +"    </transition>" +"  </state>" +"  <end-state name='end' />" +"</process-definition>");// Let's start a new execution for the process definition.ProcessInstance processInstance =new ProcessInstance(processDefinition);// The next signal will cause the execution to leave the start // state and enter the state 's'processInstance.signal();       // 这里将显示 MyActionHandler还没有被执行 assertFalse(MyActionHandler.isExecuted);// ... and that the main path of execution is positioned in // the state 's'assertSame(processDefinition.getNode("s"),processInstance.getRootToken().getNode());// The next signal will trigger the execution of the root // token.  The token will take the transition with the// action and the action will be executed during the  // call to the signal method.processInstance.signal();// Here we can see that MyActionHandler was executed during // the call to the signal method.assertTrue(MyActionHandler.isExecuted);}

下一个例子是同样的动作,但动作被分别放在 enter-node和 leave-node 事件 .注意节点同转换相比有超过一个事件类型(event type)转换(transition)只有一个事件.

ProcessDefinition processDefinition = ProcessDefinition.parseXmlString("<process-definition>" +"  <start-state>" +"    <transition to='s' />" +"  </start-state>" +"  <state name='s'>" +"    <event type='node-enter'>" +"      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +"    </event>" +"    <event type='node-leave'>" +"      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +"    </event>" +"    <transition to='end'/>" +"  </state>" +"  <end-state name='end' />" +"</process-definition>");ProcessInstance processInstance =new ProcessInstance(processDefinition);assertFalse(MyActionHandler.isExecuted);// The next signal will cause the execution to leave the start // state and enter the state 's'.  So the state 's' is entered // and hence the action is executed. processInstance.signal();assertTrue(MyActionHandler.isExecuted);// Let's reset the MyActionHandler.isExecuted  MyActionHandler.isExecuted = false;// The next signal will trigger execution to leave the  // state 's'.  So the action will be executed again. processInstance.signal();// Voila.  assertTrue(MyActionHandler.isExecuted);
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
第15章. TDD for workflow
DecisionExpressionTest(Jbpm)
使用fork/join的常见错误
JBPM数据库表说明 -              彬 ^_^ - BlogJava
blogjava - java神谕-在jbpm3.0指南中几个例子的剖析
jbpm4.4 Api 示例
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服