专注应用,关注发展,开拓创新

<-------------------------------------------------------------------& 珍惜生命 . 善用时间 . 把握未来 . 创造价值。

BlogJava 首页 新随笔 联系 聚合 管理
  11 Posts :: 17 Stories :: 10 Comments :: 0 Trackbacks

下面开始接触 JBPM JPDL 部分:

jpdl 参考手册中主要介绍了 processdefinition.xml 文件的格式( schema

一、 Process archive:

如前面所描述的, process archive 是商务流程的规则描述。它被打成 jar 包,通常以扩展名 .par 结束, jbpm 识别一个流程需要三种类型的文件数据:

1、   业务流程的正式声明:在 jpdl 中,是以 processdefinition.xml 文件来表达。这一章节我们就来解析这个文件的格式。

2、   设计逻辑:在流程上加上规划逻辑这些也是在 processdefinition.xml 中给予描述的,在 process archive 中可以嵌套 java-classes 。所有在 process archive 中的 classes 应该放在子目录 /classes 中。

3、   其他资源文件。作为工作流引擎的客户端,在运行时你可能想要在流程中包含一些资源文件的变量。例如。窗体( form )的描述与某人执行任务相关联。 Jbpm 不能在你想要包含在一个流程定义中的资源文件的类型上做任何手脚。

二、 version 机制(此处 versioning 可以大致理解为:一个 process archive 部署后转变成过程定义的过程。)(此部分需要参考原文理解。感觉不对劲)

作为最最基本的, jbpm 的翻译机制遵从下面原理:

l      每次 process archive 部署的时候,一个新的流程定义就在 jbpm 数据库中被创建。

l      在部署的时候, jbpm 安排一个 version 号码(数字)给过程定义。只有当过程名与被定义的号相同时候才会执行 Process archives 。为了实现安排 version 号码,如果它是第一个 version jbpm 采取 1+ (the highest version number of the current process definitions with the same name) 或者 1 。从 jbpm-api 中可以通过一个给定的 name 查找最近的过程定义。

l      在一个给定的定义执行某一个过程实例,过程实例将会(等到同个定义结束前)一直在这个定义中保持执行状态。

l      通过这种方式能通过最近定义启动过程并且在相同定义中的完整的生命周期中保持运行状态。

l      注意: jbpm 可以把一个设计的程序逻辑与一个过程相关联起来。通过在 process archive 中包含类文件, jbpm 将会对于每个过程定义把 classes 分离出来。

 

三、 Processdefinition.xml 格式

 

文档类型定义:

<!DOCTYPE process-definition PUBLIC

  "-//jBpm/jBpm Mapping DTD 2.0 beta3//EN"

  "http://jbpm.org/dtd/processdefinition-2.0-beta3.dtd">

the document type definition of processdefinition.xml

 

过程定义:

<!ELEMENT process-definition (  description?,

                                swimlane*,

                                type*,

                                start-state,

                                ( state |

                                  milestone |

                                  process-state |

                                  decision |

                                  fork |

                                  join

                                )*,

                                end-state,

                                action*  ) >

<!ATTLIST process-definition name CDATA #REQUIRED >

dtd fragment for process-definition

 

状态:

<!ELEMENT state ( description?, assignment?, action*, transition+ ) >

<!ATTLIST state name  CDATA #REQUIRED >

dtd fragment for a state

 

JBPM 中,状态( state )这个术语与 FSM (有限状态机)和 UML 状态图中有着同样的意思。

对商务流程进行建模的目的就是创建一个软件系统。我们考虑到过程定义是软件系统建立的一部分。所以 jbpm 中的状态术语是以一个软件系统的角度来解释的。

状态是 jbpm 的核心概念。在 jbpm 中当开始模仿一个流程,首要需要考虑的事情就是过程的状态。状态将成为你所设计的过程的基本框架。

以状态概念为核心的另外一个特殊原因是:状态在程序语言中没有容易重复混淆的概念。一个软件程序或者运行或者不运行。一个有代表性的商业过程都会与被分别执行的所设计的逻辑部分关联。 Jbpm 允许在相关联的程序逻辑中对状态建模。

Jpdl 也在状态之间定义了变迁,决定,分支,合并, milestone flow )。需要注意的,控制流定义在状态与状态之间。无论什么情况下,一个正常的设计逻辑是更合适的,过程开发人员就能够在一个过程事件上指定一个 action Jbpl 与其他过程定义语言如 bpel 等之间的区别之一是, jpdl 具备以状态管理方式对 java 进行扩展和与程序语言最小交叠性的能力。

委派( assignment ):

 

<ELEMENT assignment EMPTY >

<!ATTLIST assignment swimlane CDATA #IMPLIED

                     assignment (optional|required) #IMPLIED

                     authentication (optional|required|verify) #IMPLIED >

