轉自:http://blog.csdn.net/gekie/archive/2005/03/12/318117.aspx
h3 建立描述符
首先,讓我們來定義工作流程。你可以使用任何名字來命名工作流程。一個工作流程對應一個XML格式的定義檔案。讓我們來開始建立一個“myworkflow.xml”的檔案,這是樣板檔案:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.7//EN" "http://www.opensymphony.com/osworkflow/workflow_2_7.dtd">
<workflow>
<initial-actions> ... </initial-actions>
<steps> ... </steps>
</workflow>
首先是標準的XML頭部,要注意的是OSWorkflow將會通過這些指定的DTD來驗證XML內容的合法性。你可以使用絕大多數的XML編輯工具來編輯它,並且可以highlight相應的錯誤。
h3 步驟和動作
接 下來我們來定義初始化動作和步驟。首先需要理解的OSWorkflow重要概念是steps (步驟) 和 actions (動作)。一個步驟是工作流程所處的位置,比如一個簡單的工作流程過程,它可能從一個步驟流轉到另外一個步驟(或者有時候還是停留在一樣的步驟)。舉例來說, 一個文件管理系統的流程,它的步驟名稱可能有“First Draft - 草案初稿”,“Edit Stage -編輯階段”,“At publisher - 出版商”等。
動作指定了可能發生在步驟內的轉變,通常會導致步驟的變更。在我們的檔案管理系統中,在“草案初稿”這個步驟可能有“start first draft - 開始草案初稿”和“complete first draft - 完成草案初稿”這樣2個動作。
簡單的說,步驟是“在哪裡”,動作是“可以去哪裡”。
初始化步驟是一種特殊類型的步驟,它用來啟動工作流程。在一個工作流程開始前,它是沒有狀態,不處在任何一個步驟,使用者必須採取某些動作才能開始這個流程。這些特殊步驟被定義在 <initial-actions>。
在我們的例子裡面,假定只有一個簡單的初始化步驟:“Start Workflow”,它的定義在裡面<initial-actions>:
<action id="1" name="Start Workflow">
<results>
<unconditional-result old-status="Finished" status="Queued" step="1"/>
</results>
</action>
這個動作是最簡單的類型,只是簡單地指明了下一個我們要去的步驟和狀態。
h3 工作流程狀態
工作流程狀態是一個用來描述工作流程中具體步驟狀態的字串。在我們的文件管理系統中,在“草案初稿”這個步驟可能有2個不同的狀態:“Underway - 進行中”和“Queued - 等候處理中”
我 們使用“Queued”指明這個條目已經被排入“First Draft”步驟的隊列。比如說某人請求編寫某篇文檔,但是還沒有指定作者,那麼這個文檔在“First Draft”步驟的狀態就是“Queued”。“Underway”狀態被用來指明一個作者已經挑選了一篇文檔開始撰寫,而且可能正在鎖定這篇文檔。
h3 第一個步驟
讓我們來看第一個步驟是怎樣被定義在<steps>元素中的。我們有2個動作:第一個動作是保持當前步驟不變,只是改變了狀態到“Underway”,第二個動作是移動到工作流程的下一步驟。我們來添加如下的內容到<steps>元素:
<step id="1" name="First Draft">
<actions>
<action id="1" name="Start First Draft">
<results>
<unconditional-result old-status="Finished" status="Underway" step="1"/>
</results>
</action>
<action id="2" name="Finish First Draft">
<results>
<unconditional-result old-status="Finished" status="Queued" step="2"/>
</results>
</action>
</actions></step>
<step id="2" name="finished" />
這樣我們就定義了2個動作,old-status屬性是用來指明當前步驟完成以後的狀態是什麼,在大多數的應用中,通常用"Finished"表示。
上 面定義的這2個動作是沒有任何限制的。比如,一個使用者可以調用action 2而不用先調用action 1。很明顯的,我們如果沒有開始撰寫草稿,是不可能去完成一個草稿的。同樣的,上面的定義也允許你開始撰寫草稿多次,這也是毫無意義的。我們也沒有做任何 的處理去限制其他使用者完成別人的草稿。這些都應該需要想辦法避免。
讓我們來一次解決這些問題。首先,我們需要指定只有工作流程的狀態為“Queued”的時候,一個caller (調用者)才能開始撰寫草稿的動作。這樣就可以阻止其他使用者多次調用開始撰寫草稿的動作。我們需要指定動作的約束,約束是由Condition(條件)組成。
h3 條件
OSWorkflow 有很多有用的內建條件可以使用。在此相關的條件是“StatusCondition - 狀態條件”。 條件也可以接受參數,參數的名稱通常被定義在javadocs裡(如果是使用Java Class實現的條件的話)。在這個例子裡面,狀態條件接受一個名為“status”的參數,指明了需要檢查的狀態條件。我們可以從下面的xml定義裡面 清楚的理解:
<action id="1" name="Start First Draft">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.StatusCondition
</arg>
<arg name="status">Queued</arg>
</condition>
</conditions>
</restrict-to>
<results>
<unconditional-result old-status="Finished" status="Underway" step="1"/>
</results></action>
希望對於條件的理解現在已經清楚了。上面的條件定義保證了動作1隻能在目前狀態為“Queued”的時候才能被調用,也就是說在初始化動作被調用以後。
h3 函數
接下來,我們想在一個使用者開始撰寫草稿以後,設定他為“owner”。為了達到這樣的目的,我們需要做2件事情:
1) 通過一個函數設定“caller”變數在當前的環境設定裡。
2) 根據“caller”變數來設定“owner”屬性。
函數是OSWorkflow的一個功能強大的特性。函數基本上是一個在工作流程中的工作單位,他不會影響到流程本身。舉例來說,你可能有一個“SendEmail”的函數,用來在某些特定的流程流轉寄生時來發送email提醒。
函數也可以用來添加變數到當前的環境設定裡。變數是一個指定名稱的對象,可以用來在工作流程中被以後的函數或者指令碼使用。
OSWorkflow提供了一些內建的常用函數。其中一個稱為“Caller”,這個函數會獲得當前調用工作流程的使用者,並把它放入一個名為“caller”的字元型變數中。
因為我們需要追蹤是哪個使用者開始了編寫草稿,所以可以使用這個函數來修改我們的動作定義:
<action id="1" name="Start First Draft">
<pre-functions>
<function type="class">
<arg name="class.name">com.opensymphony.workflow.util.Caller</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished" status="Underway"step="1" owner="${caller}"/>
</results>
</action>
h3 組合起來
把這些概念都組合起來,這樣我們就有了動作1:
<action id="1" name="Start First Draft">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">com.opensymphony.workflow.util.StatusCondition</arg>
<arg name="status">Queued</arg>
</condition>
</conditions>
</restrict-to>
<pre-functions>
<function type="class">
<arg name="class.name">com.opensymphony.workflow.util.Caller</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished" status="Underway" step="1" owner="${caller}"/>
</results>
</action>
我們使用類似想法來設定動作2:
<action id="2" name="Finish First Draft">
<restrict-to>
<conditions type="AND">
<condition type="class">
<arg name="class.name">com.opensymphony.workflow.util.StatusCondition </arg>
<arg name="status">Underway</arg>
</condition>
<condition type="class">
<arg name="class.name">com.opensymphony.workflow.util.AllowOwnerOnlyCondition </arg>
</condition>
</conditions>
</restrict-to>
<results>
<unconditional-result old-status="Finished" status="Queued" step="2"/>
</results>
</action>
在這裡我們指定了一個新的條件:“allow owner only”。這樣能夠保證只有開始撰寫這份草稿的使用者才能完成它。而狀態條件確保了只有在“Underway”狀態下的流程才能調用“finish first draft”動作。
把他們組合在一起,我們就有了第一個流程定義:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.7//EN" "http://www.opensymphony.com/osworkflow/workflow_2_7.dtd">
<workflow>
<initial-actions>
<action id="1" name="Start Workflow">
<results>
<unconditional-result old-status="Finished" status="Queued" step="1"/>
</results>
</action>
</initial-actions>
<steps>
<step id="1" name="First Draft">
<actions>
<action id="1" name="Start First Draft">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">com.opensymphony.workflow.util.StatusCondition </arg>
<arg name="status">Queued</arg>
</condition>
</conditions>
</restrict-to>
<pre-functions>
<function type="class">
<arg name="class.name"> com.opensymphony.workflow.util.Caller</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished" status="Underway" step="1" owner="${caller}"/>
</results>
</action>
<action id="2" name="Finish First Draft">
<restrict-to>
<conditions type="AND">
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.StatusCondition
</arg>
<arg name="status">Underway</arg>
</condition>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.AllowOwnerOnlyCondition
</arg>
</condition>
</conditions>
</restrict-to>
<results>
<unconditional-result old-status="Finished" status="Queued" step="2"/>
</results>
</action>
</actions>
</step>
<step id="2" name="finished" />
</steps>
</workflow>
現在這個工作流程的定義已經完整了,讓我們來測試和檢查它的運行。