第10章流程建模

10.1. 概述

流程定义代表业务流程的正式规范并且基于有向图。图由节点和转换组成。图中的每个节点指定类型。节点类型定义运行时行为。一个流程定义绝对有一个开始状态。
令牌(token)是一个执行路径。一个令牌是维护图中一个节点指针的运行时概念。
流程实例是一个流程定义的执行。当一个流程实例被创建时,令牌为主执行路径创建。这个令牌叫做流程实例的根令牌并且它被放在流程定义的开始状态上。
Signal指示一个令牌继续图执行。当收到一个未命名的signal时,领先将离开它的当前节点通过缺省的离开转换。当在signal中指定一个被命名的转换时,节点将通过指定的转换离开当前节点。Signal让流程实例分派到根令牌。

在令牌进入节点后,这个节点被执行。节点自己负责图执行连续(continuation of the graph execution)。图执行连续完成后使令牌离开这个节点。每个节点类型为图执行连续实现一个不同的行为。不传播执行的节点将成为状态节点。

动作(Actions)是在流程执行里的事件上被执行的java代码片段。图是一个关于软件需要的重要沟通工具。图仅是正开发软件的是一个视图(投影)。它隐藏了许多的技术细节。动作是在图形表示外面增加技术细节的一个机制。一旦这个图放在这个位置,它可以被动作修饰。主要事件类型包含进入节点、离开节点和取得转换。

10.2. 流程图

流程定义的基础是由节点和转换组成的图。那信息被表达在一个叫prcessdefinition.xml的xml文件中。每个节点都有一个类型,如状态、决策、分支、合并等等,每个节点都有一系列的离开转换。为了区分开他们可以给转换一个名称。例如:下面的图显示的是jBAY拍卖流程的流程图:

图 10-1 拍卖流程图

下面是用使用xml表示的jBay的拍卖流程图:
<process-definition>
<start-state>

<transition to="auction" />

</start-state>

<state name="auction">

<transition name="auction ends" to="salefork" />

<transition name="cancel" to="end" />

</state>

<fork name="salefork">

<transition name="shipping" to="send item" />

<transition name="billing" to="receive money" />

</fork>

<state name="send item">

<transition to="receive item" />

</state>

<state name="receive item">

<transition to="salejoin" />

</state>

<state name="receive money">

<transition to="send money" />

</state>

<state name="send money">

<transition to="salejoin" />

</state>

<join name="salejoin">

<transition to="end" />

</join>

<end-state name="end" />

</process-definition>

10.3. 节点

一个流程图由节点和转换组成。更多的关于图和它的执行模型的信息,参考第4章 面向图的程序设计。

每个节点有一个给定的类型。节点类型决定了在运行时当一个执行到达节点时将发生什么事情。你可以使用jBPM已经实现的一系列的节点类型。也许,你可以写自定义的代码来实现你自己的特定的节点行为。

10.3.1. Node职责

·           1、不传播执行。那样的话这个节点相当于等待状态。

·           2、通过节点的离开转换中的一个来传播执行。这就意味着最初到达节点的令牌(token)使用API调用executionContext.leaveNode(String)方法通过其中的一个离开转换。这个节点将扮演一个自动节点,从某种意义上说,它可以执行一些定制的程序逻辑并且而后不用等待自动地继续流程执行。

·           3、创建新的执行路径。一个节点决定创建新的令牌。每个新令牌代表一个新的执行路径并且每个新令牌可以通过节点的离开转换被启动。这种行为相当的例子就是一个分支(fork)节点。

·           4、结束执行路径。节点能够决定执行路径的终点。那意味着令牌被结束并且执行路径被完成。

·           5、通常,节点可以修改整个流程实例的运行时结构。运行时结构是包含令牌树的一个流程实例。节点能够被创建并结束令牌、在图的一个节点上设置令牌以及通过转换启动令牌。

jBPM包含(像任何工作流和BPM引擎一样)一系列预实现的有明确的文档化配置和行为的节点类型。但关于jBPM和面向图的程序设计基础的唯一的事情是我们为开发人员展现了这样的模型。开发人员可以非常容易地写他们自己的节点行为以及在流程中使用它。

传统工作流和BPM系统更加封闭。他们通常提供一套固定的节点集合(叫流程语言)。它们的流程语言是封闭的并且执行模型是隐藏在运行时环境中。工作流模型的研究已经显示出任何的流程语言都不是足够强大的。我们选定了一个简单的模型并允许开发写自己的节点类型。那就是JPDL流程语言最后开放的途径。

10.3.2. task-node节点类型