dtd fragment for an assignment

 

当一个流程执行到某种状态时候,工作流引擎将会等到一个外部的trigger(通过调用jbpmapiExecutionService.endOfState(…))。在这个方法里面,jbpm将会算出流程实例的下一个状态。

所以一个状态能够依赖于一个外部参与者。外部参与者可以是一个人也可以是某个系统。有许多种方式来实现业务流程中的状态与任务相关联。这些任务基本上可以分为两组:

1、             基于客户端的委派

在这种策略中,jbpm的用户管理他们自己用户的任务列表。在这种情况,jbpm只是用一个执行引擎来控管有限状态机。Jbpm的职责是计算并且追踪过程执行中的状态,然而客户端的职责就是确保每个人知道做了什么。然后客户端一般就是在一个给定的状态中找到过程实例(或者说tokens

2、             基于流程的委派

(在jbpm2.0 beta3之前支持这种委派策略)

在这种委派策略中,jbpm将会担负给参与者安排状态并且追踪任务列表的职责。在jbpm中,流程在执行过程中是以一个token来进行跟踪的。一个token有一个指针来指向状态和一个参与者。在jbpm中一个参与者总是引用java.lant.string。为了详细说明jbpm如何必须安排tokens给参与者们,一些事件与此相关。接下来一个一个介绍:

只要一个客户端启动一个过程实例或者发出结束状态的信号,jbpm都会计算过程实例的下一个状态。

首要的事情是关于这些api方法中的第一个参数:参与者。这个参与用来识别谁来执行。

在启动一个新的过程实例的情况下,一个root-token在开始状态中被创建好。在结束一个状态的情况下,一个tokenid需要以一个某种状态中的参数形式指定。然后,jbpm将会开始为token计算下一个新状态。为了简单起见,我们忽略并发这种情况。Token将会经历变迁和节点,然后抵达下一个状态节点。在那时,一个token需要安排一个参与者。选择一个参与者之后,jbpm将通过token和调用的方法(开始过程实例或者结束状态)的返回值进行关联选择的参与者

所以当一个状态中的token具备有一个参与者时,那就意味着过程实例的执行是在等待这个参与者提供一个外部triggerjbpm引擎。在这种情形下,过程中的状态对应一个用户的任务,jbpm通过检索所有已经安排给指定的参与者的tokens计算任务列表。现在,参与者能够从列表中选择一个token和发出结束状态信号量。

Assignmentn (委派)有许多属性:assignmentauthenticationAssingement属性可以有两个值:optionalrequiredRequired意思指当执行到某一个状态时,jbpm将会检测是否把一个token安排了一个参与者。如果非法则会抛出AssignmentException的异常。如果assingmentoptional=default),当到达一个状态时jbpm就允许离开一个未安排的token。属性authentication指定约束条件来限定哪个参与者可以发出结束状态的信号。参与者通过endOfState方法中的参数actorid来指定。如果optional=default意思指对于指定谁来担当结束状态并不是必须的。Required意味着一个参与者需要被指定。Vertify意味着结束状态只可以安排给已经安排token的参与者。

更多信息请查看群组委派。查看faqs

Swimlane

<!ELEMENT swimlane ( description?, delegation? ) >

<!ATTLIST swimlane name CDATA  #REQUIRED >

dtd fragment for swimlane

非常典型的情况,一个人具备一个流程中多个状态的职责。在 jbpm 中通过创建一个 swimlane 并且通过 swimlane 安排状态给参与者( actor )。一个业务流程中的 swimlane 可以被看做为一个针对参与者的角色名字。 Jbpm swimlane 的解释与 UML1.5 中的术语 swimlane 解释一致。首次执行到达一个状态,给定一个 swimlane ,就会算出参与者。

public interface AssignmentHandler {

  String selectActor( AssignmentContext assignerContext );

}

the AssignmentHandler interface

swimalne 中的 delegation 标签指向一个 AssignmentHandler 的具体实现。

然后那个参与者( actor )以 swimlane 中同名的方式被存储为过程变量。下次当一个 process archives 在一个状态,利用 swimlane jbpm 引擎将会检测变量并且安排 token 给参与者(存储在变量中的)

计算的结果是存储一个 swimlane 同名的过程变量。所以当下一个状态到达相同的 swimlane 时,状态就会安排给相同的 actor ,而不再用 AssignmentHandler 。因为在 swimlane 和参与者之间的关联已经存储在变量中,而且可以通过更新变量来改变 swimlane 参与者( actor )之间的关联关系。

变量和类型:

 

<!ELEMENT type ( description?, (delegation|transient), variable* ) >

<!ATTLIST type java-type CDATA #IMPLIED >

<!ELEMENT transient EMPTY >

 

<!ELEMENT variable EMPTY >

<!ATTLIST variable name CDATA #REQUIRED >

dtd fragment for type and variable

