寫一個簡單的工作流(二)
hoho,今天完成了選擇路由的實現,完成了配置文件的讀寫和解析,流程定義文件還是決定采用xml文件,不過與其他工作流引擎采用的xml完全不同,因為是基於petri網的,因此引入了place的概念,比如下麵這個4個節點的順序路由的流程:
<workflow maxCases="100">
<node type="start" name="start" id="0">
<inputs>
<place id="1" />
</inputs>
<outputs>
<place id="2" />
</outputs>
</node>
<node name="hello" id="1" resource="user">
<conditions type="and">
<condition
class="net.rubyeye.insect.workflow.impl.NullHandler" value="false"
variable-name="name" />
</conditions>
<handler
class="net.rubyeye.insect.workflow.test.HelloWorldHandler" />
<inputs>
<place id="2" />
</inputs>
<outputs>
<place id="3" />
</outputs>
</node>
<node name="calc" id="2" resource="user">
<conditions type="and">
<condition variable-name="num">
<exp>
<![CDATA[num<=1000]]>
</exp>
</condition>
<conditions type="or">
<condition variable-name="num">
<exp>
<![CDATA[num>=10]]>
</exp>
</condition>
<condition
class="net.rubyeye.insect.workflow.impl.NullHandler" value="false"
variable-name="name" />
</conditions>
</conditions>
<handler
class="net.rubyeye.insect.workflow.test.CalculateHandler" />
<inputs>
<place id="3" />
</inputs>
<outputs>
<place id="4" />
</outputs>
</node>
<node type="end" name="hello" id="3">
<inputs>
<place id="4" />
</inputs>
<outputs>
<place id="5" />
</outputs>
</node>
</workflow>
<node type="start" name="start" id="0">
<inputs>
<place id="1" />
</inputs>
<outputs>
<place id="2" />
</outputs>
</node>
<node name="hello" id="1" resource="user">
<conditions type="and">
<condition
class="net.rubyeye.insect.workflow.impl.NullHandler" value="false"
variable-name="name" />
</conditions>
<handler
class="net.rubyeye.insect.workflow.test.HelloWorldHandler" />
<inputs>
<place id="2" />
</inputs>
<outputs>
<place id="3" />
</outputs>
</node>
<node name="calc" id="2" resource="user">
<conditions type="and">
<condition variable-name="num">
<exp>
<![CDATA[num<=1000]]>
</exp>
</condition>
<conditions type="or">
<condition variable-name="num">
<exp>
<![CDATA[num>=10]]>
</exp>
</condition>
<condition
class="net.rubyeye.insect.workflow.impl.NullHandler" value="false"
variable-name="name" />
</conditions>
</conditions>
<handler
class="net.rubyeye.insect.workflow.test.CalculateHandler" />
<inputs>
<place id="3" />
</inputs>
<outputs>
<place id="4" />
</outputs>
</node>
<node type="end" name="hello" id="3">
<inputs>
<place id="4" />
</inputs>
<outputs>
<place id="5" />
</outputs>
</node>
</workflow>
並行路由和選擇路由引入了and-split,and-join,or-split,or-join四種transition,比如and-split,它就有多個輸出place:
<node name="split" type="and-split" id="1" resource="user">
<inputs>
<place id="2" />
</inputs>
<outputs>
<place id="3" />
<place id="4" />
</outputs>
</node>
<inputs>
<place id="2" />
</inputs>
<outputs>
<place id="3" />
<place id="4" />
</outputs>
</node>
Place和Transition都有條件,用於決定操作是否執行,Transition額外指定了驅動的資源以及回調的handler,這一點非常重要,資源可能是用戶、用戶組、某個時間點定時事件、特定消息等等。
今天額外發現的一個好處就是,引入Place之後,我可以輕易地將不同的流程連接起來組織成一個更複雜的流程,僅僅是需要修改各個流程的開始和結束的節點的輸入輸出庫所,從而實現了層次化的Petri網,,類似代碼:
WorkFlow sequence = wm.getWorkFlow("sequence");
WorkFlow concurrency = wm.getWorkFlow("concurrency");
WorkFlow choose = wm.getWorkFlow("choose");
//組合流程
composite = new WorkFlow();
composite.setName("composite");
composite.setId(100);
wm.saveWorkFlow(composite);
//修改開始結束節點的輸入輸出庫所
sequence.getEnd().setType(TransitionType.NORMAL);
sequence.getEnd().setOutputs(concurrency.getStart().getInputs());
concurrency.getEnd().setType(TransitionType.NORMAL);
concurrency.getEnd().setOutputs(choose.getStart().getInputs());
composite.setStart(sequence.getStart());
composite.setEnd(choose.getEnd());
List<Transition> transitions = new ArrayList<Transition>();
transitions.addAll(sequence.getTransitions());
transitions.addAll(concurrency.getTransitions());
transitions.addAll(choose.getTransitions());
composite.setTransitions(transitions);
WorkFlow concurrency = wm.getWorkFlow("concurrency");
WorkFlow choose = wm.getWorkFlow("choose");
//組合流程
composite = new WorkFlow();
composite.setName("composite");
composite.setId(100);
wm.saveWorkFlow(composite);
//修改開始結束節點的輸入輸出庫所
sequence.getEnd().setType(TransitionType.NORMAL);
sequence.getEnd().setOutputs(concurrency.getStart().getInputs());
concurrency.getEnd().setType(TransitionType.NORMAL);
concurrency.getEnd().setOutputs(choose.getStart().getInputs());
composite.setStart(sequence.getStart());
composite.setEnd(choose.getEnd());
List<Transition> transitions = new ArrayList<Transition>();
transitions.addAll(sequence.getTransitions());
transitions.addAll(concurrency.getTransitions());
transitions.addAll(choose.getTransitions());
composite.setTransitions(transitions);
文章轉自莊周夢蝶 ,原文發布時間2007-10-11
最後更新:2017-05-17 17:01:45