10.3.3. state节点类型

10.3.4. decision节点类型

At runtime the decision node will FIRST loop over its leaving transitions THAT HAVE a condition specified. It will evaluate those transitions first in the order as specified in the xml. The first transition for which the conditions resolves to 'true' will be taken. If all transitions with a condition resolve to false, the default transition (the first in the XML) is taken.

Another approach is to use an expression that returns the name of the transition to take. With the 'expression' attribute, you can specify an expression on the decision that has to resolve to one of the leaving transitions of the decision node.

当决策被外部方(意思是:不是流程定义的部分)处理时,你应该使用多个转换离开一个状态或等待状态节点。然后离开转换能够被等待状态完成后恢复执行的外部的触发器提供。例如:Token.signal(String transitionName)和TaskInstance.end(String transitionName)。

10.3.5. fork节点类型

10.3.6. join节点类型

10.3.7. node节点类型

10.4. 转换

转换能够可选的来命名。注意jBPM的大部分属性依赖转换的命名的唯一性。如果有多个转换有相同的名称,第一个命名的转换将被处理。万一多个重复转换名称占用一个节点,方法Map getLeavingTransitionsMap()返回的元素要比List getLeavingTransitions()少。

10.5. 动作

动作(actions)是在流程执行里的事件上执行的java代码片段。图是关于软件需求沟通上一个重要的工具。而且图正好也是将要被开发的软件的一个视图(项目)。它隐藏了许多的技术细节。动作是在图形化表示外面增加技术细节的一个机制。一旦图放在那里,它可以被动作修饰。这就意味着在不改变图的结构的情况下可以让java代码同图关联起来。主要事件类型是进入节点(entering a node)、离开节点(leaving a node)和处理转换(taking a transition)。

注意下动作放在事件和放在节点上的不同。动作放在事件上当事件被触发时执行。事件上的动作没有办法去影响流程的控制流。它同观察者模式(observer pattern)很相似。另一方面,放置在节点上的动作有责任来传播执行。

图 10-2 数据库更新动作

public class RemoveEmployeeUpdate implements ActionHandler {

public void execute(ExecutionContext ctx) throws Exception {

// 从流程变量上取得被操作的员工

String firedEmployee = (String) ctx.getContextInstance().getVariable("fired employee");

// 得到同jbpm更新使用的一样的同一个数据库连接,我们为我们的数据库更新
// 重用jbpm的事务
Connection connection = ctx.getProcessInstance().getJbpmSession().getSession().getConnection();

Statement statement = connection.createStatement();

statement.execute("DELETE FROM EMPLOYEE WHERE ...");

statement.execute();

statement.close();

}

}

<process-definition name="yearly evaluation">

...

<state name="fire employee">

<transition to="collect badge">

<action class="com.nomercy.hr.RemoveEmployeeUpdate" />

</transition>

</state>

<state name="collect badge">

...

</process-definition>

10.5.1. 动作配置

10.5.2. 动作引用

10.5.3. 事件

10.5.4. 事件传播

10.5.5. 脚本

脚本(script)是一个动作执行的beanshell脚本。更多的关于beanshell的信息,请看beanshell网站。缺省情况下,所有流程变量可以当作脚本变量使用而且不会有脚本变量被写入流程变量中。下面的脚本变量是可用的:

  • executionContext
  • token
  • node
  • task
  • taskInstance
<process-definition>

<event type="node-enter">

<script>

System.out.println("this script is entering node "+node);

</script>

</event>

...

</process-definition>
为了定制缺省的加载行为了存储变量到脚本中,变量元素可以被用作脚本的子元素。那样的话,脚本表达式也会放进脚本的子元素:expression中。
<process-definition>

<event type="process-end">

<script>

<expression>

a = b + c;

</expression>

<variable name='XXX' access='write' mapped-name='a' />

<variable name='YYY' access='read' mapped-name='b' />

<variable name='ZZZ' access='read' mapped-name='c' />

</script>

</event>

...

</process-definition>
在脚本开始之前,流程变量YYY和ZZZ分别作为脚本变量b和c来用。在脚本完成后,脚本变量的值a被存储进流程变量XXX中。
如果访问变量属性包含“read”,那么流程变量将在脚本计算前作为脚本变量被加载。如果访问属性包含“write”,那么脚本变量将在计算后作为流程变量被存储。属性mapped-name能够让流程变量以脚本中的另一个名称来使用。这样可以很方便当你的流程变量命名中包含空格或其他的无效脚本字符(script-literal-characters)时。

10.5.6. 定制事件