一个是变量是一种key-value对。它与过程实例(一次过程执行)相关联。Keyjava.lang.stringvalue是任何java类型的任何pojo。所以任何是java类型,即使不给jbpm知道也能被应用到变量中。

变量存储过程实例的上下文信息(context)。变量可以通过下面几种方式进行设置读取:

  • ExecutionService.startProcessInstance( String actorId, Long definitionId, Map variables, String transitionName )

  • ExecutionService.endOfState( String actorId, Long tokenId, Map variables, String transitionName )

  • ExecutionService.setVariables( String actorId, Long tokenId, Map variables )

  • ExecutionContext.setVariable( String name, Object value )

  • ExecutionService.getVariables( String actorId, Long tokenId )

  • ExecutionContext.getVariable( String name )

当设计变量时候,jbpm尽量模仿java.util.map的语义。这一点可以通过jbpm-api来了解。也就是说一个变量只能当它被插入时被赋值,任何java类型都可以作为变量中的value

 

一个type描述jbpm如何存储变量的值到数据库中。Jbpm有一个文本域用来存储值,中间以serializer来实现文本和对象之间的转换。

public interface Serializer {

  String serialize( Object object );

  Object deserialize( String text );

}

the Serializer interface

一个type 可以被看做一个serializer的引用。Jbpm包含了一些默认serializer的实现,其中包括下面java类型:

java.lang.String

java.lang.Long

java.lang.Double

by default supported java-types

 

变量类型匹配:

Java 类型声明的变量已经被默认支持,而不用在processdefinition.xml声明。Jbpm有个自动转换机制:当一个变量初始化后,jbpm按照下面步骤,首先检测java类型。如果它默认被java支持,那么就可以正常使用,否则,jbpm检查声明的类型是否与processdefinition.xmljava-type属性定义的变量是否一致。在匹配过程中jbpm也考虑变量值的父类。如果没有找不到这种类型,jbpm就把这样的变量作为transient(瞬间)变量对待。为了避免jbpm不得不执行匹配过程,你可以把变量指定到它各自类型中去。

Transient (瞬间)变量:

一些变量并不需要做持久层处理存储在数据库中,jbpm支持瞬时变量。这样的变量不存储到数据库中并且只可以在jbpm-api的方法中使用。换句话说,瞬时变量的使用范围是:jbpm-api的方法。

开始状态:

<!ELEMENT start-state ( description?, transition+ ) >

<!ATTLIST start-state name  CDATA #REQUIRED

                      swimlane CDATA #IMPLIED >

dtd fragment for start-state

开始状态是一个过程中的唯一状态,所有的过程实例从这里开始,注意在过程实例开始的时刻你能够把变量放在过程当中了。另外重点的概念是你能够有多个从开始状态出发的变迁,这样的话,就需要你指定哪个变迁是你启动过程实例时候需要执行的。

milestone

<!ELEMENT milestone ( description?, action*, transition ) >

<!ATTLIST milestone name  CDATA #REQUIRED>

dtd fragment for a milestone

 

一个 milestone 是一种特殊的状态,它用来处理两个并发事件中的同步的作用。一个 milestone 可以被应用在下面情形:一条执行路径需要等待另外一个执行路径上的事件。如果 milestone 没有到达,接下来的执行就必须在 milestone 处等待,知道另外一个并发路径到达的时候,才可继续执行。如果 milestone 已经到达了(条件具备了),接下来的执行就是通过这个 milestone 状态。关于 milestone 的更多信息和图形请参看工作流模式。一个 milestone 与一或多个 actions (用信号通知 milestones 到达)相关联。那些 actions 能够用默认 ActionHandler org.jbpm.delegation.action.MilestoneReachdActionHandler 在流程中建模。所以 actions (发信号给 jbpm 引擎告诉它一个 milestone 已经到达)能够像下面这样在 processdefition.xml 中调度:

  ...

  <milestone name="theMilestone">

    <transition to="stateAfterMilestone" />

  </milestone>

  ...

  <state name="stateBeforeReachingMilestone" swimlane="initiator">

    <transition to="stateAfterReachingMilestone">

       <action>

          <delegation class="org.jbpm.delegation.action.MilestoneReachedActionHandler">theMilestone</delegation>

      </action>

    </transition>

  </state>

  ...

modelling a milestone in the processdefinition.xml

 

process-state:

<!ELEMENT process-state ( description?, delegation, action*, transition+ ) >

<!ATTLIST process-state name CDATA #REQUIRED>

dtd fragment for a process-state

一个 process-state 符合父过程的 invocation 。父过程执行到一个 procee-state 时候就开始一个子过程的执行。过程残留在 process-state 中用以子过程的持续。当一个子过程完成后,就从一个 process-state 中离开了。

Decision:

<!ELEMENT decision ( description?, delegation, action*, transition+ ) >

