jbpm.org:
jpdl-3.2"name="simple">
5000元总经理审批">
在样例流程中,除了开始和结束结点外,我们定义了三种类型的结点:
任务结点
任务结点是一个需要人工参与的结点类型。
当流程进入结点时,会生成相应的任务实例(TaskInstatnce),并通过委派接口AssignmentHandler或jBPM表达式将任务委派给一个或多个特定的角色或参与者。
结点自身进入等待状态,直到任务被参与者完成或者跳过,流程继续。
判定结点
判定结点的设计目标是根据上下文环境和程序逻辑,判定流程转向。
通过指定一个实现DecisionHandlder接口的Java委派类或jBPM表达式,来返回转向(transition)的字符窜类型的名称(可以是中文哦),来达到决定流程方向的功能。
普通结点
普通结点也可以定义相应的处理任务,通过定义相应的ActioinHandler类。
同任务结点不同的是,普通结点定义的任务是由流程自动执行的,无须人工干预。
三种结点都可定义结点事件(event):
node-enter,该事件在流程进入结点时触发
node-leave,该事件在流程离开节点是触发
可以在事件上挂接ActioinHandler接口的实现类来完成一些特定的功能。
三种节点都可以定义异步处理方式(async属性):
异步处理意味着每个结点的事务处理是通过消息机制分离的,不再同一线程中统一调用执行。
而是由消息监听线程从消息队列中取得消息体来运行相应得程序。
此外我们定义了结点间的转向(transition),用来记录和处理状态的变迁。
每个转向中,可以委派一个或多个的ActioinHandler接口实现类,负责处理节点变迁时的上下文状态变更及回调用户定义的处理程序。
流程的程序接口说明
动作处理接口(ActioinHandler)
接口方法:
voidexecute(ExecutionContextexecutionContext)throwsException
该接口是jPDL中最常用的一个回调接口。
从它的接口方法可以发现,它仅仅暴露了流程执行上下文变量ExecutionContext。
用户程序通过ExecutionContext来了解流程的执行状态,并通过改变ExecutionContext中的属性值来影响流程的执行。
ActioinHandler接口可以在所有能包含事件(event)、动作(action)元素的地方被回调。
判定处理接口(DecisionHandlder)
接口方法:
Stringdecide(ExecutionContextexecutionContext)throwsException
判定接口仅适用于判定节点(decision)中。
从它的接口方法可以看出,方法要返回一个字符串型的结果,这个结果必须和判定节点拥有的转向(transition)集合中的一条转向名称相匹配。
在DecisionHandlder的接口方法中一样能访问到ExecutionContext变量,这为判定提供了执行上下文的根据。
当然,如果有必要,用户也可以在该接口中改变ExecutionContext中的变量值。
委派处理接口(AssignmentHandler)
接口方法:
voidassign(Assignableassignable,ExecutionContextexecutionContext)throwsException;
委派处理接口被用户任务元素(task)的委派(assignment)子元素中,它的职责很明确,就是将任务分配给指定的人员或角色。
在AssignmentHandler接口的方法中,Assignable变量通常指任务实例(TaskInstance)。
通过将ExecutionContext和TaskInstance两个变量都暴露给接口方法,用户就可以根据流程上下文情况,来决定要将指定的任务分配个谁。
流程的部署
用户使用jPDL的流程设计器定义业务流程,当然,你也可以直接用文档编辑器直接编辑processdefinition.xml定义文件。
定义文档是可以直接被ProcessDefinition类载入使用的,但在正式运行的系统中,流程定义信息更多是使用关系型数据库来存储。
从流程定义文件将数据导入流程数据库的过程,我们称之为流程部署。
jPDL的流程部署文件包含processdefinition.xml的定义部分和Java处理器的代码部分,这些文件可以被一起打包成.jpdl的zip格式包而后上传服务器端。
这个过程可以在流程设计器界面的“deployment”标签页中操作:
这里我们着重要讲述的是接受部署文件上载的服务器端配置。
在jBPM3.2的包中带着一个jPDL的管理控制台web应用,默认名字为jbpm-console。
该应用带有接受流程定义包部署的程序,但不是最小化的。
实际上完成流程部署功能的,只是jbpm-jpdl.jar核心包中的一个servlet类:
org.jbpm.web.ProcessUploadServlet.完成这个Servlet的成功部署,需要以下工作:
1.配置web.xml,将servlet配置成启动时加载,如下:
引用
GDPDeployerServlet
org.jbpm.web.ProcessUploadServlet
1
GDPDeployerServlet
/upload/*
2.建立流程定义存储数据库表:
Demo中,我们使用的数据库是MySQL的,在E:
\Java\tools\jbpm-jpdl-3.2.2\db\目录下有个jbpm.jpdl.mysql.sql数据库脚本文件。
但我们不能直接导入该文件,会提示有错误,应为该文件的SQL语句末尾少了分号,在批量执行时,MySQL报错。
需要在每一行SQL的末尾添加一个分号,这样就可以用source命令导入了。
3.配置Hibernate.cfg.xml
由于jBPM的数据库持久化是依靠Hibernate进行的,因此需要配置Hibernate.cfg.xml使其适应我们的MySQL环境
引用
--hibernatedialect-->
org.hibernate.dialect.MySQLInnoDBDialect
com.mysql.jdbc.Driver
jdbc:
mysql:
//localhost:
3306/linly
linly
coffee
org.hibernate.cache.HashtableCacheProvider
4.Import需要的jar包
这里的jar包包括三部分:
jbpm的核心包;Hibernate及其支撑包;MySQL的JDBC驱动包。
到此,我们的配置工作完成,这是实现jBPM流程部署服务端的最小化应用配置。
流程控制及API使用
样例程序中的Handler接口实现
下面,根据上述的接口分类,列出样例程序中的类名及相应的功能说明,具体可参考源代码。
动作处理接口(ActioinHandler)
这里要提到一个很重要的区别,就是作用于Node上的ActoinHandler和作用于Transition上的ActoinHandler是有不同的。
区别在于,Node上的ActoinHandler在结束业务逻辑处理后,必须调用executionContext.leaveNode();或executionContext.leaveNode(transition)来保证流程向下执行;而作用于Transition上的则不需要。
判定处理接口(DecisionHandlder)
委派处理接口(AssignmentHandler)
流程测试剖析
本章节,我们将给大家剖析两个流程测试类。
一个是简单的基于内存模型的流程测试FirstFlowProcessTest;一个是更贴近实用的,基于MySQL数据库操作的标准测试案例。
通过对这两个测试例程的分析,来直观的学习如何通过JavaAPI操作jPDL。
简单流程测试案例
测试案例类:
FirstFlowProcessTest.java
Java代码
1.public class FirstFlowProcessTest extends TestCase {
2. ProcessDefinition pdf ;
3. ProcessInstance pi;
4.
5. public void test4000YuanApplication() throws Exception {
6. deployProcessDefinition();
7. createProcessInstance("linly");
8. submitApplication(4000);
9. approveByManager(true);
10. checkTasks();
11. }
12.
13. public void test6000YuanApplication() throws Exception {
14. deployProcessDefinition();
15. createProcessInstance("linly");
16. submitApplication(6000);
17. approveByManager(true);
18. approveByPresident(true);
19. checkTasks();
20. }
21.
22. public void test7000YuanApplication() throws Exception {
23. deployProcessDefinition();
24. createProcessInstance("linly");
25. submitApplication(7000);
26. approveByManager(true);
27. approveByPresident(false);
28. checkTasks();
29. }
30.
31. /**
32. * 部署流程定义
33. * @throws Exception
34. */
35. protected void deployProcessDefinition() throws Exception{
36. System.out.println("==FirstFlowProcessTest.deployProcessDefinition()==");
37. pdf = ProcessDefinition.parseXmlResource("firstflow/processdefinition.xml");
38. assertNotNull("Definition should not be null", pdf);
39. }
40. /**
41. * 生成流程实例
42. */
43. protected void createProcessInstance(String user){
44. System.out.println("==FirstFlowProcessTest.createProcessInstance()==");
45. assertNotNull("Definition should not be null", pdf);
46. //生成实例
47. pi = pdf.createProcessInstance();
48. assertNotNull("processInstance should not be null", pi);
49. //设置流程发起人
50. pi.getContextInstance().createVariable("initiator", user);
51. //触发流程转向
52. pi.signal();
53. }
54. /**
55. * 填写提交申请单
56. * @param money
57. */
58. protected void submitApplication(int money){
59. System.out.println("==FirstFlowProcessTest.submitApplication()==");
60. TaskInstance ti = (TaskInstance)pi.getTaskMgmtInstance().getTaskInstances().iterator() .next() ;
61. System.out.println("ti.actor = " + ti.getActorId());
62. ContextInstance ci = ti.getContextInstance();
63. ci.setVariable("money",new Integer(money));
64. ti.end();
65. }
66. /**
67. * 部门经理审批
68. * @param pass
69. */
70. @SuppressWarnings("unchecked")
71. protected void approveByManager(boolean pass){
72. System.out.println("==FirstFlowProcessTest.approveByManager()==");
73. Iterator it = pi.getTaskMgmtInstance().getTaskInstances().iterator();
74. for( ;it.hasNext(); ){
75. TaskInstance ti = it.next();