注意也可能在流程执行期间触发你自自己的事件。事件通过图的组成元素(节点、转换流程定义和超级状态是图元素)以及事件类型(java.lang.String)唯一地定义。jBPM为节点、转换和其他的图元素定义一系列的触发事件。在动作中、自定义的节点实现中或甚至流程执行的外面,你可以调用GraphElement.fireEvent(String eventType, ExecutionContext executionContext);。事件类型的名称可以被自由的选择。

10.6. 超级状态

超级状态(superstate)是一组节点。超级状态可以递归地嵌套。超级状态常用来指出一些流程定义中的层次。例如:一个应用能够组合流程的所有节点成为了阶段。动作同超级状态事件相关联。结果是令牌可以在一个给定的时间被多重嵌套节点里。这是很方便的去检查是否流程执行在开始(start-up)阶段。在jBPM模型中,你可以在超级状态中自由地组合的任何节点集。

10.6.1. 超级状态转换

所有的转换离开一个超级状态都能够被超级状态所包含的节点里的令牌处理。转换也能到达超级状态。那样的话,令牌将重定位超级状态的第一个节点。超级状态外面的节点有转换直接地到内部节点。而且,与之相反,超级状态内部节点有转换到外部节点或到超级状态自身。超级状态也可以有自己的引用。

10.6.2. 超级状态事件

超级状态有两个唯一的事件:超级状态进入(superstate-enter)和超级状态离开(superstate-leave。这些事件都将被触发无论是通过各自的节点进入或离开转换。只要令牌在超级状态的内部处理转换,这些事件就不会被触发。
注意我们已经为状态和超级状态创建了独立的事件类型。这就使它变得容易了,区分从超级状态内部传播出的超级状态事件和节点事件。

10.6.3. 分层命名

节点名称在它们的范围内必须是唯一的。节点的范围是它的节点集合(node-collection)。流程定义和超级状态都是节点的集合。为了在超级状态中引用节点,你必须指定相对、正斜线(/)分隔的名称。斜线分隔节点名称。使用“..”引用上级。下个例子显示了如何在超级状态中引用一个节点:
<process-definition>

...

<state name="preparation">

<transition to="phase one/invite murphy"/>

</state>

<super-state name="phase one">

<state name="invite murphy"/>

</super-state>

...

</process-definition>
下个例子显示了如何建立超级状态的级别。
<process-definition>

...

<super-state name="phase one">

<state name="preparation">

<transition to="../phase two/invite murphy"/>

</state>

</super-state>

<super-state name="phase two">

<state name="invite murphy"/>

</super-state>

...

</process-definition>

10.7. 异常处理

jBPM异常处理机制只应用于java异常。图执行在它自己上面不会导致问题。它只是能够导致异常的代理类(delegation classes)的执行。
在流程定义、节点和转换上,指定了一列异常处理(exception-handlers)。每个异常处理有一列动作。当在代理类中发生异常时,这个流程元素的父亲层次会搜索一个合适的异常处理。当它被找到后,异常处理的动作被执行。
注意jBPM的异常处理机制同java的异常处理不完全相似。在java中,一个被捕捉的异常对控制流会有影响。就jBPM来说,控制流不能通过jBPM异常处理机制来改变。异常要么被捕获要么没有。没有被捕获的异常被抛出到客户端(例如:调用token.signal()的客户端),要么异常就被jBPM异常处理捕获。对于捕获的异常,图执行继续就像没有异常一样。

注意在一个处理异常的动作里,它可能使用Token.setNode(Node node)方法来放置这个令牌在图的任意一个节点上。

10.8. 流程组成

流程组成借助流程状态(process-state)的在jBPM中被支持。流程状态是一个同另一个流程定义关联的状态。当图执行到达流程状态时,一个子流程的新流程实例被创建并且同在流程状态上到达的执行路径相关联。超级流程(super process)的执行路径将等待直到子流程实例已经结束。当子流程实例结束时,超级流程执行路径将离开流程状态并继续超级流程里的图执行。

<process-definition name="hire">

<start-state>

<transition to="initial interview" />

</start-state>

<process-state name="initial interview">

<sub-process name="interview" />

<variable name="a" access="read,write" mapped-name="aa" />

<variable name="b" access="read" mapped-name="bb" />

<transition to="..." />

</process-state>

...

</process-definition>

这个hire流程包含一个产生interview流程的流程状态。当执行到达“first interview”时,一个 interview流程的新的执行(=process instance)被创建。如果没有明确版本被指定,当部署hire流程时已知子流程的最新版本将被使用。为了让jBPM实例化一个特定版本,可选的版本属性可以被指定。为了延迟绑定指定的或最新的版本直到真正创建子流程时,可选的绑定属性应该被设置为late。然后hire流程的变量“a”被复制进入interview流程的变量“aa”中。同样的方法,hire流程的变量“b”被复制进入interview流程的变量“bb”中。当interview流程完成时,只有interview流程的变量“aa”被复制回hire流程的变量“a”中。

通常,当一个子流程开始时,所有的读访问(read access)变量从超级流程中读取并在signal被给予离开开始状态前输入新创建的子流程中。当子流程实例被完成时,所有的写访问(write access)变量将从子流程变量复制到超级流程中。变量元素的映射名称(mapped-name)属性允许你去指定应该在子流程中使用的变量名称。

10.9. 定制节点行为

在jBPM中,它是非常容易的去写你自定义和节点。对于创建自定义节点,一个ActionHandler的实现已经被写完,这个实现可以执行任何的业务逻辑,但也负责去传播图执行。让我们看一个更新ERP系统的例子。我们将从ERP系统中读一个数量,增加一个存储在流程变量中的数量然后再存这个结果回到ERP系统中。基于数量的大小,我们不得不通过“小额”和“大额”离开转换离开这个节点。

图 10-3 更新ERP例子的流程片段

public class AmountUpdate implements ActionHandler {

public void execute(ExecutionContext ctx) throws Exception {

// 业务逻辑
Float erpAmount = ...从ERP系统中获取数量...;

Float processAmount = (Float) ctx.getContextInstance().getVariable("amount");

float result = erpAmount.floatValue() + processAmount.floatValue();

...update erp-system with the result...;

// 图执行传播
if (result > 5000) {

ctx.leaveNode(ctx, "big amounts");

} else {

ctx.leaveNode(ctx, "small amounts");

}
}
}

它也可能创建并合并令牌在定制的节点实现里。就如何做这个的例子,到jbpm源代码检出Fork和Join节点实现吧 :-)。

