String firedEmployee = (String)
ctx.getContextInstance().getVariable(\
// by taking the same database connection as used for the jbpm updates, we
// reuse the jbpm transaction for our database update. Connection connection =
ctx.getProcessInstance().getJbpmSession().getSession().getConnection();
Statement statement = connection.createStatement();
statement.execute(\ statement.execute(); statement.close(); } }
...
9.5.1 动作配置
有关在processdefinition.xml中怎样对你定制的动作添加配置以及如何指定配置的更多信息,请参考“16.2.3配置委托”TODO。
9.5.2 动作引用
动作可以指定名称,命名的动作可以在其他需要指定动作的地方来引用,命名的动作可以作为子元素被放入流程定义中。
这个特性在你想限制动作重复配置时非常有用(例如,当动作的配置复杂时)。另外一个用处就是执行或调度运行时动作。
9.5.3 事件
事件指定了流程执行中的时刻。Jbpm引擎在图执行期间会激活事件,这发生在Jbpm计算下一个状态时(请参阅:处理信号)。事件总是同流程定义中的元素相关,例如流程定义中的
一个节点或转换。大多流程元素可以激活不同类型的事件,例如节点可以激活一个node-enter事件和一个node-leave事件。事件是同动作挂钩的,每个事件有一个动作清单,当Jbpm引擎激活事件时,清单中的动作被执行。
9.5.4 事件传播
超状态在流程定义的元素之间生成一个父-子关系,节点和转换被包含在作为父的超状态里,最顶级的元素以流程定义作为父,流程定义没有父。当一个事件被激活,事件将被向上传播至父层次,这允许在一个中心位置可以捕获到流程中的所有事件以及与事件相关联的动作。
9.5.5 脚本
脚本是动作执行的beanshell脚本,关于beanshell的更多信息,请参考beanshell站点。默认情况下,所有的流程变量可作为脚本变量和非脚本变量被写到流程变量中使用。以下脚本变量也可被使用:
l executionContext l token l node l task
l taskInstance
System.out.println(\ ...
variable元素可以作为脚本的子元素,用来定制默认的加载和存储变量到脚本的行为。如果是那样的话,脚本表达式还必须被放入脚本的子元素expression内。
...
在脚本开始之前,流程变量YYY和ZZZ分别作为脚本变量b和c将会被脚本所使用,脚本结束之后,脚本变量a的值被存储到流程变量XXX中。
如果变量的access属性包含“read”,则流程变量在脚本计算前作为脚本变量被加载;如果access属性包含“write”,则在脚本计算后脚本变量将被作为流程变量存储。属性
mapped-name可以使流程变量在脚本中以另外一个名字使用,当你的流程变量包含空格或其他非法脚本字符时这很有用。
9.5.6 定制事件
注意,在流程执行期间激活你自己的定制事件是可能的。事件通过组合图元素(节点、转换、流程定义、超状态是图元素)和事件类型(java.lang.String)被唯一的定义。Jbpm定义了一组可由节点、转换和其他图元素激活的事件,但是作为一个用户,你可以自由的激活你自己的事件,在动作中、在你自己定制的节点执行中、或者甚至在流程实例执行之外,你都可以调用GraphElement.fireEvent(String eventType, ExecutionContext executionContext),事件类型的名称可以自由选择。
9.6 超状态(Superstates)
超状态是一组节点,超状态可以被递归嵌套。超状态可以被用来在流程定义中产生一些层次,例如,一个应用可能要把流程中的所有节点按阶段进行分组。动作可以与超状态事件关联,结果就是一个令牌在某个给定时间可以存在于多个嵌套的节点,这便于检查流程是否执行,比如,是否在启动阶段。在Jbpm模型中,你可以任意分组任何节点到一个超状态。
9.6.1 超状态转换
所有离开超状态的转换都可以被包含在超状态的节点里的令牌使用,转换也可以到达超状态,如果那样的话,令牌将被重定向到超状态中的第一个节点。超状态外部的节点可以拥有指向超状态内部的转换,同样,相反的,超状态内部的节点也可以拥有指向超状态外部或超状态自己的转换。超状态还可以拥有对它自己的引用。
9.6.2 超状态事件
有两个只有超状态才有的事件:superstate-enter和superstate-leave。无论通过哪个转换进入或离开节点,这些事件都会被激活。在超状态内部令牌执行转换时,这些事件不会被激活。
9.6.3 分级命名
节点在它的范围之内必须被唯一命名,节点的范围是它自己的节点集合,流程定义和超状态都是节点集合。在指向超状态内部节点时,你必须指定相对关系,用(/)隔开节点名称,用“..”指向上一层次。下面的例子展示了怎样指向一个超状态内部的节点:
下面的例子展示了怎样向上指向超状态层次: 9.7 异常处理 Jbpm的异常处理机制仅仅集中于java异常,图本身的执行不会导致问题,只有在执行委托类时才会导致异常。 在流程定义(process-definitions)、节点(nodes)和转换(transitions)上,可以指定一个异常处理(exception-handlers)清单,每个异常处理(exception-handler)有一个动作列表,当在委托类中发生异常时,会在流程元素的父层次搜索一个适当的异常处理(exception-handler),当它被搜索到,则异常处理(exception-handler)的动作将被执行。 注意,Jbpm的异常处理机制与java异常处理不完全相似。在java中,一个捕获的异常可以影响控制流,而在Jbpm中,控制流不会被Jbpm异常处理机制所改变。异常要么被捕获,要么不捕获,没有被捕获的异常被抛向客户端(例如客户端调用token.signal()),而被捕获的异常则是通过Jbpm的exception-handler,对于被捕获的异常,图执行仍会继续,就像没有异常发生一样。 注意,在处理异常的动作中,可以使用Token.setNode(Node node)把令牌放入图中的任何节点。 9.8 流程组合 在Jbpm中依靠process-state来支持流程的组合。process-state是与另外一个流程定义关联的状态,当图执行到达process-state,一个新的子流程实例被创建,并且它与到达process-state的执行路径相关联,超流程的执行路径将会等待,直到子流程实例结束。当子流程实例结束时,超流程的执行路径将离开process-state并在超流程中继续图的执行。 这个“hire”流程包含一个产生“interview”流程的process-state,当执行到达“initial interview”,最新版本的“interview”流程的一个新的执行(相当于流程实例)被创建,然后来自“hire”流程的变量“a”被拷贝到来自“interview”流程的变量“aa”,同样,“hire”流程的变量“b”被拷贝到“interview”流程的变量“bb”。当“interview”流程结束时,只有“interview”流程的变量“aa”被拷贝回“hire”流程的变量“a”。 通常,当一个子流程被启动,在离开开始状态的信号被发出之前,所有拥有“read”存取属性的变量都被从超流程载入新创建的子流程;当子流程结束时,所有拥有“write”存取属性的变量都被从子流程拷贝到超流程。variabled元素的mapped-name属性允许你指定在子流程中将使用的变量名称。 9.9 定制节点行为 在Jbpm中很容易编写你自己的定制节点。为了创建定制节点,ActionHandler的一个实现必须被编写,这个实现可以执行任何业务逻辑,也必须包括传播图执行的职责。让我们看一个更新ERP系统的例子:我们将会从ERP系统中读取一个数量,然后加上一个存储在流程变量中的数量,再把结果存储回ERP系统;基于数量的大小,我们必须通过“small amounts”或“big amounts”转换离开节点。 图 9.3 更新erp流程示例片断 public class AmountUpdate implements ActionHandler { public void execute(ExecutionContext ctx) throws Exception { // business logic Float erpAmount = ...get amount from erp-system...; Float processAmount = (Float) ctx.getContextInstance().getVariable(\ float result = erpAmount.floatValue() + processAmount.floatValue(); ...update erp-system with the result...; // graph execution propagation if (result > 5000) {