2007年9月11日
摘要:
阅读全文
posted @
2007-12-12 16:16 jbpm 阅读(1830) |
评论 (0) |
编辑 收藏
摘要:
阅读全文
posted @
2007-12-12 16:13 jbpm 阅读(1461) |
评论 (0) |
编辑 收藏
作者:杨洪波
jbpm解析流程定义有三种方式:
1)par包
static ProcessDefinition auctionProcess =
ProcessArchive.parse("org/jbpm/tdd/auction.par");
注意,必须在classes的org/jbpm/tdd/目录下有一个auction.par文件
2)xml文件方式
static ProcessDefinition auctionProcess =
JpdlXmlReader.parseFromResource("org/jbpm/tdd/auction.xml");
注意,必须在classes的org/jbpm/tdd/目录下有一个auction.xml文件
3)文本方式
static ProcessDefinition auctionProcess = JpdlXmlReader.parse(
"<process-definition>" +
" <start-state name='start'>" +
" <transition to='auction'/>" +
" </start-state>" +
" <state name='auction'>" +
" <transition to='end'/>" +
" </state>" +
" <end-state name='end'/>" +
"</process-definition>");
这种方式的本质和xml文件解析方式是一样的.
posted @
2007-11-22 18:02 jbpm 阅读(746) |
评论 (0) |
编辑 收藏
作者:杨洪波
作者:杨洪波
shark和jbpm配置文件处理方式比较
1.都使用了单例模式
我想这个是最基本的,一般的程序员写解析程序都会这样使用;要说明的是,AgileFlow
除了使用单例模式,还实现了配置文件的动态装载,如果用户修改了配置文件,它能够在
运行中动态的获取这些变化.
使用jbpm时,第一句话就要使用该模式:JbpmServiceFactory.getInstance()....
2.都实现了缺省配置和定制配置
Shark中,缺省配置放在一个深层次的目录中,定制配置放在config目录,两个配置
文件的内容差不多;
jbpm中,缺省配置放在代码中实现,如下:
propertyClassNames = new HashMap();
propertyClassNames.put( "default", "org.jbpm.impl.DefaultServiceFactory" );
abbreviatedClassNames.put( "jbpm.service.factory", propertyClassNames );
定制配置放在config目录中,为jbpm.properties
比较而言,jbpm的实现方式要好,理由如下:
1)缺省配置容易找到
2)定制配置很简单,默认是没有配置的,比shark的要清爽很多
3.都实现了用一个单例实现多个单例
我在Shark学习系列的文章中讨论过这个功能,jbpm是在JbpmConfiguration.java中实现的:
private void instantiateConfiguredObjects() {
// instantiate configured objects
this.fileMgr = (FileMgr) instantiate( "jbpm.file.mgr", FileMgr.class );
this.idGenerator = (IdGenerator) instantiate( "jbpm.id.generator", IdGenerator.class );
this.serviceFactory = (ServiceFactory) instantiate( "jbpm.service.factory", ServiceFactory.class );
}
1.都使用了单例模式
我想这个是最基本的,一般的程序员写解析程序都会这样使用;要说明的是,AgileFlow
除了使用单例模式,还实现了配置文件的动态装载,如果用户修改了配置文件,它能够在
运行中动态的获取这些变化.
使用jbpm时,第一句话就要使用该模式:JbpmServiceFactory.getInstance()....
2.都实现了缺省配置和定制配置
Shark中,缺省配置放在一个深层次的目录中,定制配置放在config目录,两个配置
文件的内容差不多;
jbpm中,缺省配置放在代码中实现,如下:
propertyClassNames = new HashMap();
propertyClassNames.put( "default", "org.jbpm.impl.DefaultServiceFactory" );
abbreviatedClassNames.put( "jbpm.service.factory", propertyClassNames );
定制配置放在config目录中,为jbpm.properties
比较而言,jbpm的实现方式要好,理由如下:
1)缺省配置容易找到
2)定制配置很简单,默认是没有配置的,比shark的要清爽很多
3.都实现了用一个单例实现多个单例
我在Shark学习系列的文章中讨论过这个功能,jbpm是在JbpmConfiguration.java中实现的:
private void instantiateConfiguredObjects() {
// instantiate configured objects
this.fileMgr = (FileMgr) instantiate( "jbpm.file.mgr", FileMgr.class );
this.idGenerator = (IdGenerator) instantiate( "jbpm.id.generator", IdGenerator.class );
this.serviceFactory = (ServiceFactory) instantiate( "jbpm.service.factory", ServiceFactory.class );
}
posted @
2007-11-22 17:59 jbpm 阅读(469) |
评论 (0) |
编辑 收藏
摘要: 目前我看过采用JBPM的工作流有web-console (JBPM 3.2.1自带)、RUNA WFE、SMART,就这三个我做一个比较:
RUNA WFE
RUNA WFE是上面提到的三个中,唯一可以直接部署应用的,当然也有它的缺点,下面我会提到。这个框架采用的是Struts作为表示层,流程管理和组织架构管理都做的不错,良好的国际化,文档很全。如果只打算研究可以看下它的permission部分,它已经实现了对流程查看、启动、结束等的权限控制,JBPM自身在这部分基本还是TODO状态。
阅读全文
posted @
2007-11-11 16:24 jbpm 阅读(2010) |
评论 (0) |
编辑 收藏
摘要: 研究工作流及其相关技术的人一定知道这个组织——工作流管理联盟(简称WfMC,Workflow Management Coalition),其成立于1993年。作为工作流技术标准化的工业组织,WfMC提出的工作流系统参考模型(Reference Model)无疑为各家工作流软件厂商的系统设计规划提供了最权威的参考,乃至标准。下面就是这个参考模型:
阅读全文
posted @
2007-11-11 16:00 jbpm 阅读(979) |
评论 (0) |
编辑 收藏
作者:胡长城
目前主要列出了13家公司,这几家主要是做workflow的。当然,目前国内做OA,做Platform(包含workflow)的公司很多,但是,在workflow方面非常专注的,比较少。
还有很多公司没有列出来,主要是个人感觉他们在workflow这一个方面并不是非常强劲(可能他们的product,platform很好),比如:BOS(金蝶),EOS(普元),GK-Workflow(北京点击科技),iOffice.net(广州红帆),KA-2(北京科诺),OW4J(Oracle中国),UAP(用友),HotOA(上海华炎),ZoTn(中唐)。还有些小型的工作流产品公司,产品并不是非常有特色,也没有列出来,比如:WiseFlow(上海维泰),aoflow(北京奥宝)
目前我所知道的,在国内比较有名的国外workflow/BPM 厂商,主要有三家:Ultimus(较早进入中国),BusinessWare(北京麒麟,美国VITRIA),2003年进入中国; webMethods(2003年底在北京成立办事处)
以下的“
★”表示可workflow参考度和可研究度,越多表示产品在workflow这一方面更有特点。注:BusinessWare只给了三个“
★”,是表示其所定位在解决方案和项目实施,整个产品定位在Business Process Integration层次,有些超越目前国内市场需求。
编号
|
|
|
|
I00
|
★★★
|
AWF(北京炎黄盈动)
|
嵌入式的工作流平台,功能不是太完善,主要研发实力不足
|
I01
|
★★
|
DLFlo(上海东兰)
|
2000就开始做工作流平台,2002年推出了java版本。但整体来看,发展的不是很理想
|
I02
|
★★★★★
|
LiveFlow(上海东兰)
|
和DLFlo定位差不多,都面向二次开发平台。但是正个产品还是停留在“workflow”功能层次。—— 但是,吸收了DLFlo的很多经验,所以其工作流平台目前还是属于国内前列
|
I03
|
★★★
|
BusinessWare(北京麒麟远创)
|
主要方向是BPM和BPI(业务流程整合)。整个产品是一个“集成平台”。
|
I04
|
★★
|
e-cology(上海泛微)
|
但从workflow这个层次来说,泛微没有太多的特色。
|
I05
|
★★
|
eWay Platform(北京东方易维)
|
Eway的黄金时代已经一去不复返了,自动“马毅”那个团队离开以后。工作流的一些理念当时还是值得的,有些类似ofbiz。表单处里采用二次开发jsp页面来处理。
|
I06
|
★★★
|
JKCFlow(四川金科成)
|
JFCFlow从早期的工作流产品转移向“业务基础软件平台”,但是整个产品平台目前还只能算是,一个OA开发平台。在workflow和model方面并不是非常的强
|
I07
|
★★★★
|
JoinWork(上海天际星)
|
Joinwork刚刚推出来,其开发者丁宏比较欣赏jBPM,joinwork很多思想也是参考了jBPM。但功能上稍微弱了点。但是其基于SWT的设计思想很值得借鉴。
|
I08
|
★★★★
|
Koof MetaLogic(北京世纪金政)
|
去年推出的workflow产品,专做工作流平台,虽然主要定位于oa和电子政务平台,但工作流这一快,还是有很多克参考的功能。
|
I09
|
★★★
|
RiseOffice(北京有生博大)
|
当前版本riseoffice5.1,整个工作流产品基本上为“OA审批流程”量身定做。其表单处里和权限控制很有特色,以及审批历程的处理。整个design端时采用web的,用的 addflow控件。
|
I10
|
★★★★★
|
SunFlow(杭州信雅达)
|
sunFlow这一两年发展很迅速,大有赶超SynchroFlow 趋势。
其产品最大的特色是采用基于域的联邦系统架构,对分布式管理、运行支持较好。而且也是目前国内为数不多的可以支持“仿真”的工作流系统。
|
I11
|
★★★★★
|
SynchroFlow(西安协同数码)
|
基本上非常严格遵循了wfmc的规范,完全实现了interface1、interface2、interface3、interface5。
这一点上,SunFlow和SynchroFlow都有很多相像的地方,都遗留很多学院研究的特点(这两个产品的最初原型都是在大学中诞生的)。
|
I12
|
★★★★★
|
Utimus(国内)
上海敏照(增值代理商),上海永信(增值代理商)
Ultimus上海分公司
|
进入中国最早的国外工作流产品,整个产品采用逻辑的组织结构图,工作流系统支持的功能也很强。其比较有特色的是其“事件条件表
|
posted @
2007-10-28 12:21 jbpm 阅读(2975) |
评论 (4) |
编辑 收藏
作者:胡长城
今天和同事chelsea 就活动实例状态的实现思路上进行了讨论。我们两个站在了两个不同的角度来看待,这两个不同的角度也正好眼下最为常见到的两种实现思路:
helsea是从状态角度来看待,当然也完全是从state pattern的角度来思考:状态在达到某个状态的时候,会引起或必须引起活动实例执行什么操作。
而我是从活动实例的角度来考虑,活动实例的状态只是活动实例的一个属性体,是因为什么行为,造成了什么状态的结果。
这两种观点,没有谁对谁错,也没有谁优谁劣,两者是站在不同的角度来分析同一个问题。其实这两种模式在应用中都是很普遍的,也都是能够很好的解决问题的。不过在现有的workflow引擎实现中,基于活动实例的角度是占绝大多数的,比如obe,shark等等。所以我受这个的影响也是比较深的。
先说说基于活动活动实例的角度的思路吧:
让我下先来看看状态类:
public final class WMActivityInstanceState extends WMObjectState {
public static final int OPEN_NOTRUNNING_INT = 0;
public static final int OPEN_SUSPENDED_INT = 1;
}
或者也可以这么表示:
public enum WMActivityInstanceState{
NOTRUNNIN(0),
SUSPENDED(1);
private int code;
private WMActivityInstanceState(int code){this.code = code;}
public int getCode(){return this.code}
}
对于活动实例来说,状态只是其一个属性而已:
public class BasicActivityInstance extends BasicAttributedEntity{
private int _state;
public void setState(int state) {
_state = state; }
}
或者也可以是
Public void setState(WMActivityInstanceState state)
所以,从活动实例的角度来看,状态之间的关系是平行的。你可以在执行完一些初始化的操作之后,将活动实例的状态设置为Initialized:当然这个操作你必须显示的去设置活动实例(当然,你可以用一些Event去处理),比如调用活动实例的setState方法。至于为什么调用这个方法,或者此时设置的状态是对是错,活动实例并不关心。
下面再来说说基于状态角度的思路吧,这个思路大体可以说就是state pattern的应用。
说道这儿,您可以看看这篇文档:从工作流状态机实践中总结状态模式使用心得 。当然如果您对state pattern不是很了解,那么建议你先看看这篇文档:设计模式之state 。
State模式的着眼点就是状态,以状态的变迁影响实例的行为和动作。其实这就是两个不同的抽象体:state和stateOwner,我们可以看到,活动实例对象就表现为stateOwner。
State模式的依据是状态之间是有有向连接关系的,这有向连接关系其实就是状态的转换规则:A-B-C-D-A。
激发状态的变迁,是由外界的事件(Event)影响的:这个事件会告知,当前的活动实例状态要从当前状态往下一个状态变迁。而活动实例并不知道下一个状态是什么,这完全是状态对象负责维护和告知的。
至此,我们可以看出来了,两种方式的不同:
第一种方式(基于活动实例),其外界事件是影响到活动实例,或者说在事件中显示的告知活动实例状态从什么变为什么。
第二种方式(基于实例状态),其外界事件是影响到活动实例状态对象,至于这个状态的下一个状态是什么,时间并不知道,完全由活动状态之间的关系来维护。
posted @
2007-10-28 12:12 jbpm 阅读(700) |
评论 (0) |
编辑 收藏
作者:tomkoo
以下例子中 采用了jbpm console 的几个实例用户
项目提交人 : ernie .
主管审批 : bert
会签 : ernie , bert , grover
老板审批 : grover
正常流程: 项目金额 >= 500W RMB
提交项目 --> 主管审批 --> 会签 --> 老板审批 --> 审批通过(结束)
正常流程: 项目金额 < 500W RMB
提交项目 --> 主管审批 --> 会签 --> 审批通过(结束)
其中主管审批, 会签, 老板审批 , 不通过, 全部退回给项目提交人修改.
会签中: 所有人全通过, 则通过. 任何一人不通过, 停止其他会签任务.退回给提交人.
流程定义如下:
- <?xml version="1.0" encoding="UTF-8"?>
-
- <process-definition xmlns="urn:jbpm.org:jpdl-3.1"
- name="tc_prj_approval">
-
- <swimlane name="initiator" />
-
-
- <swimlane name="requester">
- <assignment expression="user(ernie)" />
- </swimlane>
-
-
- <swimlane name="chief">
- <assignment expression="user(bert)" />
- </swimlane>
-
-
- <swimlane name="boss">
- <assignment expression="user(grover)" />
- </swimlane>
-
-
- <swimlane name="cosinger">
- <assignment class="net.chenj.jbpm.sample.CosingerAssiHandler">
- </assignment>
- </swimlane>
- <start-state name="start">
- <task name="tc_prj_newprj" swimlane="initiator"></task>
- <transition name="to_submit" to="tc_prj_submit"></transition>
- </start-state>
- <task-node name="tc_prj_submit">
- <task name="tc_prj_submit"></task>
- <transition name="to_chiefapprove" to="tc_prj_chiefapprove"></transition>
- </task-node>
- <task-node name="tc_prj_chiefapprove">
- <task name="tc_prj_chiefapprove"></task>
- <transition name="approve" to="tc_prj_countersign"></transition>
- <transition name="disapprove" to="tc_prj_submit"></transition>
- </task-node>
- <task-node name="tc_prj_countersign" signal="last-wait"
- create-tasks="false">
- <task name="tc_prj_countersign">
- <event type="task-end">
- <action
- class="net.chenj.jbpm.sample.TaskEndCountersign">
- </action>
- </event>
-
- </task>
-
- <event type="node-enter">
- <action name="createInstance"
- class="net.chenj.jbpm.sample.CreateTaskInstanceCountersign">
- </action>
- </event>
-
- <transition name="approve" to="amount_decision"></transition>
- <transition name="disapprove" to="tc_prj_submit"></transition>
- </task-node>
- <decision name="amount_decision">
- <transition name="to_bossapprove" to="tc_prj_bossapprove"></transition>
- <transition name="to_end" to="end1"></transition>
- </decision>
- <task-node name="tc_prj_bossapprove">
- <task name="tc_prj_bossapprove"></task>
- <transition name="approve" to="end1"></transition>
- <transition name="disapprove" to="tc_prj_submit">
- <condition>#{amount >= 500}</condition>
- </transition>
- </task-node>
- <end-state name="end1"></end-state>
- </process-definition>
-
会签swimlane class
- package net.chenj.jbpm.sample;
-
- import org.jbpm.graph.exe.*;
- import org.jbpm.taskmgmt.def.*;
- import org.jbpm.taskmgmt.exe.Assignable;
-
- public class CosingerAssiHandler implements AssignmentHandler {
-
- private static final long serialVersionUID = 1L;
-
- public void assign(Assignable assignable, ExecutionContext executionContext) {
-
- String[] a = { "ernie", "bert", "grover" };
- assignable.setPooledActors(a);
- }
-
- }
-
创建会签任务实现类
- package net.chenj.jbpm.sample;
-
- import org.jbpm.graph.def.ActionHandler;
- import org.jbpm.graph.exe.ExecutionContext;
- import org.jbpm.graph.exe.Token;
- import org.jbpm.graph.node.TaskNode;
- import org.jbpm.taskmgmt.def.Task;
- import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
-
- public class CreateTaskInstanceCountersign implements ActionHandler {
-
- private static final long serialVersionUID = 1L;
-
- public void execute(ExecutionContext executionContext) throws Exception {
-
- Token token = executionContext.getToken();
- TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance();
- TaskNode taskNode = (TaskNode) executionContext.getNode();
- Task task = taskNode.getTask("tc_prj_countersign");
-
- tmi.createTaskInstance(task, token).setActorId("ernie");
- tmi.createTaskInstance(task, token).setActorId("bert");
- tmi.createTaskInstance(task, token).setActorId("grover");
-
- }
-
- }
结束不通过时结束其他会签任务实现
- package net.chenj.jbpm.sample;
-
- import java.util.Collection;
- import java.util.Iterator;
- import org.jbpm.graph.def.ActionHandler;
- import org.jbpm.graph.exe.ExecutionContext;
- import org.jbpm.taskmgmt.exe.TaskInstance;
- import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
-
- public class TaskEndCountersign implements ActionHandler {
-
- private static final long serialVersionUID = 1L;
-
- public void execute(ExecutionContext executionContext) throws Exception {
-
-
- boolean isDisapprove = Boolean.valueOf((String) executionContext
- .getVariable("isDisapprove"));
-
- if (isDisapprove) {
- TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance();
- TaskInstance ti = executionContext.getTaskInstance();
- final String actorId = ti.getActorId();
- Collection c = tmi.getSignallingTasks(executionContext);
- for (Iterator it = c.iterator(); it.hasNext();) {
- TaskInstance task = (TaskInstance) it.next();
- if (!(actorId.equals(task.getActorId())) && (!task.hasEnded())) {
- task.end("disapprove");
- }
- }
- }
-
- }
-
- }
posted @
2007-10-15 17:34 jbpm 阅读(6217) |
评论 (0) |
编辑 收藏
作者:Ni Yue
前一段时间做的一个jbpm和shark的feature对比,今天整理笔记突然又看到这张记录纸了,so post here and drop the paper.作比较的时候Shark是1.0版本,而Jbpm是2.0版本(现在已经出到3.0了)
|
Shark
|
Jbpm
|
持久层 |
Shark自己的一个ORM的方案DODS,感觉不是很好 |
大名鼎鼎的 Hibernate(Jbpm2中使用的是Hibernate 2.1,Jbpm3种使用的是Hibernate3) |
灵活性 |
Shark给人的感觉就是庞大,需要独立的运行一个工作量引擎服务 |
相对更加灵活,和OSWorkflow有的一比,也可以作为嵌入式的工作流引擎 |
后台管理 |
其实这点和上面一点有点相对应了,灵活性差其实是由于提供的功能太多的缘故,Shark自带了一个管理程序,界面虽然差了一点,但是功能满全面的 |
Jbpm2中没有提供后台的管理,Jbpm3还没怎么用过,好像是有的,不知道具体功能如何 |
流程定义的图形设计器 |
Shark使用的WfMC定义的XPDL语言定义流程,有一个JaWE来图形化定义流程,不过XPDL是在是看起来很难懂 |
Jbpm2中没有流程图形定义器,不过Jbpm3中已经有了,是基于Eclipse的一个插件,可以使用它定义Jbpm使用的JPDL,而且不仅是插件形式,后面还会出stand alone的版本 |
表单定制 |
这个Shark可以借助XPDL来进行表单定制,没看太懂就是了 |
Jbpm2不支持,原来看了Jbpm的MailList里面说在考虑Jbpm3中会加入这方面的内容,现在似乎没有看到还 |
用户模型 |
好像必须采用Shark中的用户模型 |
灵活性的体现,任意的用户模型。Jbpm3.1的roadmap里面考虑自带一个简单的用户模型供使用 |
异构系统交互 |
Shark可以开CORBA的服务,这个方面的功能很强大 |
只能通过Java和异构系统的交互似乎,Java能做的Jbpm就行 |
学习成本 |
Shark使用的XPDL很难看懂… |
相对简单 |
文档 |
感觉是一片空白,给的那几个pdf都不顶什么用,用两三个小时就全部看完了,组织的不是很好而且。相对其他的方面,这个是最大的缺点了 |
挺全面的文档,一个chapter一个chapter的,看起来也方便 |
posted @
2007-10-15 15:09 jbpm 阅读(1079) |
评论 (0) |
编辑 收藏
摘要: 是一张Ultimus为一个简单变更定单流程开发的地图。一个客户申请变更一个产品或服务将启动本流程。在收到申请以后,工程经理能拒绝申请,需要一个EMAIL提醒发送给客户,或申请同时输入到3个其他团队(软件,电子,机械)。当所有需求团队反馈后,流程使用网络服务申请一个包括变更所有的输入和时间和成本的预算包。这些信息将反馈给工程经理做最终检查和调整。此时,工程经理又一次能够拒绝申请(如果成本或时间预估过高)。否则,信息将提交给销售部门添加任何补充信息。然后流程将自动生成一个报价并且和提醒一起发送给客户。
阅读全文
posted @
2007-09-23 19:25 jbpm 阅读(516) |
评论 (0) |
编辑 收藏
摘要: JBoss jBPM is a flexible, extensible workflow management system. JBoss jBPM has an intuitive process language to express business processes graphically in terms of tasks, wait states for asynchronous communication, timers, automated actions,... To bind these operations together, JBoss jBPM has the most powerful and extensible control flow mechanism.
阅读全文
posted @
2007-09-23 19:18 jbpm 阅读(738) |
评论 (0) |
编辑 收藏
摘要: 在下面的例子里,我们将向您展示如何能给用户分配任务。因为在jBPM工作流
引擎和组织机构模型之间是分离的,对计算参与者的表达语言将总是被限制的。
因此,你必须指定一个任务处理的实现,包括计算任务参与者
阅读全文
posted @
2007-09-23 16:29 jbpm 阅读(1175) |
评论 (0) |
编辑 收藏
摘要: 城市政府宽带网络软件平台连接一个城市的市政府、党的机关、人大、政法四大类几十甚至上百个机关。政府部门中有大量的工作是需要部门内、部门之间的多部门、多工作岗位、多工作人员协同工作来完成的。而且其工作呈工作流状态和事务性状态(既工作流程的完整性)。
阅读全文
posted @
2007-09-23 15:56 jbpm 阅读(677) |
评论 (0) |
编辑 收藏
摘要: 工作流一直是实施BPM的重要环节,以往的开源与闭源的划分已经不适合如今的工作流局势,开源已经渗透到了各个领域,如今的工作流已是三分天下的大局
阅读全文
posted @
2007-09-23 11:06 jbpm 阅读(3481) |
评论 (1) |
编辑 收藏
摘要: 业务日历是关于业务时间的,并且被用于为任务和定时器计算预期的时间。 业务日历能够通过对一个期限和日期进行增加来计算日期。我们先看看业务日历的语法:
xml 代码
[business]
阅读全文
posted @
2007-09-19 17:40 jbpm 阅读(907) |
评论 (1) |
编辑 收藏
摘要: JBPM的流程执行模型以下面几个模型为原型:
Node 节点,Action 动作,Transition 流向,Excution 执行。 阅读全文
posted @
2007-09-19 17:08 jbpm 阅读(679) |
评论 (1) |
编辑 收藏
作者: JeffreyHsu
尽管jbpm非常强大,是目前最适合商业化的开源工作流引擎,可以开发出复杂的流程,但是特别遗憾的是并不支持并发子流程(multiple-subprocess)
有一次我需要做一个复杂的流程,主流程里要求同时启动多个并发执行的子流程,并且子流程的数目和启动的时间都不确定,当所有子流程都结束以后,主流程才继续执行。我们知道jbpm里有子流程的设定,有专门的节点ProcessState来处理,但是后来发现无论如何也实现不了多子流程并发执行,后来看其源码知道因为subprocess是作为ProcessState的一个属性,也就是说ProcessState只能包含一个subprocess的定义,并且最重要的是processInstance.getRootToken()和子流程相关的只有createSubProcessInstance, getSubProcessInstance, setSubProcessInstance三个方法,这意味着主流程的rootToken只能设置一个子流程,jbpm并不直接支持多子流程。
那么我们就必须用一个变通的方法来实现,“并发”很自然的让我们想到了fork,但是这里的fork不能搭配join来使用,具体原因,将在后面讨论。
下面先给出流程图:
state节点用来启动子流程(实际应用可以换成Task-Node),state进入fork后同时进入两个分支,一条去启动子流程,另一条回到自己,这样表面看来state没有动,而同时你又可以启动第2个,第3个……子流程,需要注意的是第2条子流程和第1个子流程并不处于同一级上,而比第一个子流程低一级,具体请看后面一张图就明白了,分解后的:
从图中我们可以看到后一个子流程的整棵树是前一个子流程的兄弟,但是在业务级上是并发的效果,已经实现我们前面的需求。
现在来说说为什么不能用join而直接用end,因为会产生一个问题,state3和sub process 2都到达了join以后,state2下面的fork就结束了,就会立刻越过join到达end,而sub process 1即使执行完毕到达了join却仍然在傻傻等待着他的兄弟分支也到达join(而实际上它已经自跑到end去了)一同结束,这样sub process 1就会永远停在join动弹不得,业务无法进行。
这是我的一个解决方案,但还有一个问题,虽然全部的子流程都能结束,主流程也能结束,但因为没有join,主流程的rootToken仍然停留在fork节点上。目前我尚不知如何解决,希望各位大家能提出其他更好的解决办法。
初学jbpm,水平有限,有不当之处还请高手斧正
最后附上demo代码供参考:
代码
-
- import static org.junit.Assert.*;
-
- import org.jbpm.graph.def.ProcessDefinition;
- import org.jbpm.graph.exe.ProcessInstance;
- import org.jbpm.graph.exe.Token;
- import org.jbpm.graph.node.ProcessState;
- import org.junit.Before;
- import org.junit.Test;
-
- public class MultiProcessTest {
- private ProcessDefinition superProcessDefinition;
-
- private ProcessDefinition subProcessDefinition;
-
- @Before
- public void setUp() throws Exception {
- superProcessDefinition = ProcessDefinition.parseXmlString(
- "<process-definition name='super'>" +
- " <start-state name='start'>" +
- " <transition to='state' />" +
- " start-state>" +
- " <state name='state'>" +
- " <transition name='create sub' to='fork' />" +
- " <transition name='end' to='end' />" +
- " state>" +
- " <fork name='fork'>" +
- " <transition name='back' to='state' />" +
- " <transition name='go to sub' to='sub process' />" +
- " fork>" +
- " <process-state name='sub process'>" +
- " <sub-process name='sub' />" +
- " <transition to='end' />" +
- " process-state>" +
- " <end-state name='end' />" +
- "process-definition>");
-
- subProcessDefinition = ProcessDefinition.parseXmlString(
- "<process-definition name='sub'>" +
- " <start-state name='start'>" +
- " <transition to='wait' />" +
- " start-state>" +
- " <state name='wait'>" +
- " <transition to='end' />" +
- " state>" +
- " <end-state name='end' />" +
- "process-definition>");
- ProcessState processState = (ProcessState) superProcessDefinition
- .getNode("sub process");
- processState.setSubProcessDefinition(subProcessDefinition);
- }
-
- @Test
- public void testMultiProcesses() {
- ProcessInstance pi = new ProcessInstance(superProcessDefinition);
-
- // 启动一个主流程
- pi.signal();
- assertEquals("state", pi.getRootToken().getNode().getName());
-
- // 进入分支,此处将进入子流程
- pi.signal("create sub");
- // 主流程token将停留在fork节点上
- assertEquals("fork", pi.getRootToken().getNode().getName());
-
- // fork分为两支,其中一支的节点停留在ProcessState上
- Token subProcessToken1 = pi.getRootToken().getChild("go to sub");
- ProcessInstance subPi1 = subProcessToken1.getSubProcessInstance();
- assertEquals("wait", subPi1.getRootToken().getNode().getName());
-
- // 另一支返回了state节点,实际上并没有返回,这个state节点不同于先前的state,它们并不在同一个path中
- Token stateToken1 = pi.getRootToken().getChild("back");
- assertEquals("state", stateToken1.getNode().getName());
-
- // 再次进入fork,启动第二个子流程
- stateToken1.signal("create sub");
- ProcessInstance subPi2 = stateToken1.getChild("go to sub")
- .getSubProcessInstance();
- // 虽然都是子流程,但它们并不相同,在逻辑上是属于并发的无关系的子流程
- assertFalse(subPi1.equals(subPi2));
- // 结束第二个子流程
- subPi2.signal();
- assertTrue(subPi2.hasEnded());
- assertFalse(pi.hasEnded());
-
- // 结束第一个子流程,但主流程仍未结束
- subPi1.signal();
- assertTrue(subPi1.hasEnded());
- assertFalse(pi.hasEnded());
-
- // 结束第二个子流程中的state,第一子流程的back分支结束,从而主流程也结束
- Token stateToken2 = stateToken1.getChild("back");
- assertEquals("state", stateToken2.getNode().getName());
- assertFalse(stateToken1.hasEnded());
- assertFalse(pi.hasEnded());
- stateToken2.signal("end");
-
- assertTrue(stateToken1.hasEnded());
- assertTrue(subPi1.hasEnded());
- assertTrue(pi.getRootToken().getChild("back").hasEnded());
- assertTrue(pi.getRootToken().getChild("go to sub").hasEnded());
- // 主流程结束了
- assertTrue(pi.hasEnded());
- // 虽然主流程已经结束了,但是因为子流程没有join,所以其rootToken仍然停留在fork上
- assertEquals("fork", pi.getRootToken().getNode().getName());
- // 第二个子流程到达的end和主流程中的end并不是同一个节点
- assertTrue(!pi.getRootToken().getNode().equals(stateToken2.getNode()));
- }
- }
posted @
2007-09-11 17:48 jbpm 阅读(1021) |
评论 (0) |
编辑 收藏
对于BPM产品目前尚无公认的分类标准,如果沿用以前对工作流的分类,则可以分为生产型(又可以再细分为自治式和嵌入式两种)、管理型、协同型和专门型四大类。但这样一来,市场上主流的通用BPM产品大都会被划分到生产型,难以分辨出它们之间的本质差异,因此我们需要一种新的分类方法。
笔者建议根据产品内在拓扑结构的差异进行分类,将BPM产品划分为面向引擎型、面向业务型、面向消费者型、以及对等型四大类。而一些功能较强的产品能同时支持多种拓扑结构。
面向引擎型:匹马单枪
见自性清静,自修自作法身,自行佛行,自成佛道。
企业内的工作流系统广泛采用了这种集中控制式拓扑结构,客户端连接到负责接受请求的中央引擎服务器。当流程上有客户端完成了任务,它会将结果发送给服务器,服务器接收齐工作数据,就开始组织下一个任务项。大多数BPM产品都支持这种最原始的拓扑形式。
这种方式的长处在于其简单性,它使得管理和控制都很容易,而且它对客户端的要求不高,大多数负载和责任都从客户端转移到了引擎服务器。
这种模式的缺点在于成败悬于一线,整个系统完全依赖于一个全能服务器。该服务器必须功能非常强大,并且必须能够承受巨大的压力。反过来说,这又限制了系统的可扩展性。
采取这种结构的BPM系统一般非常重视用于自动型活动的企业应用集成(EAI/A2A)和用于人工型活动的人机交互界面。有集成服务器背景的厂商往往侧重于应用集成和直通处理(系统到系统的交易),Fuego、SeeBeyond、Vitria和WebMethods属于此类。有着工作流背景的厂商则往往对需要大量人工干预的应用提供更完善的功能,FileNet、Identitech、Plexus和Staffware就属于此类,这类厂商对客户界面和流程设计工具进行了优化,可以支持各种流程的人工干预。新玩家HandySoft和Intalio则介于两者之间。
归根到底,应用集成能力的高低是区别诸解决方案的一个主要因素。如果你所考虑的应用需要相当高的集成水平,尤其是与多个系统的集成,集成服务器厂商提供的产品显然具有优势,但选择来自集成服务器厂商的BPM解决方案可能意味着需要采用它们的平台作为集成标准。
面向业务型:天龙八部
尔时世尊,天龙八部,四众围绕,王及大众,五体投地,为佛作礼。
许多业务流程管理系统是通过可靠消息通信实现的。消息队列技术允许系统异步和分布运行,支持跨异构网络甚至是暂时离线的系统间通信。一个客户端为了与属于另一引擎服务器的客户端进行协作,可以将消息发送到自己所属引擎的队列中,引擎会完成剩下的实际消息转发和传递工作,并把最终的返回消息也放在发起者的接收队列中,供该客户端随时提取。
这是一种多引擎的拓扑结构,可以解决许多单纯的客户/服务器拓扑存在的问题,但它仍然采用集中控制的方法,因为一个引擎通常服务于一大堆客户端,任务只是在相互连接的引擎之间分割和协作。
这一解决方案的优点在于可扩展性好,当负荷太重时可以通过添加引擎来缓解。这一方案的容错性也更强,当某台引擎出现故障时,其他引擎可以接管其原来的工作。另外,它可以支持更有效的通信,因为引擎可以与客户端离得更近。
这一方式的缺点在于引擎必须设计得很精巧,它必须既能处理客户端请求,又能与其他引擎协调。它还有一点与面向引擎的拓扑类似,即仍然将负荷和责任从客户端改扛在了引擎服务器肩上,只不过不光是一个引擎罢了。另外,同时维护多个引擎也需要更多的管理开销。
支持这种拓扑结构的BPM产品一般都擅长于跨企业的应用集成和协调(B2Bi)。许多BPM应用,如支持多账户应用处理的金融服务,往往基于应用服务器环境。例如IBM的MQSeries Workflow的产品;BEA的Process Integration。Fujitsu、Intalio、Quovadx、Savvion、Versata等厂商的产品不仅能够与IBM或BEA的应用服务器兼容,还各自提供常见BPM组件的定制开发环境。对侧重于开发流程之间的应用到应用通信并以微软产品为中心的环境而言,微软的BizTalk则非常适合。
面向消费者型:心心相印
昔时圣人互出,乃曰传灯,尔后贤者差肩,乃曰继祖,是以心心相传,法法相印。
近些年,发布/订阅(Pub/Sub)拓扑结构成为构建、实现和集成复杂流程的抢手货,被认为是满足动态需求的一种简单而有效的手段。很多强大、灵活的BPM系统就建立在这种模式之上,例如,TIBCO便一直是使用Pub/Sub方式构建松散耦合的分布式应用的先驱。在动态演化的系统中应用Pub/Sub模式实现业务流程已被证明相当有效。
Pub/Sub拓扑结构的一大长处是无需复杂的集中式服务器和路由机制,因为消息直接由来源发往目的地。该模式支持高度分散的业务流程间的协作。
它的弱点在于可伸缩性非常有限。每个发布者只能包含有限数目的订阅者,否则会处理不过来。此外,在没有集中控制的情况下发现发布者和订阅者也很困难,因为当你找不到对方的时候,无处去询问和诉说。最后,它还存在生命期的依赖性。
像抵押贷款、索赔甚至支付处理等BPM应用还需要与流程管理功能紧密相关的图像处理及内容管理功能,为此,Plexus能把大容量文档图像处理和高度可伸缩的流程管理紧密结合在一起;而Identitech等厂商捆绑了基于XML的电子表格和本地记录管理功能;FileNet的新款Panangon平台特别提供了企业内容管理(ECM)功能,能同时支持文档图像处理、Web内容管理及可靠的集成特性和选项。尽管Handysoft并不提供本地网站门户,也不提供内容管理功能,但却提供了与Documentum、Hummingbird、Plumtree和微软的SharePoint相集成的功能。
对等型:打成一片
长短好恶,打成一片,一一拈来,更无异见。
P2P(Peer-to-Peer)计算是Internet发展的最新产物,在Internet之上已经有了数不胜数的资源和对等端,它们有潜力克服传统客户/服务器系统的大多数限制,如可伸缩性、内容可用性、计算能力等,当然,这也需要比单纯将消息转发给所有对等端更有效的群组通信机制,因为这些对等端可能是在网格计算背景下分布在全球的用户和厂商。
P2P模式是完全分散的,每个结点都被认为是一个对等端,它会连接到一个或者几个其他的端口。如果不使用过滤机制的话,那么每个对等端都会把会话转发给相邻的所有对等端,形成会话“洪水”。所以在实际应用中,应该使用分割、投影、过滤等策略,只将与该对等端相关的流程部署在它上面,该对等端只接受从其流程上游发来的消息,再将经过处理的结果仅发送给它的下游对等端。
P2P拓扑的好处在于无需集中式服务器,允许任意数量的网络结点,因为工作负荷可以在各个对等端之间平衡与共享。
它的坏处在于有时候延迟现象严重,因为流程有时需要在多个对等端之间协同。另外,部分低效的对等端必然影响整体的性能。
由中科院软件所和中科国际共同开发的A2E-DI就支持完全分散的数据提取、转换、传输和加载的全过程操作。HandySoft开发的BizFlow则提供了一系列由可伸缩业务流程引擎驱动的基于Web的协作工具,其可伸缩性决定了它亦能应用于对等环境。
在P2P结构的基础之上还可能出现P2P Cluster(P2P集群)拓扑结构。它可以通过分而治之的策略解决单纯P2P模式中消息通信存在的某些问题。网络被划分为一系列集群,每个集群都了解其管辖的对等端。在每个集群中,牺牲一台服务器用于充当协调者的角色,它知道哪个对等端订阅了远程的某个发布者,也知道远程的某个订阅者订阅了集群内部的哪个对等端,这样就不必把时间花在那些无关的集群内部了。其优缺点与P2P拓扑大体相似。
|
posted @
2007-09-11 17:44 jbpm 阅读(770) |
评论 (0) |
编辑 收藏
摘要:
理论介绍(一些定义)
业务流程是一个组织及其合作伙伴的人员及系统所完成的工作的一种正式表达, 它旨在给内部或外部客户提供产品或服务。业务流程最简单的表达形式就是一组活动,它们表示流程的不同步骤,通过一些转换连接在一起。活动可能需要人为干预,也可能是全自动的。对于需要人为交互的活动,可以在流程中定义一个角色,标识允许谁在这里与流程交互。流程起到定义的作用,而流程中的实例就是完成整个流程的实际项目,从一个活动转换到另一个活动。实例总是开始于流程的Begin活动,而结束于流程的End活动。实例的路径完全取决于实例的数据以及外部环境。
转换是活动之间的直接连接, 许多的转换进出一个活动.。一旦某个实例完成了一项活动件,外发转换将被评估, 其中之一被选中,以使实例转向下一活动。条件转换包含一个布尔表达式,该表达式将被计算,要使实例继续沿流程前进,结果必须为true。有些转换是基于时间的,这就意味着如果到了预期时间,实例还在那里,这些转换将会触发到目标活动的自动路由。流程也可以有状态:可为流程定义属性,接受每个实例的一个值,这能帮助您保持实例状态,以 阅读全文
posted @
2007-09-11 17:40 jbpm 阅读(529) |
评论 (0) |
编辑 收藏
摘要: 业务流程管理(BPM)是一个当前软件行业最热门的市场分类。BPM是模块化,自动化,管理和优化业务流程来获取利润的学科。
阅读全文
posted @
2007-09-11 17:37 jbpm 阅读(496) |
评论 (0) |
编辑 收藏
作者: nogocn
在某一公司中,部门员工要休假的话需要部门主管的批准。如果休假天数大于10天的话,在部门主管的同意后,还必须上级主管批准。如果是部门主管要休假只要上级主管批准即可。在休假被批准之前,申请人可以撤销休假申请。
每个员工还有多少天休假必须管理起来,在员工提交休假申请时要检查申请天数是否超过可用天数。申请批准后,要在可用天数里减去申请天数。每次休假申请结束之后,不管通过未通过或是否取消,都必须记录下来。主管在批复申请之后,系统要将批复结果Email给申请人。对于大于10天的申请,如果部门主管已批准同意而上级主管还未批准,这时申请人撤销申请后,系统应发Email通知部门主管申请已撤销。
processdefinition.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSPY v2004 rel. 3 U (http://www.xmlspy.com) by Keller (zju) -->
<!DOCTYPE process-definition PUBLIC
"-//jBpm/jBpm Mapping DTD 2.0//EN"
"http://jbpm.org/dtd/processdefinition-2.0.dtd">
<process-definition name="RequestLeave">
<swimlane name="requester">
<description>申请者</description>
</swimlane>
<swimlane name="chief">
<description>部门主管</description>
<delegation class="kellerdu.jbpm.delegation.ChiefSwimlane"/>
</swimlane>
<swimlane name="boss">
<description>上级主管</description>
<delegation class="kellerdu.jbpm.delegation.BossSwimlane"/>
</swimlane>
<start-state name="request" swimlane="requester">
<transition to="Begin Request"/>
</start-state>
<fork name="Begin Request">
<transition to="Requester Cancel"/>
<transition to="IsChief"/>
</fork>
<decision name="IsChief">
<delegation class="kellerdu.jbpm.delegation.ChiefDecision"/>
<transition name="Boss Approve" to="Boss Approve"/>
<transition name="Chief Approve" to="Chief Approve"/>
</decision>
<state name="Requester Cancel">
<assignment swimlane="requester"/>
<transition name="cancel" to="Decided">
<action>
<!-- 将请假的状态改变为“取消”-->
<delegation class="kellerdu.jbpm.action.RequestCancel"/>
</action>
</transition>
</state>
<state name="Chief Approve">
<assignment swimlane="chief"/>
<transition name="approve" to="NeedBossApprove">
<action>
<!-- 将请假的状态改变为“主管批准”-->
<delegation class="kellerdu.jbpm.action.ChiefApprove"/>
</action>
</transition>
<transition name="disapprove" to="Decided">
<action>
<!-- 将请假的状态改变为“主管否决”-->
<delegation class="kellerdu.jbpm.action.ChiefDisapprove"/>
</action>
</transition>
</state>
<state name="Boss Approve">
<assignment swimlane="boss"/>
<transition name="approve" to="Decided">
<action>
<!-- 将请假的状态改变为“老板批准”-->
<delegation class="kellerdu.jbpm.action.BossApprove"/>
</action>
</transition>
<transition name="disapprove" to="Decided">
<action>
<!-- 将请假的状态改变为“老板否决”-->
<delegation class="kellerdu.jbpm.action.BossDisapprove"/>
</action>
</transition>
</state>
<decision name="NeedBossApprove">
<!-- 请假天数大于10天的要老板批准 -->
<delegation class="kellerdu.jbpm.delegation.NeedBossApproveDecision"/>
<transition name="need" to="Boss Approve"/>
<transition name="notNeed" to="Decided"/>
</decision>
<join name="Decided">
<description>有一个先到达即进行父Token</description>
<delegation class="kellerdu.jbpm.delegation.DecidedJoin"/>
<transition to="Do Something"/>
</join>
<decision name="Do Something">
<description>
根据请求的状态决定。
(1)“主管或者老板批准”-‘approve’:修改员工休假的总天数,设定发给用户E-Mail的信息。
(2)“主管或者老板否决”-“disapprove”:设定发给用户E-Mail的信息。
(3)“撤销”-"cancel"-设定发给用户E-Mail的信息。如果主管批准,要发给主管消息说明已经撤销。
</description>
<delegation class="kellerdu.jbpm.delegation.DoSomethingDecision"/>
<transition name="disapprove" to="Finished">
<action>
<delegation class="kellerdu.jbpm.action.Disapprove"/>
</action>
</transition>
<transition name="approve" to="Finished">
<action>
<delegation class="kellerdu.jbpm.action.Approve"/>
</action>
</transition>
<transition name="cancel" to="Finished">
<action>
<delegation class="kellerdu.jbpm.action.Cancel"/>
</action>
</transition>
</decision>
<end-state name="Finished"/>
<action event-type="process-end">
<!-- 发送E-Mail消息给申请者,记录请假日志 -->
<delegation class="kellerdu.jbpm.action.ProcessEndAction"/>
</action>
</process-definition>
posted @
2007-09-11 13:47 jbpm 阅读(2415) |
评论 (0) |
编辑 收藏
摘要: JBoss jBPM为设计及开发工作流和业务流程管理系统提供了一个先进的平台。由API、特定领域的语言和图形建模工具组成的框架让开发人员和业务分析人员能够使用通用平台进行沟通及操作。 阅读全文
posted @
2007-09-11 13:35 jbpm 阅读(434) |
评论 (0) |
编辑 收藏
转自: 百度
jBPM,全称是Java Business Process Management,是一种基于J2EE的轻量级工作流管理系统。jBPM是公开源代码项目,它使用要遵循 Apache License。jBPM在2004年10月18日,发布了2.0版本,并在同一天加入了JBoss,成为了JBoss企业中间件平台的一个组成部分,它的名称也改成JBoss jBPM。随着jBPM加入JBoss组织,jBPM也将进入一个全新的发展时代,它的前景是十分光明的。
jBPM最大的特色就是它的商务逻辑定义没有采用目前的一些规范,如WfMC´s XPDL, BPML, ebXML, BPEL4WS等,而是采用了它自己定义的Process defiJBoss jBPM nition language (jPdl)。jPdl认为一个商务流程可以被看作是一个UML状态图。jPdl就是详细定义了这个状态图的每个部分,如起始、结束状态,状态之间的转换等。
jBPM的另一个特色是它使用Hibernate来管理它的数据库。Hibernate是目前Java领域最好的一种数据持久层解决方案。通过Hibernate,jBPM将数据的管理职能分离出去,自己专注于商务逻辑的处理。
posted @
2007-09-11 13:32 jbpm 阅读(380) |
评论 (0) |
编辑 收藏
作者: fndcz
1. JPDL的流程定义元素
1) 第一层:GraphElement
这个容易理解,因为在画流程定义时,每个拖拉的对象都是一个graph的元素。GraphElement有四个属性:
(1)processDefine 表示当前元素属于哪个流程定义
(2)events 表示可以接收哪些event
(3)name 名字
(4)exceptionHandlers 异常处理类集合(List)
2) 第二层:node、processDefinition、Transition、Task
它们都继承自GraphElement
(1)processDefinition表示流程定义(implements NodeCollection),它有下面的属性:name、version、nodes、startState。nodes表示流程中所有的node,startState用于启动流程时找到首节点。
(2)Transition表示转移,它有三个属性:from(Node),to(Node),supportedEventTypes表示支持的event类型
(3)node表示节点,它有四个属性:leaving transitions、arriving transitions、action、superState。
(4)Task 定义任务
3) 第三层:各种不同的node
它们都继承自node。 Decision、EndState、Fork、Join、Merge、Milestone、 InterleaveEnd、InterleaveStart、ProcessState、State。
posted @
2007-09-11 13:29 jbpm 阅读(570) |
评论 (0) |
编辑 收藏
摘要: 1概述
一个流程定义是对一个业务流程的正式说明,以及它是基于有向图的。该图是结点(node)与流向(transition)的组合。图中每一个结点都是一个特殊的类型,结果的类型决定了该结点的运行时的行为。一个流程定义有且仅有一个开始状态。
一个令牌(token)是执行的轨迹。令牌是一个运行时的概念,其维护着速个图中指向结点的指针。
阅读全文
posted @
2007-09-11 13:27 jbpm 阅读(718) |
评论 (0) |
编辑 收藏