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.tkk7.com/Files/persister/NewOfbizWorkflowStore.rar