osworkflow dynamic split 动态会签的实现
目前 osworkflow的版本是2.8,很久没有更新了,而且这个版本的动态会签无法实现,虽然她提供了 split和join这样的标签,但是split中result的个数是固定的,这往往在我们现实的系统中用的很少,比如 我要给你一个组提供会签功能,而这个组的人数事先是不知道的,所以必须提供动态会签,也就是动态的split。
附件里面是我通过改写osworkflow使其能够动态会签的例子
?
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.8//EN" "workflow_2_8.dtd" ><workflow> <initial-actions> <action id="1" name="Start Workflow"> <results> <unconditional-result old-status="Finished" status="Queued" step="1"/> </results> </action> </initial-actions> <steps> <step id="1" name="First Part"> <actions> <action id="2" name="Finish First Part"> <results> <unconditional-result old-status="Finished" status="Queued" split="1" owner="test1,test2,test3"/> </results> </action> </actions> </step> <step id="2" name="Second Part"> <actions> <action id="3" name="Back to First Part"> <results> <unconditional-result old-status="Rejected" status="Queued" join="2"/> </results> </action> <action id="4" name="Finish"> <results> <unconditional-result old-status="Finished" status="Queued" join="1"/> </results> </action> </actions> </step> <step id="4" name="End" /> </steps> <splits> <split id="1" dynamic="TRUE" obtain-groups-callback="com.siemens.dingchao.test.DynamicSplitGroup"> <unconditional-result old-status="Finished" status="Queued" step="2"/> </split> </splits> <joins> <join id="1"> <conditions type="AND"> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test1").getStatus())</arg> </condition> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test2").getStatus())</arg> </condition> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test3").getStatus())</arg> </condition> </conditions> <unconditional-result old-status="Finished" status="Underway" step="4"/> </join> <join id="2"> <conditions type="OR"> <condition type="beanshell"> <arg name="script">"Rejected".equals(jn.getStep(2,"test1").getStatus())</arg> </condition> <condition type="beanshell"> <arg name="script">"Rejected".equals(jn.getStep(2,"test2").getStatus())</arg> </condition> <condition type="beanshell"> <arg name="script">"Rejected".equals(jn.getStep(2,"test3").getStatus())</arg> </condition> </conditions> <unconditional-result old-status="Finished" status="Underway" step="1"/> </join> </joins></workflow>
?
上面的红颜色部分是我为split标签添加的 属性,dynamic 属性 : 可以为 TRUE,true,FALSE,false,指定是否是动态的,如果是动态的 则必须指定obtain-group-callback 属性,该callback必须实现com.opensymphony.workflow.util.DynamicSplitGroupCallback接口(该接口为新添加)
?
?
?
test case :
?
/* * Copyright (c) 2002-2003 by OpenSymphony * All rights reserved. */package com.siemens.dingchao.test;import junit.framework.TestCase;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.opensymphony.workflow.Workflow;import com.opensymphony.workflow.basic.BasicWorkflow;/** * @author hani Date: Feb 17, 2005 Time: 4:24:20 PM */public class JoinTestCase extends TestCase { //~ Instance fields //////////////////////////////////////////////////////// private Workflow workflow; //~ Methods //////////////////////////////////////////////////////////////// public void testWithReject() throws Exception { //说明: checkRoute(new int[] {2, 3, 2, 4 ,4 ,4}); //checkRoute(new int[] {4,4}); } protected void setUp() throws Exception { /* workflow = new BasicWorkflow("testuser");*/ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); workflow = (Workflow)context.getBean("workflow"); } private void checkRoute(int[] actions) throws Exception { long workflowId = workflow.initialize("join", 1, null); for (int i = 0; i < actions.length; i++) { workflow.doAction(workflowId, actions[i], null); } }}?
?
test case 的红颜色部分标明了 步骤的 route 均是 xml里面的action id ,你可以把这个数字和xml对照起来看。
?
?
调试结果???? 以下图例都是 表 os_currentstep:
?
流程实例初始化
?
运行action? 2 此时动态split为3个任务,因为 owner为 test1,test2,test3
?运行action : 3? reject(驳回) 回到step1
运行action 2 ,相当于再次提交任务,此时任务再次分裂成为3个任务,owner分别为test1 ,test2,test3
test1 执行action 4 : test1 用户提交任务
test2执行action 4 : test2 用户提交任务
test3 执行action 4 : test3 用户提交任务
此时3个用户都提交了任务,任务移动到下一步 , 即 结束节点,至此 这个工作流实例完成
?
在看看 os_historystep 表的数据 :
?
我们可以发现历史信息业完整的记录了这个操作轨迹。
?
希望能给你们带来帮助
<join id="1"> <conditions type="AND"> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test1").getStatus())</arg> </condition> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test2").getStatus())</arg> </condition> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test3").getStatus())</arg> </condition> </conditions> <unconditional-result old-status="Finished" status="Underway" step="4"/> </join>难道这个join只能join 固定的三个步骤吗!!!
如果会签数不确定能否可以,对付。。。。。。。 <join id="1"> <conditions type="AND"> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test1").getStatus())</arg> </condition> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test2").getStatus())</arg> </condition> <condition type="beanshell"> <arg name="script">"Finished".equals(jn.getStep(2,"test3").getStatus())</arg> </condition> </conditions> <unconditional-result old-status="Finished" status="Underway" step="4"/> </join>
难道这个join只能join 固定的三个步骤吗!!!
如果会签数不确定能否可以,对付。。。。。。。
当然可以对付,我是用beanshell写的,你可以写自己的condition啊?
import java.util.Map;import com.opensymphony.module.propertyset.PropertySet;import com.opensymphony.workflow.Condition;import com.opensymphony.workflow.JoinNodes;import com.opensymphony.workflow.WorkflowException;public enum JoinCondition implements Condition {;@Overridepublic boolean passesCondition(Map transientVars, Map args, PropertySet ps)throws WorkflowException {// TODO Auto-generated method stubJoinNodes jn = (JoinNodes)transientVars.get("jn");//bla bla 你自己的判断逻辑return false;}}public class ApproveJoinCondition implements Condition {public boolean passesCondition(Map transientVars, Map args, PropertySet ps)throws WorkflowException {// TODO Auto-generated method stubJoinNodes jn = (JoinNodes)transientVars.get("jn");Collection steps = (Collection)jn.getSteps();Iterator it = steps.iterator();Step step = null;boolean result = true;while(it.hasNext()){step = (Step)it.next();result = result&&"Finished".equals(step.getStatus());}return result;}}
处理 Approval的condition;
public class RejectJoinCondition implements Condition {public boolean passesCondition(Map transientVars, Map args, PropertySet ps)throws WorkflowException {// TODO Auto-generated method stubJoinNodes jn = (JoinNodes)transientVars.get("jn");Collection steps = (Collection)jn.getSteps();Iterator it = steps.iterator();Step step = null;boolean result = false;while(it.hasNext()){step = (Step)it.next();result = result || "Rejected".equals(step.getStatus());}return result;}}
处理 Reject的 condition
另外需要修改xml
<joins> <join id="1"> <conditions type="AND"> <condition type="class"> <arg name="class.name">com.siemens.dingchao.test.ApproveJoinCondition</arg> </condition> </conditions> <unconditional-result old-status="Finished" status="Underway" step="4"/> </join> <join id="2"> <conditions type="AND"> <condition type="class"> <arg name="class.name">com.siemens.dingchao.test.RejectJoinCondition</arg> </condition> </conditions> <unconditional-result old-status="Finished" status="Underway" step="1"/> </join> </joins>
另外 源代码还需要修改一个地方 就是JoinNodes 需要加一个 getSteps 方法 你可以反编译了再加,完后替换这个class即可
以上2个condition对全部通过,和一票否决的情况可以通用,但如果 比如说 2/3的人通过 ,否决这样的情况需要自己写自己的判断逻辑了