10.10. 图执行

图 10-4 图执行的相关方法

当令牌是在一个节点上时,信号能够被送到令牌上。发送一个信号是一个开始执行的指令。一个信号因此必须指定令牌的当前节点的离开转换。第一个转换是缺省的。在一个信号到达令牌上,令牌处理它的当前节点并调用Node.leave(ExecutionContext,Transition)方法。认为ExecutionContext是令牌因为在ExecutionContext中的主要对象是一个令牌。Node.leave(ExecutionContext,Transition)方法将触发转换事件并在转换的目标结点上调用Node.enter(ExecutionContext)方法。那个方法将触发节点进入事件并且调用 Node.execute(ExecutionContext)方法。每一节点类型都有它自己的在execute方法中实现的行为。每一个节点通过再次调用Node.leave(ExecutionContext,Transition)方法负责传播图执行。综上所述:

10.11. 事务划分

同样的解释在10.10 图执行部分和第4章 面向图的程序设计,jBPM在客户端线程中运行流程而且天生就是同步的。那意味着token.signal()或taskInstance.end()当流程已经进入新的等待状态时将只是返回。

我们这里描述的jPDL属性是来自第15章 异步连续的建模视图。

...
<start-state>

<transition to="one" />

</start-state>

<node async="true" name="one">

<action class="com...MyAutomaticAction" />

<transition to="two" />

</node>

<node async="true" name="two">

<action class="com...MyAutomaticAction" />

<transition to="three" />

</node>

<node async="true" name="three">

<action class="com...MyAutomaticAction" />

<transition to="end" />

</node>

<end-state name="end" />

...
客户端代码同流程执行的交互(开始和恢复)是同正常(同步)流程绝对相同的:

...start a transaction...

JbpmContext jbpmContext = jbpmConfiguration.createContext();

try {

ProcessInstance processInstance = jbpmContext.newProcessInstance("my async process");

processInstance.signal();

jbpmContext.save(processInstance);

} finally {

jbpmContext.close();

}
在第一个事务后,流程实例根令牌指到节点one并且一个ExecuteNodeCommandmessage被送到命令执行器。
在随后的事务里,命令执行器将从队列中读消息并执行节点one。动作可以决定是传播执行还是进入等待状态。如果动作决定传播执行,当执行到达节点two时事务将被结束,等等,等等……
海绵中的水还是可以挤的呀,昨天少少的加了一个班,完成了这章的翻译,传上来了
继续吧.....
:-)

