在上一下节中,我们曾写道讲解了step的prefunction以及postfunction,其实都是标签层面的讲解,因为在后文中我们将要详细描述Function组建,这在osworkflow中占有非常重要的位置,上一节中还有两个step非常重要的概念,那就是split和join,我们在本节中详细说明。
先来说说split和join的作用是什么,我们不妨来看看如下的状态图。
通过上图可以看出当请假条直接上司审批之后,还需要两个部门*审批,只有两个领导审批通过之后,最终到最高领导处审批,最高领导审批通过才算成功!
通过上面的文字描述和图示,我们不难看出有两个非常重要的概念,那就是拆分和联合,也就是split和join,这种情况也是一个流程引擎中必须具备的功能。
针对上面的流程图,我们不难写出配置文件,配置文件如下所示!
<?xml version="1.0" encoding="UTF-8"?>对照着上文中的描述,我们将xml写了出来,其中在joins中有一个非常重要的上下文常量,叫做jn,其中jn是JoinNodes对象的一个实例,在该示例中提供了若干个方法,其中有一个方法getStep,可以通过他获取step的实例对象,在后文中讲解源码的时候都会讲解到,耐心等待吧。
<!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>
写完了配置文件,就直接单元测试呗,看看我们的流程是否行得通!
@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)>Splits标签
<!ATTLIST join
id CDATA #REQUIRED
>
<!--
A list of join elements.
Used in: workflow
-->
<!ELEMENT joins (join*)>
<!ELEMENT split (unconditional-result+)>好了,本节的内容描述完毕!下节再见!
<!ATTLIST split
id CDATA #REQUIRED
>
<!--
List of split elements.
Used in: workflow
-->
<!ELEMENT splits (split+)>