1.OSWorklow的基本概念
Osworkflow是完全用java语言编写的开放源代码的工作流引擎,具有显著的灵活性及完全面向有技术背景的用户的特点。用户可以根据自身的需求利用这款开源软件设计简单或是复杂的工作流。Osworkflow几乎提供了所有用户可能在实际流程定义中需要用到的工作流构成元素,如:环节(step)、条件(conditions)、循环(loops)、分支(splits)、合并(joins)、角色(roles)等等。
用户可以在OpenSymphony的网站上下载osworkflow的发布。当前的最高版本是2.8(OSWorkflow已不再维护),解压缩发布的软件包,即得到二进制程序、源代码、API文档、说明文档等。说明文档里面有一些概念描绘和例子,可以作为入门学习的资料。
在osworkflow中最重要的概念是step,每个工作流包含了多个step,读者可以把环节想象成工作流中每一个重要的活动。每个step可以有一些诸如“已完成”、“正在处理”、“已添加至处理队列”、“未处理”等的状态,设计工作流的人可以根据需要自己定义这些状态。
在每个step,action被用户指定为自动或手动地执行。每个动作执行后,都有一个结果(result)。结果决定了工作流的流转方向:可以停留在同一step,跳转到另一step,跳转到一个split,或者汇集到一个join等。
最后两个概念涉及用户对业务流程的并发执行,split把工作流分解为两个并行的step,join则在用户满足一定条件后,把两个并行的环节合并成一个。
动作的执行代表了业务流程的执行,每个动作都有一组预处理功能(pre-functions)和一组后处理功能(post-functions)。一个在动作触发之前执行,一个在动作触发之后执行。一个简单的例子是:可以在预处理功能中检验申请表格数据的正确性,而后在后处理贡功能中把经检验的数据保存至数据库。
动作的执行结果可以是有条件的(conditional)或无条件的(unconditional)。对于有条件的结果,引擎将首先检查是否条件被满足,然后再交给工作流来处理。如果条件不满足的话,引擎将进一步判断下一个有条件结果是否得到满足,以此类推,直到系统最终执行到无条件结果进行处理。如果所有的条件结果都没有得到满足会如何呢?事实上,每个动作都强制要求具有唯一一个无条件结果。与此对应的,可以有多个有条件的结果。业务规则常常在最终结果中带有条件判断,比如,“如果申请来自于一个老客户,则流转到环节1”或者“如果当前系统的用户的角色是经理的话,直接流转道最后一个环节”。
最后一个重要的概念是流程状态(process state),在osworkflow中,当前状态是所有当前step状态的集合。读者可能会认为工作流在运行过程中只能有一个状态,但现实的情况是:因为对分支和合并的支持,引擎能够做到对环节的并发控制,因此工作流的当前状态就可能出现:“等待风险分析及已核查财务历史”的情况。
激活动作的用户被顺理成章地称为触发者(caller),每个step都有一个所有者(owner),以代表在当前环节中负责执行动作的角色或用户。当用户在step中运转流程的时候,已完成的环step被保存至历史表中(history),用户当前所处的环节成为current steps。
注册器(register)是一个全局变量,它在工作流运行时被解析,可以被每个function和condition 使用
propertyset是全局范围的持久数据集合(如果用数据库存储,它为os_propertyentry表)
transientVars是一个保存临时数据的Map对象,它应用于所有的functions和conditons。这个transientVars里面包括所有的registers(全局变量),用户输入,以及当前工作流的上下文和状态。它仅在一次工作流调用的生命周期中存在
2.OSWorkflow的流程配置
工作流包括四个方面:流程定义、流程加载、流程运行和流程监控。下面简单分析一下其流程配置文件,这个流程如下图所示:
用户提出申请,等待上级审批,审批通过后流程结束,审批拒绝重写打回申请人继续申请,流程非常的简单,复杂点就是加了回退功能,并且回退到起始申请人,审批回到上次的审批人。其xml配置文件如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE workflow PUBLIC
3 "-//OpenSymphony Group//DTD OSWorkflow 2.8//EN"
4 "http://www.opensymphony.com/osworkflow/workflow_2_8.dtd">
5 <workflow>
6 <initial-actions>
7 <action id="100" name="Start Workflow">
8 <pre-functions>
9 <function type="class">
10 <arg name="class.name">com.opensymphony.workflow.util.Caller</arg>
11 </function>
12 </pre-functions>
13 <results>
14 <unconditional-result old-status="Finished" status="Underway" step="1" owner="${caller}"/>
15 </results>
16 </action>
17 </initial-actions>
18 <steps>
19 <step id="1" name="Customer Apply">
20 <actions>
21 <action id="1" name="Submit Customer Apply">
22 <restrict-to>
23 <conditions>
24 <condition type="class">
25 <arg name="class.name">
26 com.opensymphony.workflow.util.StatusCondition
27 </arg>
28 <arg name="status">Underway</arg>
29 </condition>
30 </conditions>
31 </restrict-to>
32 <results>
33 <unconditional-result old-status="Finished" status="Underway"
34 step="2" owner="${caller}"/>
35 </results>
43 </action>
44 <action id="3" name="Edit Customer Apply">
45 <restrict-to>
46 <conditions>
47 <condition type="class">
48 <arg name="class.name">
49 com.opensymphony.workflow.util.StatusCondition
50 </arg>
51 <arg name="status">Back</arg>
52 </condition>
53 </conditions>
54 </restrict-to>
55 <pre-functions>
56 <function type="class">
57 <arg name="class.name">com.opensymphony.workflow.util.MostRecentOwner</arg>
58 <arg name="stepId">2</arg>
59 </function>
60 </pre-functions>
61 <results>
62 <unconditional-result old-status="Finished" status="Underway"
63 step="2" owner="${mostRecentOwner}"/>
64 </results>
65 </action>
66 </actions>
67 </step>
68 <step id="2" name="Customer Apply Approve" >
69 <actions>
70 <action id="2" name="Approve Customer Apply">
71 <restrict-to>
72 <conditions type="AND">
73 <condition type="class">
74 <arg name="class.name">
75 com.opensymphony.workflow.util.StatusCondition
76 </arg>
77 <arg name="status">Underway</arg>
78 </condition>
79 <condition type="class">
80 <arg name="class.name">
81 com.opensymphony.workflow.util.AllowOwnerOnlyCondition
82 </arg>
83 </condition>
84 </conditions>
85 </restrict-to>
86 <pre-functions>
87 <function type="class">
88 <arg name="class.name">com.opensymphony.workflow.util.MostRecentOwner</arg>
89 <arg name="stepId">1</arg>
90 </function>
91 </pre-functions>
92 <results>
93 <result old-status="Finished" status="Back" step="1" owner="${mostRecentOwner}">
94 <conditions type="AND">
95 <condition type="beanshell">
96 <arg name="script">
97 "Reject".equals("${conclusion}");
98 </arg>
99 </condition>
100 </conditions>
101 </result>
102 <unconditional-result old-status="Finished" status="Finished" step="3"/>
103 </results>
104 </action>
105 </actions>
106 </step>
107 <step id="3" name="End Apply" />
108 </steps>
109 </workflow>
上面一共有三个step,最后一个step什么也不错,就是结束流程。每一个step和action都有一个编号,用于流程跳转和选择action执行。上面pre-functions用户查找某个step最近的owner,目的是让回退回到原始的申请者和由同一审批人审批此申请。
3.Osworkflow流程运行和接口
流程的加载是引擎自动执行的。在osworkflow.xml中,配置流程定义文件的地址,workflows.xml(可自定义)配置具体的流程定义文件,如下:
1 osworkflow.xml
2
3 <osworkflow>
4 <persistence class="com.aicent.osworkflow.ofbiz.NewOfbizWorkflowStore" />
5 <factory class="com.opensymphony.workflow.loader.XMLWorkflowFactory">
6 <property key="resource" value="workflows.xml" />
7 </factory>
8 </osworkflow>
9
10 workflows.xml
11
12 <workflows>
13 <workflow name="customerApply" type="resource" location="customerApply.xml"/>
14 </workflows>
Osworkflow最主要的接口是Workflow,这个接口也是整个工作流引擎的入口点。是整个系统的门面(facade)。
接口的实现主要关注具体的业务操作能力,这个接口定义了工作流查询,获取当前的可执行动作,执行动作,显示历史环节等。
工作流被持久化在工作流存储体(Workflow Store)中,osworkflow提供了几种持久化的方法,包括Hibernate持久化集成,JDBC持久化集成和OFBiz持久化集成等。OFBiz持久化集成类为OfbizWorkflowStore.java,但是其中有一个重要的方法没有实现,即query方法,我将这个类重写了,将query方法实现了,见附件。
流程的启动:
Workflow workflow = WorkFlowFactory.getWorkFlow(UserUtil.getUserName());
long workflowId = workflow.initialize("customerApply", 100, null);
执行申请:
Workflow workflow = WorkFlowFactory.getWorkFlow(UserUtil.getUserName());
Map<String, String> inputs = new HashMap<String, String>();
inputs.put("caller", approver);
workflow.doAction(workflowId.longValue(), 1, inputs);
http://www.blogjava.net/Files/persister/NewOfbizWorkflowStore.rar