在上一下節中,我們曾寫道講解了step的prefunction以及postfunction,其實都是標籤層面的講解,因爲在後文中我們將要詳細描述Function組建,這在osworkflow中佔有非常重要的位置,上一節中還有兩個step非常重要的概念,那就是split和join,我們在本節中詳細說明。
先來說說split和join的作用是什麼,我們不妨來看看如下的狀態圖。
通過上圖可以看出當請假條直接上司審批之後,還需要兩個部門領導人審批,只有兩個領導審批通過之後,最終到最高領導處審批,最高領導審批通過纔算成功!
通過上面的文字描述和圖示,我們不難看出有兩個非常重要的概念,那就是拆分和聯合,也就是split和join,這種情況也是一個流程引擎中必須具備的功能。
針對上面的流程圖,我們不難寫出配置文件,配置文件如下所示!
<?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="100" name="請假初始化">
<results>
<unconditional-result old-status="Finished"
status="Underway" step="1" owner="step" />
</results>
</action>
</initial-actions>
<steps>
<step id="1" name="員工請假">
<actions>
<action id="1" name="請假">
<results>
<unconditional-result old-status="Finished"
status="Underway" step="2" />
</results>
</action>
</actions>
</step>
<step id="2" name="直接上司審批">
<actions>
<action id="2" name="上司審批">
<results>
<unconditional-result old-status="Finished"
status="Underway" split="1" />
</results>
</action>
</actions>
</step>
<step id="4" name="部門領導A審批">
<actions>
<action id="4" name="領導A審批">
<results>
<unconditional-result old-status="Finished"
status="Underway" join="1" />
</results>
</action>
</actions>
</step>
<step id="5" name="部門領導B審批">
<actions>
<action id="5" name="領導B審批">
<results>
<unconditional-result old-status="Finished"
status="Underway" join="1" />
</results>
</action>
</actions>
</step>
<step id="6" name="最高領導審批">
<actions>
<action id="6" name="最高領導審批" finish="true">
<results>
<unconditional-result old-status="Finished"
status="Underway" step="6" />
</results>
</action>
</actions>
</step>
</steps>
<splits>
<split id="1">
<unconditional-result old-status="Finished"
status="Underway" step="4" />
<unconditional-result old-status="Finished"
status="Underway" step="5" />
</split>
</splits>
<joins>
<join id="1">
<conditions type="AND">
<condition type="beanshell">
<arg name="script"><![CDATA[
"Finished".equals(jn.getStep(4).getStatus())
&& "Finished".equals(jn.getStep(5).getStatus())
]]></arg>
</condition>
</conditions>
<unconditional-result old-status="Finished"
status="Underway" step="6" />
</join>
</joins>
</workflow>
對照着上文中的描述,我們將xml寫了出來,其中在joins中有一個非常重要的上下文常量,叫做jn,其中jn是JoinNodes對象的一個實例,在該示例中提供了若干個方法,其中有一個方法getStep,可以通過他獲取step的實例對象,在後文中講解源碼的時候都會講解到,耐心等待吧。
寫完了配置文件,就直接單元測試唄,看看我們的流程是否行得通!
@Test
public void testJoinAndSplit()
{
long id ;
try {
id = wf.initialize("joinsplit", 100, null);
List currentSteps = wf.getCurrentSteps(id);
/*系統初始化之後只有一個step可以執行,那就是step,也就是請假單發起的步驟*/
Assert.assertEquals(1, currentSteps.size());
Assert.assertEquals(1,((SimpleStep)currentSteps.get(0)).getId());
/*執行請假申請流程*/
wf.doAction(id, 1, Collections.EMPTY_MAP);
/*接下來應該到直接上級*/
currentSteps = wf.getCurrentSteps(id);
Assert.assertEquals(1, currentSteps.size());
/*直接上級的step爲2*/
Assert.assertEquals(2,((SimpleStep)currentSteps.get(0)).getId());
/*獲取執行歷史*/
List historySteps = wf.getHistorySteps(id);
/*只有一個執行歷史*/
Assert.assertEquals(1, currentSteps.size());
/*直接上級審批通過*/
wf.doAction(id, 2, Collections.EMPTY_MAP);
/*接下來應該到了兩位部門領導哪裏,因此需要執行的步驟應該有兩個纔對*/
currentSteps = wf.getCurrentSteps(id);
Assert.assertEquals(2, currentSteps.size());
/*部門領導A審批*/
wf.doAction(id, 4, Collections.EMPTY_MAP);
/*部門領導B審批*/
wf.doAction(id, 5, Collections.EMPTY_MAP);
/*接下來應該到了最高領導哪裏,因此需要執行的步驟應該有1個纔對*/
currentSteps = wf.getCurrentSteps(id);
Assert.assertEquals(1, currentSteps.size());
/*最高領導審批*/
wf.doAction(id, 6, Collections.EMPTY_MAP);
/*流程執行完畢*/
Assert.assertEquals(WorkflowEntry.COMPLETED, wf.getEntryState(id));
historySteps = wf.getHistorySteps(id);
Assert.assertEquals(5, historySteps.size());
} catch (InvalidActionException e) {
e.printStackTrace();
} catch (InvalidRoleException e) {
e.printStackTrace();
} catch (InvalidInputException e) {
e.printStackTrace();
} catch (InvalidEntryStateException e) {
e.printStackTrace();
} catch (WorkflowException e) {
e.printStackTrace();
}
}
執行單元測試,順利通過,並且我們的期望都得到了正確的驗證,通過上面的例子,您是不是對join和split標籤有了一個比較清楚的認識呢?如果不瞭解標籤如何配置,我給您的建議是直接打開dtd文件,非常直觀,如下所示
joins標籤:
<!ELEMENT join (conditions, unconditional-result)>
<!ATTLIST join
id CDATA #REQUIRED
>
<!--
A list of join elements.
Used in: workflow
-->
<!ELEMENT joins (join*)>
Splits標籤<!ELEMENT split (unconditional-result+)>
<!ATTLIST split
id CDATA #REQUIRED
>
<!--
List of split elements.
Used in: workflow
-->
<!ELEMENT splits (split+)>
好了,本節的內容描述完畢!下節再見!