<!ATTLIST decision name CDATA #REQUIRED>

dtd fragment for a decision

一个 decision 用以决定在多个执行路径中哪个才可以被执行。如果你是一个程序员,把它可以理解成 if-then=else 结构即可,当然。一个 decision 能够具有许多离开的变迁。

需要注意的是一个 decision 对某个情况建模,在这里工作流引擎根据上下文( =variables )和一些其他外部资源决定哪个路由可以被接受。作为可供选择的(可以替代的做法),你设计从一个状态出发具备多个变迁。在那种情况下, jbpm 客户端必须通过调用以一个选择变迁名字作为一个参数的 endOfState 方法决定哪个变迁被执行。

Fork (分支):

<!ELEMENT fork ( description?, delegation?, action*, transition+ ) >

<!ATTLIST fork name               CDATA #REQUIRED

               corresponding-join CDATA #IMPLIED>

dtd fragment for a fork

这个比较好理解,定义一般普通的 fork 行为一般是通过 ForkHandler 接口。但是默认行为(当在 fork 中没有 delegetion 时候)是 fork 的每个变迁都将获得一个子 token 。所以仅仅对一些高级外来的并发,你才需要实现 ForkHandler.

一般情况下,一个 fork 会有一个相关的 join 。这个 join 定义个并发的 block 。默认下 fork join 仅支持严格的嵌套,并且默认情况不支持绕过并发 block 边界的变迁。

public interface ForkHandler {

  void fork( ForkContext forkContext ) throws ExecutionException;

}

the ForkHandler interface

 

join

<!ELEMENT join ( description?, delegation?, action*, transition ) >

<!ATTLIST join name               CDATA #REQUIRED

               corresponding-fork CDATA #IMPLIED>

dtd fragment for a join

 

一个 fork joins 用于多条路径执行,用 JoinHandler 接口指定普通的 join 行为。但是默认情况下(没有 delegation )是所有 fork 上的子 token 合并。最后 token 到达 join 将会触发父 token 最后引发 join 上的离开变迁。所以仅仅高级外来的并发你才需要实现 JoinHandler.

约束:一个 join 只能有一个离开变迁。

public interface JoinHandler {

   void join( JoinContext joinContext ) throws ExecutionException;

}

the JoinHandler interface

 

结束状态:

<!ELEMENT end-state EMPTY >

<!ATTLIST end-state name CDATA #REQUIRED>

dtd fragment for end-state

一个过程定义有一个精确的结束状态。当一个过程实例执行到一个结束状态时候,这个过程实例就结束了。

 

变迁( transition ):

<!ELEMENT transition ( action* )>

<!ATTLIST transition name CDATA #IMPLIED

                     to   CDATA #REQUIRED>

dtd fragment for a transition

变迁用来指定节点之间的连接。变迁元素应该放在 node 里面,那么这个变迁就会从这个节点出离开。

 

Action

<!ELEMENT action ( delegation ) >

<!ATTLIST action event-type (process-start|process-end|

                             state-enter|state-leave|state-after-assignment|

                             milestone-enter|milestone-leave|

                             decision-enter|decision-leave|

                             fork-enter|fork-every-leave|

                             join-every-enter|join-leave|

                             transition) #IMPLIED>

dtd fragment for an action

一个 action 是一段 java 代码。在过程执行期间在一些事件基础之上 action 在工作流引擎上执行。

Action 总是被定义成一个过程定义元素( process-definition, state, transition, decision, ... )的子元素。当 action 执行的时候,父元素会在过程执行时候外加一些事件类型来定义精确时刻。可以想象得到,一个 action 的可能事件类型依赖于 action 被包含进去的元素。 事件类型名字( event-type-names )被暗示出是他们应用到的元素(理解有误)。 javadoc 中有事件类型,可以进行查看。

 

public interface ActionHandler {

  void execute( ExecutionContext executionContext );

}

the ActionHandler interface

 

delegation

<!ELEMENT delegation ( #PCDATA ) >

<!ATTLIST delegation class CDATA #REQUIRED>

dtd fragment for a delegation

解释在约束元素和 delegation 类必须实现的接口之间的关联。

四、其他 process archive 文件

当一个 process archive 被部署, processdefinition.xml 将被解析并且把信息存储到 jbpm 数据库中去。所有其他的文件或者被存储在数据库中或者文件系统,与被创建的过程定义相关联。作为一 jbpm api 的客户端你能够通过 ExecutionReadService.getFile( Long processDefinitionId, String fileName ) 访问这些文件。

一个 process archive 和一个过程定义( process definition )之间的区别参看 versioning mechanism

posted on 2006-05-06 16:38 吴名居 阅读(512) 评论(0)  编辑  收藏 所属分类: ERP/CRM-compie

只有注册用户登录后才能发表评论。


网站导航: