jbpm的流程定义从发布上看有2种方式,一种是发布持久化到关系型数据库中,另一种则是由java代码实时生成。
之前一直关注持久化的方式,每次都是生成好固定的xml文件,然后发布到数据中,然后再从数据库中检索出来使用。
不过通过2天的学习,第二种代码生成的方式有着第一种持久化方式所不能替代的优点。下面通过一个简单但是非常实用的例子来说明。
网上有很多人在问,fork分出去的多条路线,为什么一定要全部到达join后才能延续流程,能不能其中部分路线到达后流程就继续呢。很多人通过了很复杂的方法实现了这个功能。下面我就介绍一个简单的办法,在fork下增加script元素:
- package com.jeffentest;
- import org.jbpm.*;
- import org.jbpm.graph.def.ProcessDefinition;
- import org.jbpm.graph.exe.*;
- import org.jbpm.context.exe.ContextInstance;
-
-
- public class Jeffentest {
- static JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
- static ProcessDefinition processDefinition = null;
- static ProcessInstance processInstance = null;
- //static SchedulerSession schedulerSession =null;
- private static void run(){
- //JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
- try {
- processDefinition= ProcessDefinition.parseXmlString(
- "<process-definition>" +
- " <start-state name='start'>" +
- " <transition to='a' />" +
- " start-state>" +
- " <state name='a'>" +
- " <transition to='multichoice' />" +
- " state>" +
- " <fork name='multichoice'>" +
- " <script>" +
- " <variable name='transitionNames' access='write' />" +
- " <expression>" +
- " transitionNames = new ArrayList();" +
- " if ( scenario == 1 ) {" +
- " transitionNames.add( \"to b\" );" +
- " } else if ( scenario == 2 ) {" +
- " transitionNames.add( \"to c\" );" +
- " } else if ( scenario >= 3 ) {" +
- " transitionNames.add( \"to b\" );" +
- " transitionNames.add( \"to c\" );" +
- " }" +
- " expression>" +
- " script>" +
- " <transition name='to b' to='b' />" +
- " <transition name='to c' to='c' />" +
- " fork>" +
- " <state name='b'>" +
- " <transition to='syncmerge' />" +
- " state>" +
- " <state name='c'>" +
- " <transition to='syncmerge' />" +
- " state>" +
- " <join name='syncmerge'>" +
- " <transition to='end' />" +
- " join>" +
- " <end-state name='end'>end-state>" +
- "process-definition>"
- );
- processInstance= new ProcessInstance(processDefinition);
- ContextInstance ci = (ContextInstance) processInstance.getInstance( ContextInstance.class );
- Token root = processInstance.getRootToken();
- System.out.println(root.getNode());//StartState(start)
- root.signal();
- System.out.println(root.getNode());//State(a)
- ci.setVariable( "scenario", new Integer(2) );
- root.signal();
- Token tokenB = root.getChild("to b");
- Token tokenC = root.getChild("to c");
- System.out.println(root.getNode());//Fork(multichoice)
- System.out.println("tokenC:"+tokenC.getNode());//tokenC:State(c)
- tokenC.signal();
- System.out.println("tokenC:"+tokenC.getNode());//tokenC:Join(syncmerge)
- System.out.println(root.getNode());//EndState(end)
-
- }catch(Exception e){
- e.printStackTrace();
- }finally {
- //jbpmContext.close();
- }
- }
- public static void main(String[] args) {
- run();
- }
- }
运行结果如下:
StartState(start)
State(a)
Fork(multichoice)
tokenC:State(c)
tokenC:Join(syncmerge)
EndState(end)
大家看到了,fork出去2条路线b/c,c完成了而b没有完成,但是整个流程已经结束了。
这里有一点需要注意,这种方式仅仅适合代码生成流程定义,如果你想通过持久化流程定义到数据库的方式,那么结果就仍然要等待路线b的完成了。为什么呢?因为这是jbpm3.1.2的限制:the script in a fork is not persisted. script in fork might be removed in later versions of jPDL.
有兴趣的朋友可以验证一下。
还有一个节点类型Merge也是同样的情况,它有一个Synchronized属性。对于这个节点jbpm的开发者有这么一段话,大家见仁见智吧。
/**
* TODO is the merge node usefull ?
* i don't think the merge node is usefull because every node has an
* implicit merge in front of it (= multiple transitions can arrive in
* the same node). maybe we should just leave this in for the sake
* of workflow patterns ?
*/
附:merge的使用语句
Merge merge = (Merge) processDefinition.getNode("xor");
merge.setSynchronized( false );