论坛首页 Java企业应用论坛

使用JBPM实现动态会签

浏览 8413 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-09-19   最后修改:2008-11-27

目前有很多实现动态会签的文章,但是给人感觉不是很优雅,下面介绍一种实现方式。
1、流程定义文件:

xml 代码
 
  1. < process-definition   
  2. xmlns = "urn:jbpm.org:jpdl-3.1"   name = "foreach" >   
  3. < start-state   name = "start" >   
  4. < task   name = "one" >   
  5. </ task >   
  6. < transition   name = "a"   to = "foreachf" > </ transition >   
  7. </ start-state >   
  8. < node   name = "foreachf" >   
  9. < action   class = "com.framework.workflow.jbpm.ForEachFork" >   
  10. < foreach > #{bpm_assignees} </ foreach >   
  11. < var > reviewer </ var >   
  12. </ action >   
  13. < transition   name = "review"   to = "review" > </ transition >   
  14. </ node >   
  15. < task-node   name = "review" >   
  16. < task   name = "reviewTask" >   
  17. < assignment   class = "com.framework.workflow.jbpm.DefaultAssignment" >   
  18. < actor > #{reviewer} </ actor >   
  19. </ assignment >   
  20. </ task >   
  21. < transition   name = "reject"   to = "endreview" >   
  22. < action   class = "com.framework.workflow.jbpm.JoinEndForkedTokens"   />   
  23. </ transition >   
  24. < transition   name = "approve"   to = "endreview" > </ transition >   
  25. </ task-node >   
  26. < join   name = "endreview" >   
  27. < transition   name = "toend"   to = "end1" > </ transition >   
  28. </ join >   
  29. < end-state   name = "end1" > </ end-state >   
  30. </ process-definition >    


在这里我们从node节点动态生成任务节点,会签时当有一个是reject时便结束所有节点。
2、动态派生ForEachFork代码:

java 代码
 
  1. public   class  ForEachFork  implements  ActionHandler  
  2. {  
  3. private  Element foreach;  
  4. private  String var;  
  5. //测试数据   
  6. private   static  Map map =  new  HashMap();  
  7. static {  
  8. List list = new  ArrayList();  
  9. list.add("1234" );  
  10. list.add("2345" );  
  11. list.add("3456" );  
  12. map.put("bpm_assignees" , list);  
  13. }  
  14.   
  15. /**  
  16. *  
  17.  
  18. 为每个元素创建一个分支  
  19.  
  20. *  
  21. * @param executionContext  
  22. * @throws Exception  
  23. */   
  24. @SuppressWarnings ( "unchecked" )  
  25. public   void  execute( final  ExecutionContext executionContext)  
  26. throws  Exception  
  27. {  
  28.   
  29.   
  30. if  (foreach ==  null )  
  31. {  
  32. throw   new  WorkflowException( "forEach has not been provided" );  
  33. }  
  34.   
  35. List forEachColl = null ;  
  36. String forEachCollStr = foreach.getTextTrim();  
  37.   
  38. if  (forEachCollStr !=  null )  
  39. {  
  40. if  (forEachCollStr.startsWith( "#{" ))  
  41. {  
  42. String expression = forEachCollStr.substring(2 , forEachCollStr.length() - 1 );  
  43. forEachColl = (List)map.get(expression);  
  44.   
  45. }  
  46.   
  47. }  
  48.   
  49. if  (var ==  null  || var.length() ==  0 )  
  50. {  
  51. throw   new  WorkflowException( "forEach variable name has not been provided" );  
  52. }  
  53.   
  54. //   
  55. // 创建分支   
  56. //   
  57.   
  58. Token rootToken = executionContext.getToken();  
  59. Node node = executionContext.getNode();  
  60. List forkTransitions = new  ArrayList();  
  61. // 为每一个元素创建一个token   
  62. for  ( int  i =  0 ; i < node.getLeavingTransitions().size(); i++)  
  63. {  
  64. Transition transition = (Transition) node.getLeavingTransitions().get(i);  
  65. for  ( int  iVar =  0 ; iVar < forEachColl.size(); iVar++)  
  66. {  
  67. // 为每一个新token创建一个path   
  68. String tokenName = getTokenName(rootToken, transition.getName(), iVar);  
  69. Token loopToken = new  Token(rootToken, tokenName);  
  70. loopToken.setTerminationImplicit(true );  
  71. executionContext.getJbpmContext().getSession().save(loopToken);  
  72.   
  73. //赋予一个新变量   
  74. final  ExecutionContext newExecutionContext =  new  ExecutionContext(loopToken);  
  75. newExecutionContext.getContextInstance().createVariable(var, forEachColl.get(iVar), loopToken);  
  76.   
  77. // 记录下每一transition   
  78. ForkedTransition forkTransition = new  ForkedTransition();  
  79. forkTransition.executionContext = newExecutionContext;  
  80. forkTransition.transition = transition;  
  81. forkTransitions.add(forkTransition);  
  82. }  
  83. }  
  84. //   
  85. // 转向下一个节点   
  86. //   
  87. for  (ForkedTransition forkTransition : forkTransitions)  
  88. {  
  89. node.leave(forkTransition.executionContext, forkTransition.transition);  
  90. }  
  91. }  
  92. /**  
  93. *  
  94.  
  95. 获得分支token name  
  96.  
  97. *  
  98. * @param parent  
  99. * @param transitionName  
  100. * @return  
  101. */   
  102. protected  String getTokenName(Token parent, String transitionName,  int  loopIndex)  
  103. {  
  104. String tokenName = null ;  
  105. if  (transitionName !=  null )  
  106. {  
  107. if  (!parent.hasChild(transitionName))  
  108. {  
  109. tokenName = transitionName;  
  110. }  
  111. else   
  112. {  
  113. int  i =  2 ;  
  114. tokenName = transitionName + Integer.toString(i);  
  115. while  (parent.hasChild(tokenName))  
  116. {  
  117. i++;  
  118. tokenName = transitionName + Integer.toString(i);  
  119. }  
  120. }  
  121. }  
  122. else   
  123. {  
  124. // 没有转向   
  125. int  size = ( parent.getChildren()!= null  ? parent.getChildren().size()+ 1  :  1  );  
  126. tokenName = Integer.toString(size);  
  127. }  
  128. return  tokenName +  "."  + loopIndex;  
  129. }  
  130.   
  131.   
  132.   
  133. /**  
  134. * Fork Transition  
  135. */   
  136. private   class  ForkedTransition  
  137. {  
  138. private  ExecutionContext executionContext;  
  139. private  Transition transition;  
  140. }  
  141. }   

 

 


在具体应用中需要灵活的根据业务逻辑需要派生所需要的分支。

 

3、DefaultAssignment
进行简单的权限操作,这里面主要是将#{reviewer}值作为actorId进行设置
4、JoinEndForkedTokens结束所有节点

java 代码
 
  1. public   class  JoinEndForkedTokens  implements  ActionHandler  
  2. {  
  3.   
  4. public  JoinEndForkedTokens()  
  5. {  
  6. }  
  7. /* (non-Javadoc)  
  8. * @see org.jbpm.graph.def.ActionHandler#execute(org.jbpm.graph.exe.ExecutionContext)  
  9. */   
  10. public   void  execute(ExecutionContext executionContext)  
  11. {  
  12. Token token = executionContext.getToken().getParent();  
  13. Map childTokens = token.getActiveChildren();  
  14. for  (Object childToken : childTokens.values())  
  15. {  
  16. cancelToken(executionContext, (Token)childToken);  
  17. }  
  18.   
  19. }  
  20. /**  
  21. *  
  22.  
  23. 取消 token  
  24.  
  25. *  
  26. * @param executionContext  
  27. * @param token  
  28. */   
  29. protected   void  cancelToken(ExecutionContext executionContext, Token token)  
  30. {  
  31.   
  32. Map childTokens = token.getActiveChildren();  
  33. for  (Object childToken : childTokens.values())  
  34. {  
  35. cancelToken(executionContext, (Token)childToken);  
  36. }  
  37.   
  38. if  (!token.hasEnded())  
  39. {  
  40. token.end(true );  
  41. }  
  42.   
  43.   
  44. cancelTokenTasks(executionContext, token);  
  45. }  
  46. /**  
  47. *  
  48.  
  49. 结束token关联的任务  
  50.  
  51. *  
  52. * @param executionContext  
  53. * @param token  
  54. */   
  55. protected   void  cancelTokenTasks(ExecutionContext executionContext, Token token)  
  56. {  
  57. TaskMgmtInstance tms = executionContext.getTaskMgmtInstance();  
  58. Collection tasks = tms.getUnfinishedTasks(token);  
  59. for  (Object task : tasks)  
  60. {  
  61. TaskInstance taskInstance = (TaskInstance)task;  
  62. if  (taskInstance.isBlocking())  
  63. {  
  64. taskInstance.setBlocking(false );  
  65. }  
  66. if  (taskInstance.isSignalling())  
  67. {  
  68. taskInstance.setSignalling(false );  
  69. }  
  70. if  (!taskInstance.hasEnded())  
  71. {  
  72. taskInstance.end();  
  73. }  
  74. }  
  75. }  
  76. }   

 

 


结束所有分支节点任务,流向结束节点。

 

   发表时间:2007-12-03  
如果将流程定义文件修改,变成两次调用生成<node name="foreachf">就会有错误,而不是直接结束。
错误出现在 executionContext.getJbpmContext().getSession().save(loopToken);  
。通过跟踪发现,是executionContext.getJbpmContext()为空。即报Caused by: java.lang.NullPointerException的错误。
这个问题困扰我几天了。一致没有解决。
不知那位有过此情况下的情况,望告知。谢谢!
0 请登录后投票
   发表时间:2007-12-04  
问题已经解决。是测试程序测试方法不对造成的。
0 请登录后投票
   发表时间:2008-07-18  
太感谢楼主的分享精神了,搞了好久的会签 被楼主点通了,谢谢
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics