Osworkflow完全用java語言編寫的開放源代碼的工作流引擎,具有顯著的靈活性及完全面向有技術
背景的用戶的特點。用戶可以根據自身的需求利用這款開源軟件設計簡單或是復雜的工作流。通過使用,用戶就可以把工作中心放在業務和規則的定義上,而不需通
過硬編碼的方式實現一個Petri網或是一個有窮自動機。用戶可以以最小的代價把osworkflow整合到自己的程序中來。Osworkflow幾乎提
供了所有用戶可能在實際流程定義中需要用到的工作流構成元素,如:環節(step)、條件(conditions)、循環(loops)、分支
(spilts)、合并(joins)、角色(roles)等等。(假如讀者對這些概念還不熟悉,筆者將在Osworkflow基本概念一節中進行簡單描
述。)
但是,這款開源軟件的文檔十分匱乏,而且在大多數現實情形中并不適用。本文將嘗試為讀者填平實際的用例需求與十分簡單的說明文檔間的鴻溝。
用戶可以在OpenSymphony的網站上下載osworkflow的發布。當前的最高版本是2.7(譯者注:最新版本為2.8). 解壓縮發布的軟件包,即得到二進制程序、源代碼、API文檔、說明文檔等。用戶可以在軟件的論壇和維基上獲得進一步的幫助。
版權聲明:任何獲得Matrix授權的網站,轉載時請務必保留以下作者信息和鏈接
作者:Diego Naya;bugaboo(作者的blog:http://blog.matrix.org.cn/page/bugaboo)
Matrix原文:http://www.matrix.org.cn/resource/article/44/44467_osworkflow.html
關鍵字:osworkflow;business
什么是工作流?
維基百科(Wikipedia,WP)把工作流定義為“一份工作的操作過程”:任務如何組成、如何操作、相關順序如何、如何同步、信息如何流動以支持這些任務、以及任務如何被跟蹤等。
一個工作流引擎實現了業務的流程處理。用戶應可以自動跟蹤過程,這將使得引擎更具效率。同時用戶可以對工作流進行建模,監控及統計引擎數據等。
示例業務過程:貸款程序
本
文的示例業務過程研究一個貸款應用程序的實例。我們將通過一個利用osworkflow工作流引擎的工作流來實現它。這個過程會在每家銀行及金融機構中出
現, 其區別僅僅體現為有更過的部門或更多地文檔需要處理. 在本示例中,
我們會用盡量簡單的方法來實現這個業務流程以便于用戶理解。圖一描述了這個業務流程

圖一 貸款業務流程
過程非常簡單,分為如下4步,如下所示:
1)????????填寫表格:銀行客戶填寫表格申請貸款。
2)????????風險分析:一位風險分析家評估不良貸款的風險。
3)????????財務歷史審查:財務管理官員負責檢查客戶歷史貸款、應付賬單、信用卡歷史紀錄等信息。
4)????????最終決定(同意/拒絕):銀行部門主管根據風險分析情況及財務歷史審查情況最終決定是否貸款給該客戶。
正如我們之前看到的,每個工作流都包含角色,每個角色都包含被分配的任務。下文說明了業務流程中涉及到的角色:
1)????????前臺職員:在某個銀行部門向顧客提供信貸申請表的雇員。
2)????????財務官員:負責檢查申請者歷史財務情況(往期貸款、未支付帳單等等)的職員。
3)????????風險分析家:負責分析將錢給予借貸申請者的外部因素(比如社會經濟情況等)及借貸者本人的個人情況。
4)????????銀行部門經理:負責最終決定是否給予借貸者貸款的經理。
請記住,“信貸申請表”是一個重要的概念(我們將在系統實現一節看到其重要性)因為它是流經整個工作流的業務數據。
基本工作流概念
筆者在開篇曾介紹osworkflow提供了一些特有的構造,現在筆者將逐一介紹它們。
首
先,在osworkflow中讀者需要了解得最重要的概念是環節,每個工作流包含了多個環節,讀者可以把環節想象成工作流中每一個重要的活動。每個環節可
以有一些諸如“已完成”、“正在處理”、“已添加至處理隊列”、“未處理”等的狀態,設計工作流的人可以根據需要自己定義狀態。
在每個環節,動作被用戶指定為自動或手動地執行。每個動作執行后,都有一個結果(result)。結果決定了工作流的流轉方向:可以停留在同一環節,跳轉到另一環節,跳轉到一個分支,或者匯集到一個合并等。
最后兩個概念涉及用戶對業務流程的并發執行,分支把工作流分解為兩個并行的環節,合并則在用戶滿足一定條件后,把兩個并行的環節合并成一個。
動
作的執行代表了業務流程的執行,每個動作都有一組預處理功能(pre-functions)和一組后處理功能(post-functions)。其作用正
如讀者想象的那樣,一個在動作觸發之前執行,一個在動作觸發之后執行。一個簡單的例子是:可以在預處理功能中檢驗申請表格數據的正確性,而后在后處理貢功
能中把經檢驗的數據保存至數據庫。
動作的執行結果可以是有條件的(conditional)或無條件的(unconditional)。
對于有條件的結果,引擎將首先檢查是否條件被滿足,然后再交給工作流來處理。如果條件不滿足的話,引擎將進一步判斷下一個有條件結果是否得到滿足,以此類
推,直到系統最終執行到無條件結果進行處理。
讀者可能會問,如果所有的條件結果都沒有得到滿足會如何呢?事實上,每個動作都強制要求具有唯一一個無條件結果。與此對應的,可以有多個有條件的結果。
業務規則常常在最終結果中帶有條件判斷,比如,“如果申請來自于一個老客戶,則流轉到環節1”或者“如果當前系統的用戶的角色是經理的話,直接流轉道最后一個環節”。
最
后一個重要的概念是步驟狀態(process
state),在osworkflow中,當前步驟狀態是所有當前環節狀態的集合。讀者可能會認為工作流在運行過程中只能有一個狀態,但現實的情況是:因
為對分支和合并的支持,引擎能夠做到對環節的并發控制,因此工作流的當前狀態就可能出現:“等待風險分析及已核查財務歷史”的情況。
激活動作的用戶被順理成章地稱為觸發者(caller),每個環節都有一個所有者(owner),以代表在當前環節中負責執行動作的角色或用戶。
當用戶在環節中運轉流程的時候,已完成的環節被保存至歷史表中(history),用戶當前所處的環節成為當前環節(current steps)。
最
后,讀者可能注意到,在osworkflow中并不存在其他工作流引擎中所包含的工作項(workitem)的概念。這是因為osworkflow是“十
分底層”的工作流實現,怎樣實現或定義工作項完全交由用戶來決定。筆者認為工作項的概念太過抽象,用業務數據來稱呼它或許更為貼切一些。
Osworkflow
的文檔中介紹了更多的構造元素,如寄存器(Registers),共用方法(common
functions)等,但筆者建議在建立好第一個工作流以后再去研究它們。它們是osworkflow基本元素外的高級特性,而我們前面所認識的元素則
是osworkflow的根本所在。
Osworkflow體系結構
我們將在本節分析控制osworkflow的體系結構,我們需要理解它是怎樣適用到我們的程序中來的。如我們所猜想的,Osworkflow最主要的接口是Workflow,這個接口也是整個工作流引擎的入口點。是整個系統的門面(facade)。
接口的實現主要關注具體的業務操作能力,這個接口定義了工作流查詢,獲取當前的可執行動作,執行動作,顯示歷史環節等。
工作流被持久化在工作流存儲體(Workflow Store)中,osworkflow提供了幾種持久化的方法,包括Hibernate持久化集成,JDBC持久化集成等。一個存儲體包含了環節信息,變量,工作流自身的描述信息等等。
用戶可能遇到的最常見的應用模式如下所示:
1)通過給定的狀態在工作流存儲體中查詢工作流信息,通常還根據某一個工作流程中具有需執行動作的用戶來進行查詢。這種查詢時通過WorkflowQuery對象中的Workflow.query()方法實現的。
2)通過getAvailableActions()方法列出所有在滿足條件查詢結果中可執行的操作。
3)通過doAction()方法執行用戶選擇的動作。在執行動作的時候一些執行參數可以以java.util.Map的形式傳遞,以實現在工作流定義的運行期進行信息的傳遞。
4)用戶可以有選擇地通過調用initialize()實例化一個工作流。
在理想情況下,由業務邏輯層負責調用osworkflow中的方法,如圖二所示:

圖二 在業務邏輯中集成工作流
在osworkflow
中,業務邏輯描述在一個XML文件中,稱為工作流描述符(workflow
descriptor.)。我們將在實現小節中建立一個簡單的描述符。在工作流描述符中的功能(functions)和條件(conditions)中,
用戶可以定義自己的業務邏輯。筆者將在把工作流集成到應用程序中一節中進行論述。
實現
本小節介紹如何把一個業務邏輯抽象成一個工作流。首先我們要在業務流程圖中識別出工作流的環節。如圖一所示,顯然,我們共有四個環節,同時包含一個分支及一個合并。在下面的bank.xml文件中,讀者將看到它們在描述符中是如何被表示的。
建立好環節以后,必須在每個環節中添加一些動作以便于工作流運轉。每個動作有唯一的無條件結果,條件結果由讀者有選擇地來實現。
<step id="1" name="Form Filling">
<actions>
??<action id="2" name="Fill Form">
?? <results>
????????<unconditional-result old-status="Finished" split="1"/>
?? </results>
??</action>
</actions>
</step>
接下來要并行地執行風險分析和財務歷史核查,這里是放置分支的最理想地點。
<splits>
<split id="1">
??<unconditional-result old-status="Finished"
????status="Underway" owner="Risk Analyst" step="2"/>
??<unconditional-result old-status="Finished"
????status="Underway" owner="Financial Officer" step="3"/>
</split>
</splits>
在
部門經理最終確認以前,并發的工作流環節必須得到合并。我們可以通過應用一個合并(join)來實現它,合并通過一個條件告訴工作流引擎,是否可以合并并
進行到下一環節。在本例中,我們假設這個條件為:前面兩個環節都已具有“Finished”的結束狀態。即當風險分析或財務審核任何一個未完成前,不能進
行到下一步:
<joins>
<join id="1">
??<conditions type="AND">
?? <condition type="beanshell">
????<arg name="script"><![CDATA[
???? "Finished".equals(jn.getStep(2).getStatus()) &&
????????"Finished".equals(jn.getStep(3).getStatus())
??????]]></arg>
????</condition>
?? </conditions>
??<unconditional-result old-status="Finished"
????status="Underway" owner="Manager" step="4"/>
</join>
</joins>
下面在描述符中加入每個環節的所有者,正如我們在基本概念一節看到的那樣,所有者通常代表了環節間交互的角色,角色的引入默認情況下通過osuser框架來實現。
用戶既可以手寫XML描述符文件,也可以通過osworkflow提供的設計器來實現。讀者可以在OpenSymphony的網站上試用這個工具。
測試實現
測試時,我們可以應用osworkflow提供的例子,把bank.xml放到WEB-INF/classes文件夾下,在文件workflows.xml中添加一行以使引擎能夠識別這個工作流。
把工作流集成到應用程序
在建模及測試工作流之后,我們即可以通過下面的幾行代碼把osworkflow集成到我們的程序中。
orkflow wf = new BasicWorkflow(username);
HashMap inputs = new HashMap();
inputs.put("docTitle", request.getParameter("title"));
wf.initialize("workflowName", 1, inputs);
inputs
哈希表包含了初始工作流動作中需要傳出的參數,有幾個實現了Workflow接口的類,其中BasicWorkflow是不支持事務的簡單實現。在工作流
執行過程中可以在流程中調用外部的方法,這種方法應該是實現了FunctionProvider接口的方法類。然后我們就可以用以下的方式調用它:
<action id="1" name="Execute business rule">
<pre-functions>
??<function type="class">
?? <arg name="class.name">java.net.DroolsExecutorFunction</arg>
?? <arg name="ruleBaseName">BusinessRules.drl</arg>
??</function>
</pre-functions>
...
用戶可以通過實現Condition接口,添加自己的條件控制。FunctionProvider及Condition接口可以調用工作流中的已知方法,這兩個接口都可以接受來自于XML描述符文件中的參數。
結論
把
一個業務流程抽象成一個工作流的任務并不容易,需要好的方法和合適的工具,osworkflow是一個為我們提供了許多可重用結構的理想工具。希望通過對
本文的閱讀,讀者能夠理解最基本的osworkflow概念。本文論述過程中所采用的方法非常基礎和簡單,但卻值得借鑒。