jBPM jPDL 用户开发手册 3.2.3 - 第10章相关推荐

  1. 佳铁怎样传输程序_阿里资深开发工程师合著《Java开发手册》,影响250万程序员附pdf...

    写在前面 <码出高效: Java开发手册> 源于影响了全球250万名工程师的<阿里巴巴Java开发手册),作者静心沉淀,对Java规约内容的来龙去脉进行了全面而彻底的梳理.本书以实战 ...

  2. .NET Micro Framework开发板用户简明手册(v3.0)

    说明:前段时间已经先后发布了<.Net Micro Framework开发板用户简明手册>和< .NET Micro Framework开发板用户简明手册(v2.0)>,分别对 ...

  3. Java基础知识第二讲:Java开发手册/JVM/集合框架/异常体系/Java反射/语法知识/Java IO

    Java基础知识第二讲(Java编程规范/JVM/集合框架/异常体系/Java反射/语法知识/Java IO/码出高效) 分享在java学习及工作中,常使用的一些基础知识,本文从JVM出发,讲解了JV ...

  4. android 设置setmultichoiceitems设置初始化勾选_阿里巴巴Java开发手册建议创建HashMap时设置初始化容量,但是多少合适呢?...

    集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生. 关于HashMap,很多人都对他有一些基本的了解,比如他和hashtab ...

  5. 设置作者_阿里Java开发手册建议创建HashMap时设置初始化容量,但多少合适

    集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生. 关于HashMap,很多人都对他有一些基本的了解,比如他和hashtab ...

  6. 《AOSuite 开发手册》之AOSuite 服务端开发

    2019独角兽企业重金招聘Python工程师标准>>> <AOSuite G1开发手册>http://git.oschina.net/osworks/AOS/wikis/ ...

  7. 阿里JAVA开发手册零度的思考理解(二)

    转载请注明原创出处,谢谢! 说在前面 人生的大道上默默地走,就必须要有一盏灯亮着为你引导方向!而这盏灯抑或只是一句话,一句鼓励,一个赞美,一次承认,一次认可,一次相识一次交流-- 上篇文章:阿里JAV ...

  8. 读书笔记:《HTML5开发手册》--figure、time、details、mark

    周日继续读<HTML5开发手册>,并进行Demo练习,今天主要学习四个HTML5新增的元素:figure.time.details.mark. 不学不知道,原来这些平时不注意的元素都有着很 ...

  9. BATZ,一份《Android架构开发手册》就够,已offer

    前言 今年的面试比往年要难得多,各个互联网企业对于Android岗位的要求越来越多,也越来越高,主要是初级岗位已经趋近饱和,但高级岗位又相对来说缺乏,这类的人才偏少,因此作为Android开发人员,我 ...

最新文章

  1. 史上最全开源中文 NLP 数据集:包括10大类、142条数据源,总有你钟意的那一款!...
  2. 没有c语言基础可以学python吗-学习Python之前需要先学习一下c语言吗?
  3. 九、二手信息站点后台完成 (IVX 快速开发教程)
  4. android刷新时的圆形动画_Android自定义加载圈动画效果
  5. SQL那些事儿(八)--oracle用户、表、表空间之间的关系
  6. Excel文件内容比对 -- Java Apache Poi
  7. 超高度近视合并白内障患者如何重返年轻优视力
  8. PopupWindow 监听返回键
  9. String Shifting(今日头条2017秋招真题)
  10. 123456789 往这串数字里插入3个乘号,使得结果最大
  11. Excel-VBA:“银行家舍入” 与“国际标准的四舍五入”
  12. 主平台对接多个系统,系统表的性能和对接方案
  13. Android 关于系统应用添加一键拨号
  14. 【数据结构功法】第2话 · 一篇文章带你彻底吃透·算法复杂度
  15. ue4-runtime_ubuntu_docker_使用教程方法
  16. Group by 后面直接加数字
  17. [转]SaaS风暴:中国软件企业如何应对挑战?
  18. Linux文件系统预读的情景分析
  19. css-alert-demo
  20. Tikadpro分享 | 如何广告投放和管理优化

热门文章

  1. 详解CSS——display各个属性值(带例子)
  2. windows文件保护_专业数据资料文件恢复软件
  3. myyearbook分析
  4. 跨境电商亚马逊运营英语?亚马逊的优势有哪些
  5. 【运营小卖部】hr喜欢的运营简历模板
  6. PAT A 1002,最后一个格式错误
  7. 查看网络适配器的名称
  8. 程序员如何追女孩(转帖)
  9. 【每日刷题3.19】2道算法+1道真题+10道面试 - 阿V
  10. Photoshop入门与进阶实例:4.3 图像幻觉