OSWorkFlow分析
1. OSWorkFlow基本概念
在商用和開(kāi)源世界里,OSWorkflow 都不同于這些已有的工作流系統。最大不同在于 OSWorkflow 有著(zhù)非常優(yōu)秀的靈活性。在開(kāi)始接觸 OSWorkflow 時(shí)可能較難掌握(有人說(shuō)不適合工作流新手入門(mén)),比如,OSWorkflow 不要求圖形化工具來(lái)開(kāi)發(fā)工作流,而推薦手工編寫(xiě) xml 格式的工作流程描述符。它能為應用程序開(kāi)發(fā)者提供集成,也能與現有的代碼和數據庫進(jìn)行集成。這一切似乎給正在尋找快速“即插即用”工作流解決方案的人制造了麻煩,但研究發(fā)現,那些“即插即用”方案也不能在一個(gè)成熟的應用程序中提供足夠的靈活性來(lái)實(shí)現所有需求。
2. OSWorkFlow主要優(yōu)勢
OSWorkflow 給你絕對的靈活性。OSWorkflow 被認為是一種“低級別”工作流實(shí)現。與其他工作流系統能用圖標表現“Loops(回路)”和“Conditions(條件)”相比,OSWorkflow 只是手工“編碼(Coded)”來(lái)實(shí)現的。但這并不能說(shuō)實(shí)際的代碼是需要完全手工編碼的,腳本語(yǔ)言能勝任這種情形。OSWorkflow 不希望一個(gè)非技術(shù)用戶(hù)修改工作流程,雖然一些其他工作流系統提供了簡(jiǎn)單的 GUI 用于工作流編輯,但像這樣改變工作流,通常會(huì )破壞這些應用。所以,進(jìn)行工作流調整的最佳人選是開(kāi)發(fā)人員,他們知道該怎么改變。不過(guò),在最新的版本中,OSWorkflow 也提供了 GUI 設計器來(lái)協(xié)助工作流的編輯。
OSWorkflow 基于有限狀態(tài)機概念。每個(gè) state 由 step ID 和 status 聯(lián)合表現(可簡(jiǎn)單理解為 step 及其 status 表示有限狀態(tài)機的 state)。一個(gè) state 到另一 state 的 transition 依賴(lài)于 action 的發(fā)生,在工作流生命期內有至少一個(gè)或多個(gè)活動(dòng)的 state。這些簡(jiǎn)單概念展現了 OSWorkflow 引擎的核心思想,并允許一個(gè)簡(jiǎn)單 XML 文件解釋工作流業(yè)務(wù)流程。
3. OSWorkFlow核心概念
3.1. 概念定義
步驟(Step)
一個(gè) Step 描述的是工作流所處的位置??赡軓囊粋€(gè) Step Transtion(流轉)到另外一個(gè) Step,或者也可以在同一個(gè) Step 內流轉(因為 Step 可以通 Status 來(lái)細分,形成多個(gè)State)。一個(gè)流程里面可以多個(gè)Step。
狀態(tài)(Status)
工作流 Status 是用來(lái)描述工作流程中具體Step(步驟)狀態(tài)的字符串。OSWorkflow 的有 Underway(進(jìn)行中)、Queued(等候處理中)、Finished(完成)三種 Status。一個(gè)實(shí)際State(狀態(tài))真正是由兩部分組成:State = (Step + Status) 。
流轉(Transtion)
一個(gè)State到另一個(gè)State的轉移。
動(dòng)作(Action)
Action 觸發(fā)了發(fā)生在 Step 內或 Step 間的流轉,或者說(shuō)是基于 State 的流轉。一個(gè) step 里面可以有多個(gè)Action。Action 和Step 之間的關(guān)系是,Step 說(shuō)明“在哪里”,Action 說(shuō)明“去哪里”。 一個(gè) Action 典型地由兩部分組成:可以執行此Action(動(dòng)作)的
Condition(條件),以及執行此動(dòng)作后的 Result(結果)。
條件(Condition)
類(lèi)似于邏輯判斷,可包含“AND”和“OR”邏輯。比如一個(gè)請假流程中的“本部門(mén)審批階段”,該階段利用“AND”邏輯,判斷流程狀態(tài)是否為等候處理中,以及審批者是否為本部門(mén)主管。
結果(Result)
Result 代表執行Action(動(dòng)作)后的結果,指向新的 Step 及其 Step Status,也可能進(jìn)入 Split 或者 Join。Result 分為兩種, Contidional-Result (有條件結果),只有條件為真時(shí)才使用該結果,和 Unconditional-Result(無(wú)條件結果),當條件不滿(mǎn)足或沒(méi)有條件時(shí)使用該結果。
分離/連接(Split/Join)
流程的切分和融合。很簡(jiǎn)單的概念,Split 可以提供多個(gè) Result(結果);Join 則判斷多個(gè) Current Step 的態(tài)提供一個(gè) Result(結果)。
3.2. 步驟、狀態(tài)和動(dòng)作(Step, Status, and Action)
工作流要描述步驟(Step)、步驟的狀態(tài)(Status)、各個(gè)步驟之間的關(guān)系以及執行各個(gè)步驟的條件和權限,每個(gè)步驟中可以含有一個(gè)或多個(gè)動(dòng)作(Action),動(dòng)作將會(huì )使一個(gè)步驟的狀態(tài)發(fā)生改變。
對于一個(gè)執行的工作流來(lái)講,步驟的切換是不可避免的。一個(gè)工作流在某一時(shí)刻會(huì )有一個(gè)或多個(gè)當前步驟,每個(gè)當前步驟都有一個(gè)狀態(tài)值,當前步驟的狀態(tài)值組成了工作流實(shí)例的狀態(tài)值。一旦完成了一個(gè)步驟,那么這個(gè)步驟將不再是當前步驟(而是切換到一個(gè)新的步驟),通常一個(gè)新的當前步驟將隨之建立起來(lái),以保證工作流繼續執行。完成了的步驟的最終狀態(tài)值是用Old-Status屬性指定的,這個(gè)狀態(tài)值的設定將發(fā)生在切換到其他步驟之前。Old-Status的值可以是任意的,但在一般情況下,我們設置為Finished。
切換本身是一個(gè)動(dòng)作(Action)的執行結果。每個(gè)步驟可以含有多個(gè)動(dòng)作,究竟要載入哪個(gè)動(dòng)作是由最終用戶(hù)、外部事件或者Tiggerd的自動(dòng)調用決定的。隨著(zhù)動(dòng)作的完成,一個(gè)特定的步驟切換也將發(fā)生。動(dòng)作可以被限制在用戶(hù)、用戶(hù)組或當前狀態(tài)。每一個(gè)動(dòng)作都必須包含一個(gè)Unconditional Result和0個(gè)或多個(gè)Conditional Results。
所以,總體來(lái)說(shuō),一個(gè)工作流由多個(gè)步驟組成。每個(gè)步驟有一個(gè)當前狀態(tài)(例如:Queued, Underway or Finished),一個(gè)步驟包含多個(gè)動(dòng)作。每個(gè)步驟含有多個(gè)可以執行的動(dòng)作。每個(gè)動(dòng)作都有執行的條件,也有要執行的函數。動(dòng)作包含有可以改變狀態(tài)和當前工作流步驟的results。
3.3. 結果、分支和連接(Results, Joins, and Splits)
3.3.1. 無(wú)條件結果(Unconditional Result)
對于每一個(gè)動(dòng)作來(lái)講,必須存在一個(gè)Unconditional Result。一個(gè)result是一系列指令,這些指令將告訴OSWorkFlow下一個(gè)任務(wù)要做什么。這包括使工作流從一個(gè)狀態(tài)切換到另一個(gè)狀態(tài)。
3.3.2. 有條件結果(Conditional Result)
Conditional Result是Unconditional Result的一個(gè)擴展。它需要一個(gè)或多個(gè)Condition子標簽。第一個(gè)為true的Conditional(使用AND或OR類(lèi)型),會(huì )指明發(fā)生切換的步驟,這個(gè)切換步驟的發(fā)生是由于某個(gè)用戶(hù)執行了某個(gè)動(dòng)作的結果導致的。
3.3.3. 三種不同的Results(conditional or unconditional)
一個(gè)新的、單一的步驟和狀態(tài)的組合。
一個(gè)分裂成兩個(gè)或多個(gè)步驟和狀態(tài)的組合。
將這個(gè)和其他的切換組合成一個(gè)新的單一的步驟和狀態(tài)的組合。
每種不同的result對應了不同的xml描述,你可以閱讀
http://www.opensymphony.com/osworkflow/workflow_2_7.dtd,獲取更多的信息。
注意:通常,一個(gè)split或一個(gè)join不會(huì )再導致一個(gè)split 或 join的發(fā)生。
3.4. 自動(dòng)步驟(Auto actions)
有的時(shí)候,我們需要一些動(dòng)作可以基于一些條件自動(dòng)地執行。為了達到這個(gè)目的,你可以在action中加入auto="true"屬性。流程將考察這個(gè)動(dòng)作的條件和限制,如果條件符合,那么將執行這個(gè)動(dòng)作。 Auto action是由當前的調用者執行的,所以將對該動(dòng)作的調用者執行權限檢查。
3.5. 整合抽象實(shí)例(Integrating with Abstract Entities)
建議在你的核心實(shí)體中,例如"Document" 或 "Order",在內部創(chuàng )建一個(gè)新的屬性:workflowId。這樣,當新的"Document" 或 "Order"被創(chuàng )建的時(shí)候,它能夠和一個(gè)workflow實(shí)例關(guān)聯(lián)起來(lái)。那么,你的代碼可以通過(guò)OSWorkflow API查找到這個(gè)workflow實(shí)例并且得到這個(gè)workflow的信息和動(dòng)作。
3.6. 工作流實(shí)例狀態(tài)(Workflow Instance State)
有的時(shí)候,為整個(gè)workflow實(shí)例指定一個(gè)狀態(tài)是很有幫助的,它獨立于流程的執行步驟。OSWorkflow提供一些workflow實(shí)例中可以包含的"meta-states"。這些"meta-states"可以是CREATED, ACTIVATED, SUSPENDED, KILLED 和 COMPLETED。當一個(gè)工作流實(shí)例被創(chuàng )建的時(shí)候,它將處于CREATED狀態(tài)。然后,只要一個(gè)動(dòng)作被執行,它就會(huì )自動(dòng)的變成ACTIVATED狀態(tài)。如果調用者沒(méi)有明確地改變實(shí)例的狀態(tài),工作流將一直保持這個(gè)狀態(tài)直到工作流結束。當工作流不可能再執行任何其他的動(dòng)作的時(shí)候,工作流將自動(dòng)的變成COMPLETED狀態(tài)。
然而,當工作流處于A(yíng)CTIVATED狀態(tài)的時(shí)候,調用者可以終止或掛起這個(gè)工作流(設置工作流的狀態(tài)為KILLED 或 SUSPENDED)。一個(gè)終止了的工作流將不能再執行任何動(dòng)作,而且將永遠保持著(zhù)終止狀態(tài)。一個(gè)被掛起了的工作流會(huì )被凍結,他也不能執行任何的動(dòng)作,除非它的狀態(tài)再變成ACTIVATED。
4. OSWorkFlow包用途分析及代碼片斷
4.1. com.opensymphony.workflow
該包為整個(gè)OSWorkflow 引擎提供核心接口。例如 com.opensymphony.workflow.Workflow 接口,可以說(shuō),實(shí)際開(kāi)發(fā)中的大部分工作都是圍繞該接口展開(kāi)的,該接口有 BasicWorkflow、EJBWorkflow、OfbizWorkflow 三個(gè)實(shí)現類(lèi)。
4.2. com.opensymphony.workflow.basic
該包有兩個(gè)類(lèi),BasicWorkflow 與 BasicWorkflowContext。BasicWorkflow 不支持事務(wù),盡管依賴(lài)持久實(shí)現,事務(wù)也不能包裹它。BasicWorkflowContext 在實(shí)際開(kāi)發(fā)中很少使用。
public void setWorkflow(int userId) {
Workflow workflow = new BasicWorkflow(Integer.toString(userId));
}
4.3. com.opensymphony.workflow.config
該包有一個(gè)接口和兩個(gè)該接口的實(shí)現類(lèi)。在 OSWorkflow 2.7 以前,狀態(tài)由多個(gè)地方的靜態(tài)字段維護,這種方式很方便,但是有很多缺陷和約束。最主要的缺點(diǎn)是無(wú)法通過(guò)不同配置運行多個(gè) OSWorkflow 實(shí)例。實(shí)現類(lèi) DefaultConfiguration 用于一般的配置文件載入。而 SpringConfiguration 則是讓 Spring 容器管理配置信息。
public void setWorkflow(int userId) {
Workflow workflow = new BasicWorkflow(Integer.toString(userId));
}
4.4. com.opensymphony.workflow.ejb
該包有兩個(gè)接口 WorkflowHome 和 WorkflowRemote。該包的若干類(lèi)中,最重要的是 EJBWorkflow,該類(lèi)和 BasicWorkflow 的作用一樣,是 OSWorkflow 的核心,并利用 EJB 容器管理事務(wù),也作為工作流 session bean 的包裝器。
4.5. com.opensymphony.workflow.loader
該包有若干類(lèi),用得最多的是 XxxxDescriptor,如果在工作流引擎運行時(shí)需要了解指定的動(dòng)作、步驟的狀態(tài)、名字,等信息時(shí),這些描述符會(huì )起到很大作用。
public String findNameByStepId(int stepId,String wfName) {
WorkflowDescriptor wd = workflow.getWorkflowDescriptor(wfName);
StepDescriptor stepDes = wd.getStep(stepId);
return stepDes.getName();
}
4.6. com.opensymphony.workflow.ofbiz
OfbizWorkflow 和 BasicWorkflow 在很多方面非常相似,除了需要調用 ofbiz 的 TransactionUtil 來(lái)包裝事務(wù)。
4.7. com.opensymphony.workflow.query
該包主要為查詢(xún)而設計,但不是所有的工作流存儲都支持查詢(xún)。通常,Hibernate 和 JDBC 都支持,而內存工作流存儲不支持。值得注意的是 Hibernate 存儲不支持混合型查詢(xún)(例如,一個(gè)查詢(xún)同時(shí)包含了 history step 上下文和 current step 上下文)。執行一個(gè)查詢(xún),需要創(chuàng )建 WorkflowExpressionQuery 實(shí)例,接著(zhù)調用 Workflow 對象的 query 方法來(lái)得到最終查詢(xún)結果。
public List queryDepAdmin(int userId,int type) {
int[] arr = getSubPerson(userId,type);
//構造表達式
Expression[] expressions = new Expression[1 + arr.length];
Expression expStatus = new FieldExpression(FieldExpression.STATUS,
FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, "Queued");
expressions[0] = expStatus;
for (int i = 0; i < arr.length; i++) {
Expression expOwner = new FieldExpression(FieldExpression.OWNER,
FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS,
Integer.toString(arr[i]));
expressions[i + 1] = expOwner;
}
//查詢(xún)未完成流編號
List wfIdList = null;
try {
WorkflowExpressionQuery query = new WorkflowExpressionQuery(
new NestedExpression(expressions, NestedExpression.AND));
wfIdList = workflow.query(query);
} catch (Exception e) {
e.printStackTrace();
}
}
4.8. com.opensymphony.workflow.soap
OSWorkflow 通過(guò) SOAP 來(lái)支持遠端調用。這種調用借助 WebMethods 實(shí)現。
4.9. com.opensymphony.workflow.spi
該包可以說(shuō)是 OSWorkflow 與持久層打交道的途徑,如當前工作流的實(shí)體,其中包括:EJB、Hibernate、JDBC、Memory、Ofbiz、OJB、Prevayler。
HibernateWorkflowEntry hwfe = (HibernateWorkflowEntry) getHibernateTemplate()
.find("from HibernateWorkflowEntry where Id="
+ wfIdList.get(i)).get(0);
4.10. com.opensymphony.workflow.util
該包是 OSWorkflow 的工具包,包括了對 BeanShell、BSF、EJB Local、EJB Remote、JNDI 的支持。
5. OSWorkFlow表結構分析
5.1. OS_WFENTRY
工作流主表,存放工作流名稱(chēng)和狀態(tài)
字段名 數據類(lèi)型 說(shuō)明
ID NUMBER 自動(dòng)編號
NAME VARCHAR2(20) 工作流名稱(chēng)
STATE NUMBER 工作流狀態(tài)
5.2. OS_CURRENTSTEP
當前步驟表,存放當前正在進(jìn)行步驟的數據
字段名 數據類(lèi)型 說(shuō)明
ID NUMBER 自動(dòng)編號
ENTRY_ID NUMBER 工作流編號
STEP_ID NUMBER 步驟編號
ACTION_ID NUMBER 動(dòng)作編號
OWNER VARCHAR2(20) 步驟的所有者
START_DATE DATE 開(kāi)始時(shí)間
FINISH_DATE DATE 結束時(shí)間
DUE_DATE DATE 授權時(shí)間
STATUS VARCHAR2(20) 狀態(tài)
CALLER VARCHAR2(20) 操作人員的賬號名稱(chēng)
5.3. OS_CURRENTSTEP_PREV
前步驟表,存放當前步驟和上一個(gè)步驟的關(guān)聯(lián)數據
字段名 數據類(lèi)型 說(shuō)明
ID NUMBER 當前步驟編號
PREVIOUS NUMBER 前步驟編號
5.4. OS_HISTORYSTEP
歷史步驟表,存放當前正在進(jìn)行步驟的數據
字段名 數據類(lèi)型 說(shuō)明
ID NUMBER 自動(dòng)編號
ENTRY_ID NUMBER 工作流編號
STEP_ID NUMBER 步驟編號
ACTION_ID NUMBER 動(dòng)作編號
OWNER VARCHAR2(20) 步驟的所有者
START_DATE DATE 開(kāi)始時(shí)間
FINISH_DATE DATE 結束時(shí)間
DUE_DATE DATE 授權時(shí)間
STATUS VARCHAR2(20) 狀態(tài)
CALLER VARCHAR2(20) 操作人員的賬號名稱(chēng)
5.5. OS_HISTORYSTEP_PREV
前歷史步驟表,存放歷史步驟和上一個(gè)步驟的關(guān)聯(lián)數據
字段名 數據類(lèi)型 說(shuō)明
ID NUMBER 當前歷史步驟編號
PREVIOUS NUMBER 前歷史步驟編號
5.6. OS_PROPERTYENTRY
屬性表,存放臨時(shí)變量
字段名 數據類(lèi)型 說(shuō)明
GLOBAL_KEY VARCHAR2(255) 全局關(guān)鍵字
ITEM_KEY VARCHAR2(255) 條目關(guān)鍵字
ITEM_TYPE NUMBER 條目類(lèi)型
STRING_VALUE VARCHAR2(255) 字符值
DATE_VALUE DATE 日期值
DATA_VALUE BLOB 數據值
FLOAT_VALUE FLOAT 浮點(diǎn)值
NUMBER_VALUE NUMBER 數字值