工作流模式
本文以jdpl/jar/src/test/java jbpm3 关于workflow
patterns 说明 jbpm 对 workflow patterns 的实现示例.
基本控制模式 (Basic Control Flow Patterns)
顺序 (sequence)
Description : An activity in a workow process
is enabled after the completion of another
activity in the same process.
描述: 同一个流程中, 一个活动在其他活动完成以后才能发生.
同义词 :Sequential routing, serial routing.
java 代码
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package org.jbpm.jpdl.patterns;
-
- import junit.framework.TestCase;
-
- import org.jbpm.graph.def.ProcessDefinition;
- import org.jbpm.graph.exe.ProcessInstance;
- import org.jbpm.graph.exe.Token;
-
-
-
-
- public class Wfp01SequenceTest extends TestCase {
-
- public void testSequence() {
-
- ProcessDefinition pd = ProcessDefinition.parseXmlString(
- "
" +
- " +
- " +
- " " +
- " +
- " +
- " " +
- " +
- " +
- " " +
- " +
- " +
- " " +
- " +
- ""
- );
-
- ProcessInstance pi = new ProcessInstance( pd );
- pi.signal();
- Token token = pi.getRootToken();
- assertSame( pd.getNode("a"), token.getNode() );
-
- token.signal();
- assertSame( pd.getNode("b"), token.getNode() );
-
- token.signal();
- assertSame( pd.getNode("c"), token.getNode() );
-
- token.signal();
- assertSame( pd.getNode("end"), token.getNode() );
- }
- }
流程定义文件如下
xml 代码
- <process-definition>
- <start-state name='start'>
- <transition to='a' />
- start-state>
- <state name='a'>
- <transition to='b' />
- state>
- <state name='b'>
- <transition to='c' />
-
state>
- <state name='c'>
- <transition to='end' />
-
state>
- <end-state name='end' />
- process-definition>
节点流程 start
--> a --> b --> c --> end
本例中包括start , a , b ,c ,end 四个node.
token.signal() 可以理解为流程中当前节点(token对应节点) 活动结束. 代码一目了然.
不需要过多解释.
并行分支(Parallet Split)
Description : A point in the workow
process where a single thread of control splits into
multiple threads of control which can be executed in
parallel, thus allowing activities to be executed simultaneously
or in any order.
描述 : 在分支点上,一个工作流程执行线程 分出多个执行线程同时并行执行, 多个分支线程可以同时以任意顺序执行.
同义词:AND-split, parallel routing, fork.
java 代码
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package org.jbpm.jpdl.patterns;
-
- import junit.framework.TestCase;
-
- import org.jbpm.graph.def.ProcessDefinition;
- import org.jbpm.graph.exe.ProcessInstance;
- import org.jbpm.graph.exe.Token;
-
-
-
-
- public class Wfp02ParallelSplitTest extends TestCase {
-
- public void testParallelSplit() {
- ProcessDefinition pd = ProcessDefinition.parseXmlString(
- "
" +
- " +
- " +
- " " +
- " +
- " +
- " +
- " " +
- " +
- " +
- ""
- );
-
- ProcessInstance pi = new ProcessInstance( pd );
- pi.signal();
- Token root = pi.getRootToken();
- assertNotNull( root );
-
- Token firstToken = root.getChild( "first" );
- assertNotNull( firstToken );
- assertSame( pd.getNode("a"), firstToken.getNode() );
-
- Token secondToken = root.getChild( "second" );
- assertNotNull( secondToken );
- assertSame( pd.getNode("b"), secondToken.getNode() );
- }
- }
流程定义文件:
xml 代码
- <process-definition>
- <start-state name='start'>
- <transition to='and' />
-
start-state>
- <fork name='and'>
- <transition name='first' to='a' />
- <transition name='second' to='b' />
-
fork>
- <state name='a' />
- <state name='b' />
- process-definition>"
节点流程 start --> and
--> a
-- > b
本例中and --a , and --> b 一定回被执行.
所以判断如下
Token firstToken = root.getChild( "first"
);
assertNotNull( firstToken );
并行分支 (AND-Split ) 多以 同步聚合((Synchronization)
结束.
同步聚合(Synchronization)
Description : A point in the workow process where
multiple parallel subprocesses/activities converge into
one single thread of control, thus synchronizing multiple
threads. It is an assumption of this pattern that each
incoming branch of a synchronizer is executed only once
描述:一个汇聚点, 多路工作流成执行线程汇聚成单个工作流执行线程. 只有汇聚线程都执行完毕,改汇聚点聚合后的单一线程才会执行.
同义词: AND-join, rendezvous, synchronizer.
java 代码
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package org.jbpm.jpdl.patterns;
-
- import junit.framework.*;
-
- import org.jbpm.graph.def.*;
- import org.jbpm.graph.exe.*;
-
-
-
-
- public class Wfp03SynchronizationTest extends TestCase {
-
- public ProcessDefinition createSynchronizationProcessDefinition() {
- ProcessDefinition pd = ProcessDefinition.parseXmlString(
- "
" +
- " +
- " +
- " " +
- " +
- " +
- " +
- " " +
- " +
- " +
- " " +
- " +
- " +
- " " +
- " +
- " +
- " " +
- " +
- ""
- );
- return pd;
- }
-
- public void testSynchronizationFirstTokenFirst() {
- ProcessDefinition pd = createSynchronizationProcessDefinition();
-
- ProcessInstance pi = new ProcessInstance( pd );
- pi.signal();
- Token root = pi.getRootToken();
- Token firstToken = root.getChild( "first" );
- Token secondToken = root.getChild( "second" );
-
-
- assertSame( pd.getNode("fork"), root.getNode() );
- assertSame( pd.getNode("one"), firstToken.getNode() );
- assertSame( pd.getNode("two"), secondToken.getNode() );
-
- firstToken.signal();
- assertSame( pd.getNode("fork"), root.getNode() );
- assertSame( pd.getNode("join"), firstToken.getNode() );
- assertSame( pd.getNode("two"), secondToken.getNode() );
-
- secondToken.signal();
- assertSame( pd.getNode("end"), root.getNode() );
- assertSame( pd.getNode("join"), firstToken.getNode() );
- assertSame( pd.getNode("join"), secondToken.getNode() );
- }
-
-
-
-
- public void testSynchronizationSecondTokenFirst() {
- ProcessDefinition pd = createSynchronizationProcessDefinition();
-
- ProcessInstance pi = new ProcessInstance( pd );
- pi.signal();
- Token root = pi.getRootToken();
- Token firstToken = root.getChild( "first" );
- Token secondToken = root.getChild( "second" );
-
-
- assertSame( pd.getNode("fork"), root.getNode() );
- assertSame( pd.getNode("one"), firstToken.getNode() );
- assertSame( pd.getNode("two"), secondToken.getNode() );
-
- secondToken.signal();
- assertSame( pd.getNode("fork"), root.getNode() );
- assertSame( pd.getNode("one"), firstToken.getNode() );
- assertSame( pd.getNode("join"), secondToken.getNode() );
-
- firstToken.signal();
- assertSame( pd.getNode("end"), root.getNode() );
- assertSame( pd.getNode("join"), firstToken.getNode() );
- assertSame( pd.getNode("join"), secondToken.getNode() );
- }
-
-
-
-
- public ProcessDefinition createNestedSynchronizationProcessDefinition() {
-
- ProcessDefinition pd = new ProcessDefinition(
- new String[]{"start-state start",
- "fork fork",
- "fork fork1",
- "fork fork2",
- "state state1.1",
- "state state1.2",
- "state state2.1",
- "state state2.2",
- "join join2",
- "join join1",
- "join join",
- "end-state end"},
- new String[]{"start --> fork",
- "fork --first--> fork1",
- "fork --second--> fork2",
- "fork1 --first--> state1.1",
- "fork1 --second--> state1.2",
- "fork2 --first--> state2.1",
- "fork2 --second--> state2.2",
- "state1.1 --> join1",
- "state1.2 --> join1",
- "state2.1 --> join2",
- "state2.2 --> join2",
- "join1 --> join",
- "join2 --> join",
- "join --> end"});
- return pd;
- }
-
- public void testSynchronizationNested() {
- ProcessDefinition pd = createNestedSynchronizationProcessDefinition();
- ProcessInstance pi = new ProcessInstance( pd );
- pi.signal();
- Token rootToken = pi.getRootToken();
- Token token1 = rootToken.getChild( "first" );
- Token token2 = rootToken.getChild( "second" );
- Token token11 = token1.getChild( "first" );
- Token token12 = token1.getChild( "second" );
- Token token21 = token2.getChild( "first" );
- Token token22 = token2.getChild( "second" );
-
- assertSame( pd.getNode("fork"), rootToken.getNode() );
- assertSame( pd.getNode("fork1"), token1.getNode() );
- assertSame( pd.getNode("fork2"), token2.getNode() );
- assertSame( pd.getNode("state1.1"), token11.getNode() );
- assertSame( pd.getNode("state1.2"), token12.getNode() );
- assertSame( pd.getNode("state2.1"), token21.getNode() );
- assertSame( pd.getNode("state2.2"), token22.getNode() );
-
- token11.signal();
-
- assertSame( pd.getNode("fork"), rootToken.getNode() );
- assertSame( pd.getNode("fork1"), token1.getNode() );
- assertSame( pd.getNode("fork2"), token2.getNode() );
- assertSame( pd.getNode("join1"), token11.getNode() );
- assertSame( pd.getNode("state1.2"), token12.getNode() );
- assertSame( pd.getNode("state2.1"), token21.getNode() );
- assertSame( pd.getNode("state2.2"), token22.getNode() );
-
- token12.signal();
-
- assertSame( pd.getNode("fork"), rootToken.getNode() );
- assertSame( pd.getNode("join"), token1.getNode() );
- assertSame( pd.getNode("fork2"), token2.getNode() );
- assertSame( pd.getNode("join1"), token11.getNode() );
- assertSame( pd.getNode("join1"), token12.getNode() );
- assertSame( pd.getNode("state2.1"), token21.getNode() );
- assertSame( pd.getNode("state2.2"), token22.getNode() );
-
- token21.signal();
-
- assertSame( pd.getNode("fork"), rootToken.getNode() );
- assertSame( pd.getNode("join"), token1.getNode() );
- assertSame( pd.getNode("fork2"), token2.getNode() );
- assertSame( pd.getNode("join1"), token11.getNode() );
- assertSame( pd.getNode("join1"), token12.getNode() );
- assertSame( pd.getNode("join2"), token21.getNode() );
- assertSame( pd.getNode("state2.2"), token22.getNode() );
-
- token22.signal();
-
- assertSame( pd.getNode("end"), rootToken.getNode() );
- assertSame( pd.getNode("join"), token1.getNode() );
- assertSame( pd.getNode("join"), token2.getNode() );
- assertSame( pd.getNode("join1"), token11.getNode() );
- assertSame( pd.getNode("join1"), token12.getNode() );
- assertSame( pd.getNode("join2"), token21.getNode() );
- assertSame( pd.getNode("join2"), token22.getNode() );
- }
- }
xml 代码
- <process-definition>
- <start-state name='start'>
- <transition to='fork' />
- start-state>
- <fork name='fork'>
- <transition name='first' to='one' />
- <transition name='second' to='two' />
- fork>
- <state name='one'>
- <transition to='join' />
- state>
- <state name='two'>
- <transition to='join' />
- state>
- <join name='join'>
- <transition to='end' />
- join>
- <end-state name='end' />
- process-definition>
其中testSynchronizationFirstTokenFirst()
节点执行顺序为
start --> fork --> one -->
join(先) --> end
--> two --> join(后)
其中 firstToken.signal() 后 one --> join 先执行.
在 two --> join 执行技术之前 join -->
end 不会执行
testSynchronizationSecondTokenFirst() 与上面方法类似, 只是one
和 two 互换.
testSynchronizationNested()
中createNestedSynchronizationProcessDefinition()
创建如下流程
xml 代码
- <process-definition>
- <start-state name='start'>
- <transition to='fork' />
- start-state>
- <fork name='fork'>
- <transition name='first' to='fork1' />
- <transition name='second' to='fork2' />
- fork>
- <fork name='fork1'>
- <transition name='first' to='state1.1' />
- <transition name='second' to='state1.2' />
- fork>
- <fork name='fork2'>
- <transition name='first' to='state2.1' />
- <transition name='second' to='state2.2' />
- fork>
- <state name='state1.1'>
- <transition to='join1' />
- state>
- <state name='state1.2'>
- <transition to='join1' />
- state>
- <state name='state2.1'>
- <transition to='join2' />
- state>
- <state name='state2.2'>
- <transition to='join2' />
- state>
- <join name='join'>
- <transition to='end' />
- join>
- <join name='join1'>
- <transition to='join' />
- join>
- <join name='join2'>
- <transition to='join' />
- join>
- <end-state name='end' />
- process-definition>
节点执行顺序:
start --> fork --> fork1 -->
state1.1 --> join1 --> join --> end
--> state1.2 --> join1
--> fork2 --> state2.1 --> join2 --> join
--> state2.2 --> join2
token11.signal() token11
到 join1
token12.signal() token12
到 join1 , token1到join
token21.signal() token21
到 join2
token22.signal() token22
到 join2 , token2到join
排它选择(Exclusive Choice)
Description:A point in the workow process where a single
thread of control splits into
multiple threads of control which can be executed in
parallel, thus allowing activities to be
executed simultaneously or in any order.
描述:在流程的某一点,依据工作流控制数据, 从多个分支路径中选定一个路径
同义词:XOR-split, conditional routing, switch, decision.
java 代码
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package org.jbpm.jpdl.patterns;
-
- import junit.framework.TestCase;
-
- import org.jbpm.context.def.ContextDefinition;
- import org.jbpm.context.exe.ContextInstance;
- import org.jbpm.graph.def.ProcessDefinition;
- import org.jbpm.graph.exe.ProcessInstance;
- import org.jbpm.graph.exe.Token;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class Wfp04ExclusiveChoiceTest extends TestCase {
-
- static ProcessDefinition exclusiveChoiceProcessDefinition = ProcessDefinition.parseXmlString(
- "
" +
- " +
- " +
- " " +
- " +
- " +
- " " +
- " +
- " +
- " +
- " #{scenario==1}" +
- " " +
- " +
- " #{scenario==2}" +
- " " +
- " " +
- " +
- " +
- " +
- "" );
- static {
- exclusiveChoiceProcessDefinition.addDefinition( new ContextDefinition() );
- }
-
-
-
-
- public void testExclusiveChoiceSituation1() {
- ProcessDefinition pd = exclusiveChoiceProcessDefinition;
-
- ProcessInstance pi = new ProcessInstance( pd );
- ContextInstance ci = (ContextInstance) pi.getInstance( ContextInstance.class );
- pi.signal();
- Token root = pi.getRootToken();
-
- assertSame( pd.getNode("a"), root.getNode() );
-
- ci.setVariable( "scenario", new Integer(1) );
- root.signal();
-
- assertSame( pd.getNode("b"), root.getNode() );
- }
-
-
-
-
- public void testExclusiveChoiceSituation2() {
- ProcessDefinition pd = exclusiveChoiceProcessDefinition;
-
- ProcessInstance pi = new ProcessInstance( pd );
- ContextInstance ci = (ContextInstance) pi.getInstance( ContextInstance.class );
- pi.signal();
- Token root = pi.getRootToken();
-
- assertSame( pd.getNode("a"), root.getNode() );
-
- ci.setVariable( "scenario", new Integer(2) );
- root.signal();
-
- assertSame( pd.getNode("c"), root.getNode() );
- }
-
- }
流程定义文件:
xml 代码
- <process-definition>
- <start-state name='start'>
- <transition to='a' />
- start-state>
- <state name='a'>
- <transition to='xor' />
- state>
- <decision name='xor'>
- <transition name='forget about it' to='d' />
- <transition name='urgent' to='b'>
- <condition>#{scenario==1}condition>
- transition>
- <transition name='dont care' to='c'>
- <condition>#{scenario==2}condition>
- transition>
- decision>
- <state name='b' />
- <state name='c' />
- <state name='d' />
- process-definition>
节点执行顺序:
start --> a --> xor --> d
xor --> b
xor --> c
其中 xor --> d , xor --> b , xor--> c
只能从中选一.
当scenario==1 执行 xor --> b, 当 scenario==2
执行xor --> c , 其他情况(默认)执行xor --> d
代码中根据变量scenario , 判断流程转向, 比较直观,不再详述.
简单聚合(Simple Merge)
Description : A point in the workow process where
two or more alternative branches come together
without synchronization. It is an assumption of this
pattern that none of the alternative
branches is ever executed in parallel
描述: 在流程中某一点,将两个或更多可选分支聚合而不同步.
同义词: XOR-join, asynchronous join, merge.
好像源代码功能有点问题.
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors
as indicated
* by the @authors tag. See the copyright.txt in
the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute
it and/or modify it
* under the terms of the GNU Lesser General Public
License as
* published by the Free Software Foundation; either
version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that
it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied
warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser
General Public
* License along with this software; if not, write
to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth
Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jbpm.jpdl.patterns;
import junit.framework.*;
import org.jbpm.graph.def.*;
import org.jbpm.graph.exe.*;
/**
* http://is.tm.tue.nl/research/patterns/download/swf/pat_5.swf
*
* <p>in jbpm every node has an implicit
merge in front of it.
* so it's not necessary to use the merge node.
in fact, i can
* not think of a situation where implicit merge
nodeMap are not
* sufficient. for the sake of workflow patterns,
we leave if in.
* jbpm supports merging of both alternative paths
of execution
* and concurrent paths of execution.
* </p>
*
* <p>first the merge node is demonstrated
exactly as in the pattern.
* then the implicit variant is demonstrated, then
the merging of
* concurrent paths is demonstrated.
* </p>
*/
public class Wfp05SimpleMergeTest extends TestCase {
private static ProcessDefinition simpleMergeProcessDefinition
= createSimpleMergeProcessDefinition();
public static ProcessDefinition createSimpleMergeProcessDefinition()
{
ProcessDefinition pd = new ProcessDefinition(
new String[]{"start-state
start",
"state a",
"state b",
"merge xor",
"state c"},
new String[]{"start
--to a--> a",
"start --to b--> b",
"a --> xor",
"b --> xor",
"xor --> c"});
return pd;
}
public void testSimpleMergeScenario1() {
ProcessDefinition pd = simpleMergeProcessDefinition;
ProcessInstance pi = new ProcessInstance(
pd );
pi.signal("to a");
Token root = pi.getRootToken();
assertSame( pd.getNode("a"),
root.getNode() );
root.signal();
assertSame( pd.getNode("c"),
root.getNode() );
}
public void testSimpleMergeScenario2() {
ProcessDefinition pd = simpleMergeProcessDefinition;
ProcessInstance pi = new ProcessInstance(
pd );
pi.signal("to b");
Token root = pi.getRootToken();
assertSame( pd.getNode("b"),
root.getNode() );
root.signal();
assertSame( pd.getNode("c"),
root.getNode() );
}
private static ProcessDefinition implicitMergeProcessDefinition
= createImplicitMergeProcessDefinition();
public static ProcessDefinition createImplicitMergeProcessDefinition()
{
ProcessDefinition pd = new ProcessDefinition(
new String[]{"start-state
start",
"state a",
"state b",
"state c"},
new String[]{"start
--to a--> a",
"start --to b--> b",
"a --> c",
"b --> c"});
return pd;
}
public void testImplicitMergeScenario1() {
ProcessDefinition pd = implicitMergeProcessDefinition;
ProcessInstance pi = new ProcessInstance(
implicitMergeProcessDefinition );
pi.signal("to a");
Token root = pi.getRootToken();
assertSame( pd.getNode("a"),
root.getNode() );
root.signal();
assertSame( pd.getNode("c"),
root.getNode() );
}
public void testImplicitMergeScenario2() {
ProcessDefinition pd = implicitMergeProcessDefinition;
ProcessInstance pi = new ProcessInstance(
implicitMergeProcessDefinition );
pi.signal("to b");
Token root = pi.getRootToken();
assertSame( pd.getNode("b"),
root.getNode() );
root.signal();
assertSame( pd.getNode("c"),
root.getNode() );
}
}
createSimpleMergeProcessDefinition()
创建如下流程定义文件
xml 代码
- <process-definition name="process">
- <start-state name='start'>
- <transition name='to a' to='a' />
- <transition name='to b' to='b' />
- </start-state>
- <state name='a'>
- <transition to='xor' />
- </state>
- <state name='b'>
- <transition to='xor' />
- </state>
- <state name='xor'>
- <transition to='c' />
- </state>
- <state name='c' />
- </process-definition>
testSimpleMergeScenario1()
节点执行顺序
start --> a --> xor --> c
testSimpleMergeScenario2()
start --> b --> xor --> c
createImplicitMergeProcessDefinition()
创建如下流程定义文件
xml 代码
- <process-definition name="process">
- <start-state name='start'>
- <transition name='to a' to='a' />
- <transition name='to b' to='b' />
- </start-state>
- <state name='a'>
- <transition to='c' />
- </state>
- <state name='b'>
- <transition to='c' />
- </state>
- <state name='c' />
- </process-definition>
testImplicitMergeScenario1()
节点执行顺序 start --> a --> c
testImplicitMergeScenario2()
节点执行顺序
start --> b --> c
|