1.
步驟、狀態和動作
工作流要描述步驟
(step)
、步驟的狀態
(status)
、各個步驟之間的關系以及執行各個步驟的條件和權限,每個步驟中可以含有一個或多個動作
(action)
,動作將會使一個步驟的狀態發生改變。
對于一個執行的工作流來講,步驟的切換是不可避免的。一個工作流在某一時刻會有一個或多個當前步驟,每個當前步驟都有一個狀態值,當前步驟的狀態值組成了工作流實例的狀態值。一旦完成了一個步驟,那么這個步驟將不再是當前步驟(而是切換到一個新的步驟),通常一個新的當前步驟將隨之建立起來,以保證工作流繼續執行。完成了的步驟的最終狀態值是用
old-status
屬性指定的,這個狀態值的設定將發生在切換到其他步驟之前。
old-status
的值可以是任意的,但在一般情況下,我們設置為
Finished
。
切換本身是一個動作(
action
)的執行結果。每個步驟可以含有多個動作,究竟要載入哪個動作是由最終用戶、外部事件或者
triggerd
的自動調用決定的。隨著動作的完成,一個特定的步驟切換也將發生。動作可以被限制在用戶、用戶組或當前狀態。每一個動作都必須包含一個
unconditional result
和
0
個或多個
conditional results
。
所以,總體來說,一個工作流由多個步驟組成。每個步驟有一個當前狀態(例如:
Queued, Underway, or Finished
),一個步驟包含多個動作。每個步驟含有多個可以執行的動作。每個動作都有執行的條件,也有要執行的函數。動作包含有可以改變狀態和當前工作流步驟的
results
。
2. Results, Joins, and Splits
(1) Unconditional Result
對于每一個動作來講,必須存在一個
Unconditional Result
。一個
result
是一系列指令,這些指令將告訴
OSWorkFlow
下一個任務要做什么。這包括使工作流從一個狀態切換到另一個狀態。
(2) conditional Result
conditional Result
是
unconditional Result
的一個擴展。它需要一個或多個
condition
子標簽。第一個為
true
的
conditional
(使用
AND
或
OR
類型),會指明發生切換的步驟,這個切換步驟的發生是由于某個用戶執行了某個動作的結果導致的。
(3)
三種不同的
Results
(
conditional or unconditional
)
?--
一個新的、單一的步驟和狀態的組合。
?--
一個分裂成兩個或多個步驟和狀態的組合。
?--
將這個和其他的切換組合成一個新的單一的步驟和狀態的組合。
?
每種不同的
result
對應了不同的
xml
描述,你可以閱讀
http://www.opensymphony.com/osworkflow/workflow_2_6.dtd
,獲取更多的信息。
?
注意:通常,一個
split
或一個
join
不會再導致一個
split
或
join
的發生。
①
單一步驟和狀態的結果可以這樣描述:
<unconditional-result old-status="Finished" step="2" status="Underway" owner="${someOwner}"/>
如果狀態不是
Queued
的話,那么第三個必要條件就是新步驟的所有者(
owner
)。除了可以指明下一個狀態的信息之外,
result
也可以指定
validators
和
post-functions
,這將在下面討論。
②
從一個狀態分裂成多個狀態可以這樣描述:
<unconditional-result split="1"/>
...
<splits>
? <split id="1">
??? <unconditional-result old-status="Finished" step="2"
????????????????????????? status="Underway" owner="${someOwner}"/>
??? <unconditional-result old-status="Finished" step="2"
????????????????????????? status="Underway" owner="${someOtherOwner}"/>
? </split>
</splits>
③
將多個狀態合并為一個狀態可以這樣描述:
<!-- for step id 6 ->
<unconditional-result join="1"/>
...
<!- for step id 8 ->
<unconditional-result join="1"/>
...
<joins>
? <join id="1">
??? <conditions type="AND">
????? <condition type="beanshell">
??????? <arg name="script">
?
????????"Finished".equals(jn.getStep(6).getStatus()
????????? && "Finished".equals(jn.getStep(8).getStatus())
??????? </arg>
????? </condition>
??? </conditions>
? <unconditional-result old-status="Finished" status="Underway" owner="test" step="2"/>
? </join>
</joins>
上面的描述也許有點含糊,但是你最應該關注的是
condition
標簽,它使用一個
"jn"
的變量,利用這個變量,你可以組成表達式來決定合并動作發生的條件。這個表達式的意思是說:“當
id=6
和
id=8
的步驟的狀態都變成
Finished
的狀態并且他們要發生的切換都是
join="1"
時,這個合并動作才發生”。
3.
外部函數
OSWorkFlow
為要定義和執行的外部業務邏輯定義了一個標準的解決方法。這是通過使用
"functions"
來實現的。
OSWorkFlow
有兩種
function
,
pre
和
post step functions
。
Pre functions
是在流程的步驟發生切換之前執行的。一個例子是取得調用者名字的函數,將取得的調用者的名字作為要發生狀態切換的
result
使用。另外一個例子是
pre-function
用來更新大多數的動作的最近調用者。這兩個函數是做為標準的工具函數提供的,在實際的工作流中非常實用。
Post functions
與
Pre functions
有著同樣的適用范圍,不同點在于
Post functions
是在狀態發生變化之后執行的。一個典型的
Post functions
的例子是:在某個動作執行完畢后,給某些人發送電子郵件。例如:當一個文檔處于
'research'
步驟,并且執行了
'markReadyForReview'
動作的時候,要發送郵件給所有的
reviewers
。
使用
Post functions
與
Pre functions
可能有很多原因。一個是如果用戶點擊完成按鈕兩次而且發送了兩次執行動作的指令,而且這個動作的
Pre function
會執行很長時間,那么這個長時間執行的函數可能會被執行多次,因為切換動作還沒有發生,這時
OSWorkflow
會認為第二次執行動作是合理的。所以要將這個函數改變成
Post function
。一般情況下,
Pre function
應該是簡單的、能快速執行的函數。
函數可以定義在兩個獨立的位置:步驟
(step)
和動作
(action)
。
通常情況下,
Post functions
與
Pre functions
被定義在
action
中。在
action
中定義的
Pre-functions
是指在該動作發生之前要執行的函數。當工作流發生切換的時候,函數用來做某些事情,不管是發送
E_mail
也好,還是為以后的使用設置變量。
當
Post functions
與
Pre functions
被定義在
step
中的時候,用途就有點不同了。在
step
中定義的
Pre-functions
是指在切換到這個
step
之前要執行
的函數。注意:這些函數將被應用到這個步驟的所有的切換,即使是由于這個步驟本身發起的切換,例如:在同一個步驟內,由
Queued
狀態轉移到
Underway
狀態時,也將調用所有的
Pre functions
。與此相同,在
step
中的
Post functions
將在流程離開這個步驟之前。
4. Trigger Functions
Trigger Functions
與其他函數一樣,不同點在于他們不是與一個動作相聯系的。他們也是通過一個唯一的
ID
來標識。這些函數通常是運行在系統級用戶或非正規用戶的環境中。
Trigger functions
是通過
OSWorkflow
的
API
來使用。
5. Validators
validator
是用來校驗一個動作的輸入的有效性的。如果輸入符合條件,那么將執行這個動作。如果輸入不符合條件,那么將拋出
InvalidInputException
異常。
6. Registers
A register
是一個輔助函數,這個函數可以返回一個對象,這個對象可以用在函數中去訪問其他的普通對象,特別是出現在
workflow
中的實體。被注冊的對象可以是任何類型,典型的注冊對象的例子是:
Document, Metadata, Issue,
和
Task
。
下面是一個
registers
的例子:
<registers>
?????? <register name="doc" class="com.acme.DocumentRegister"/>
</registers>
...
<results>
?????? <result condition="doc.priority == 1" step="1" status="Underway"
????????????????? owner="${someManager}"/>
?????? <unconditional-result step="1" status="Queued"/>
</results>
...
7. Conditions
Conditions
就象
validators
,
registers
和
functions
一樣,可以用不同的語言和技術來實現。
Conditions
可以用
AND
或
OR
邏輯運算符來組織。
Conditions
通常是與
conditional results
聯系的,只有當條件成立,
result
才會執行。
Conditions
與函數很相似,唯一不同的是
Conditions
返回的是
boolean
值,而不是
void
。
8. Variable Interpolation
在所有的
functions
、
conditions
、
validators
和
registers
中,可能要提供一系列的參數。這些參數將會被轉化為參數
Map
,這將在后面討論。同樣,在
workflow
描述符中的
status
,
old-status
和
owner
標簽也將被動態的解析成變量。一個變量是這樣被識別的:
${foo}
。當
OSWorkflow
識別出這種格式的時候,它首先到
transientVars
中去找關鍵字為
foo
的對象,如果沒有找到,那么就到
propertySet
中去找,如果也沒找到,那么變量
foo
將被轉換為一個空字串。
?
One thing of particular importance is that in the case of args, if the variable is the only argument, the argument will not be of type String, but instead whatever the variable type is. However, if the arg is a mix of characters and variables, the entire argument is converted to String no matter what. That means the two arguments below are very different in that foo is a Date object and bar is a String:
<arg name="foo">${someDate}</arg>
<arg name="bar"> ${someDate} </arg> <!--
注意多余的空格
-->
9. Permissions and Restrictions
Permissions can be assigned to users and/or groups based on the state of the workflow instance. These permissions are unrelated to the functionality of the workflow engine, but they are useful to have for applications that implement OSWorkflow. For example, a document management system might have the permission name "file-write-permission" enabled for a particular group only during the "Document Edit" stage of the workflow. That way your application can use the API to determine if files can be modified or not. This is useful as there could be a number of states within the workflow where the "file-write-permission" is applicable, so instead of checking for specific steps or conditions, the check can simply be made for a particular permission.
?
10. Auto actions
有的時候,我們需要一些動作可以基于一些條件自動地執行。為了達到這個目的,你可以在
action
中加入
auto="true"
屬性。流程將考察這個動作的條件和限制,如果條件符合,那么將執行這個動作。
Auto action
是由當前的調用者執行的,所以將對該動作的調用者執行權限檢查。
11. Integrating with Abstract Entities
建議在你的核心實體中,例如
"Document"
或
"Order"
,在內部創建一個新的屬性:
workflowId
。這樣,當新的
"Document"
或
"Order"
被創建的時候,它能夠和一個
workflow
實例關聯起來。那么,你的代碼可以通過
OSWorkflow API
查找到這個
workflow
實例并且得到這個
workflow
的信息和動作。
12. Workflow Instance State
有的時候,為整個
workflow
實例指定一個狀態是很有幫助的,它獨立于流程的執行步驟。
OSWorkflow
提供一些
workflow
實例中可以包含的
"meta-states"
。這些
"meta-states"
可以是
CREATED, ACTIVATED, SUSPENDED, KILLED
和
COMPLETED
。當一個工作流實例被創建的時候,它將處于
CREATED
狀態。然后,只要一個動作被執行,它就會自動的變成
ACTIVATED
狀態。如果調用者沒有明確地改變實例的狀態,工作流將一直保持這個狀態直到工作流結束。當工作流不可能再執行任何其他的動作的時候,工作流將自動的變成
COMPLETED
狀態。
?
然而,當工作流處于
ACTIVATED
狀態的時候,調用者可以終止或掛起這個工作流(設置工作流的狀態為
KILLED
或
SUSPENDED
)。一個終止了的工作流將不能再執行任何動作,而且將永遠保持著終止狀態。一個被掛起了的工作流會被凍結,他也不能執行任何的動作,除非它的狀態再變成
ACTIVATED
。