AnsweredAssumed Answered

problem with jump to a multi-instance user task

Question asked by windfighter on Apr 20, 2016
Latest reply on May 18, 2016 by windfighter
my workflow model is: start->user task1->user task2(multi-instance)->user task3-> end

all the assignee I set is using flow variables.
at runtime of the flow ,the assignee are as below.

user task1 : assignee is `zhangsan`
user task2: assignee are `lisi` and `wanger`
user task3: assignee is `mazi`

I write a test function,
and hope the flow can jump from `user task3` to `user task2`,and I set the assignees of `user task2` in the `jumpAcitivtyCmd` before jumping.

but the result is : jumping work correctly, but when the second task user `wanger` complete the task of `user task2`, pop up execption.

it tasks me long time on it, and I don't kown how to resolve it. and very exhausted.

Hope you can help me!!!
thanks.

the flow mode is :

<code>
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="simpleFlow" name="任务发起" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="User Task1" activiti:assignee="${user}"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="User Task2" activiti:assignee="${user}">
      <multiInstanceLoopCharacteristics isSequential="true" activiti:collection="${users}" activiti:elementVariable="user"></multiInstanceLoopCharacteristics>
    </userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <userTask id="usertask3" name="User Task3" activiti:assignee="${user}"></userTask>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_simpleFlow">
    <bpmndi:BPMNPlane bpmnElement="simpleFlow" id="BPMNPlane_simpleFlow">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="140.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="220.0" y="140.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="370.0" y="140.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="520.0" y="140.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="680.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="175.0" y="167.0"></omgdi:waypoint>
        <omgdi:waypoint x="220.0" y="167.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="325.0" y="167.0"></omgdi:waypoint>
        <omgdi:waypoint x="370.0" y="167.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="475.0" y="167.0"></omgdi:waypoint>
        <omgdi:waypoint x="520.0" y="167.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="625.0" y="167.0"></omgdi:waypoint>
        <omgdi:waypoint x="680.0" y="167.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
<code>

and my test code is :
<code>
@Test
   public void testJump() {
       //flow template model is: start->usertask1->usertask2->usertask3->end
       //user task2 is multi-instance user task, and multi-instance collection is ${users}, and element is user;
       String processDefId = "simpleFlow:2:1587504";


       Map<String, Object> variables = new HashMap<>();

       //set user task1 assignee
       variables.put("user", "zhangsan");

       ProcessInstance pi = runtimeService.startProcessInstanceById(processDefId, variables);
       printExecutions(pi.getProcessInstanceId(), "after start flow");
       logger.info("流程实例Id:{}", pi.getProcessInstanceId());


       //set user task2 assignee
       List<String> u2Assignees =  Arrays.asList(new String[]{"lisi", "wanger"});
       runtimeService.setVariable(pi.getProcessInstanceId(), "users",u2Assignees);
       //complete user task 1
       completeTask(pi.getProcessInstanceId(), null);
       printExecutions(pi.getProcessInstanceId(), "after complete user task1");

       //set user task3 assignee
       runtimeService.setVariable(pi.getProcessInstanceId(), "user", "mazi");
       //complete user task2
       completeTask(pi.getProcessInstanceId(), null);
       printExecutions(pi.getProcessInstanceId(), "after complete user task2-instance1");

       //complete user task2
       completeTask(pi.getProcessInstanceId(), null);
       printExecutions(pi.getProcessInstanceId(), "after complete user task2-instance2");

       //complete user task3
       //completeTask(pi.getProcessInstanceId(), null);
       //printExecutions(pi.getProcessInstanceId(), "after complete user task3");

       //jump to user task2
       JumpActivityCmd cmd = new JumpActivityCmd(pi.getProcessInstanceId(),"usertask2","disapprove",u2Assignees,u2Assignees.get(0));
      
       managementService.executeCommand(cmd);
/*

       TaskFlowControlService taskFlowControlService = new TaskFlowControlService(processEngine,pi.getProcessInstanceId());
       try {
           taskFlowControlService.jump("usertask2");
       }catch (Exception e){
           logger.error("",e);
       }
*/

       printExecutions(pi.getProcessInstanceId(), "after jump to user task2");

       completeTask(pi.getProcessInstanceId(), null);
       printExecutions(pi.getProcessInstanceId(), "after complete user task2-instance1");


       completeTask(pi.getProcessInstanceId(), null);
       printExecutions(pi.getProcessInstanceId(), "after complete user task2-instance2");
      
   }

private void printExecutions(String processInstanceId,String messageTitle){
        List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list();
        if(executions != null && executions.size() > 0){
            for(Execution e : executions){
                logger.info(messageTitle + ":current executionId is {},activityId is {}, parent executionId is {}",e.getId(),e.getActivityId(),e.getParentId());
            }
        }
    }

    private  void completeTask(String processInstanceId,Map variables) {
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();

        if (tasks != null && tasks.size() > 0) {

            for (Task e : tasks) {
                logger.info("****************************complete task:{},task assignee {} ,execution id {}****************************", e.getId(),e.getAssignee(), e.getExecutionId());
                taskService.complete(e.getId());
            }


        }

    }

<code>

and the jumpActivityCmd class is :
<code>
public class JumpActivityCmd implements Command<Object> {
    Logger logger = org.slf4j.LoggerFactory.getLogger(JumpActivityCmd.class);

    private String activityId;
    private String processInstanceId;
    private String jumpOrigin;

    //task assignees,if the target activity is multi-instance
    private List<String> taskUsers;

    //task assignee, if not multi-instance
    private String taskUser;


    public JumpActivityCmd(String processInstanceId, String activityId,String jumpOrigin,
                           List<String> taskUsers,String taskUser) {
        this(processInstanceId, activityId, jumpOrigin);
        this.taskUsers = taskUsers;
        this.taskUser = taskUser;
    }

    public JumpActivityCmd(String processInstanceId, String activityId) {
        this(processInstanceId, activityId, "jump");
    }

    public JumpActivityCmd(String processInstanceId, String activityId, String jumpOrigin) {
        this.activityId = activityId;
        this.processInstanceId = processInstanceId;
        this.jumpOrigin = jumpOrigin;
    }

    public Object execute(CommandContext commandContext) {


        ExecutionEntity executionEntity = commandContext.getExecutionEntityManager().findExecutionById(processInstanceId);
        executionEntity.destroyScope(jumpOrigin);

        ProcessDefinitionImpl processDefinition = executionEntity.getProcessDefinition();
        ActivityImpl activity = processDefinition.findActivity(activityId);

        if(!activityId.equals("end") && jumpOrigin.equals("disapprove")) {
            executionEntity.setVariable("users",taskUsers);
            executionEntity.setVariable("user",taskUser);
        }

        executionEntity.executeActivity(activity);

        return executionEntity;

    }

}
<code>

Outcomes