activiti学习(二十七)——涉及并行网关的节点跳转

分析

关于并行任务的跳转,分享牛大神有他的代码。不过我觉得并行网关分支出来的任务,无论从现实业务还是逻辑实现上,都不应该可以随意跳转。

分享牛的跳转逻辑,无非是把并行分支的execution及其对应task都结束,然后跳转到目标节点上。然而这里其实涉及一些问题。从业务上来讲,某个分支流程,它自己是否要跳转到别的节点,不应该影响平行的其他任务节点,除非有明确的业务要求。从实现逻辑的角度来说,当存在多个并行网关多次分支的流程图中,跳转到某个节点时,到底需要提前结束哪些任务就会变得极难判断,如下图所示。综上所述,我认为并行网关中的任务不应该随意进行跳转。

activiti学习(二十七)——涉及并行网关的节点跳转_第1张图片

实际业务可能不存在这样的流程,这里夸张了一点,纯粹举个例子。例如usertask6要跳转到usertask7,那根据图上来看,usertask5、usertask3的任务和execution必须删除。而且例如usertask4要跳转到usertask1,涉及的并行execution如何处理也是个问题。所以真不建议在并行网关中使用跳转。

只有一种情况的是可以进行跳转的,就是同一分支上的节点之间的跳转。例如下图这样:

activiti学习(二十七)——涉及并行网关的节点跳转_第2张图片

usertask3跳转到usertask1,usertask2跳转到usertask6。类似这些在同一分支上的任务节点跳转,情况和普通的跳转类似,不过我们还是要对前面的例子改改

 

代码

这次我们的流程图如下,会有分支、以及多实例任务,我们计划是usertask1和usertask3之间可来回跳转,usertask2和usertask4也是如此:

activiti学习(二十七)——涉及并行网关的节点跳转_第3张图片



  
    
    
    
    
      
        3
      
    
    
    
    
    
    
    
      
        3
      
    
    
    
    
    
    
    
  
  
    
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
        
      
      
        
        
        
      
      
        
        
        
      
      
        
        
      
      
        
        
      
      
        
        
        
      
      
        
        
        
      
      
        
        
      
    
  

跳转的代码与前面MultiInstanceJumpCmd类似,但是要还要进行一些修改。之前我们是通过getProcessInstance获取其流程实例,进而获得其父execution,另外task也是与流程实例id关联的,通过流程实例id去控制是一种相对简便的处理方式。但在并行网关中,如果我们只处理单个分支的情况,通过流程实例id去处理task和execution,很可能会把另一分支也处理了,这不符合我们的预期,我们仅仅是需要处理当前分支对应的task和execution而已,所以不能通过流程实例id去操作,要老老实实根据活动节点的分类,判断是否获取其父节点进行操作:

package jump;

import java.util.List;
import java.util.Map;

import org.activiti.engine.delegate.TaskListener;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.runtime.AtomicOperation;
import org.activiti.engine.runtime.Execution;

public class ParallelJumpCmd implements Command {

	private String taskId;
	private Map variables;
	private String desActivityId;
	private String scActivityId;

	public ParallelJumpCmd(String taskId, Map variables, String scActivityId, String desActivityId) {
		this.taskId = taskId;
		this.variables = variables;
		this.desActivityId = desActivityId;
		this.scActivityId = scActivityId;
	}

	public Object execute(CommandContext commandContext) {
		TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
		TaskEntity taskEntity = taskEntityManager.findTaskById(taskId);
		ExecutionEntity parentExecutionEntity = taskEntity.getProcessInstance();
		String processDefinitionId = parentExecutionEntity.getProcessDefinitionId();
		ProcessDefinitionEntity processDefinitionEntity = Context.getProcessEngineConfiguration().getDeploymentManager()
				.findDeployedProcessDefinitionById(processDefinitionId);
		ActivityImpl curActivityImpl = processDefinitionEntity.findActivity(scActivityId);

		if(curActivityImpl.getActivityBehavior() instanceof SequentialMultiInstanceBehavior) {
			parentExecutionEntity = taskEntity.getExecution().getParent();
		}else if(curActivityImpl.getActivityBehavior() instanceof ParallelMultiInstanceBehavior) {
			parentExecutionEntity = taskEntity.getExecution().getParent().getParent();
		}else {
			parentExecutionEntity = taskEntity.getExecution();
		}
		
		// 设置流程变量
		parentExecutionEntity.setVariables(variables);
		parentExecutionEntity.setExecutions(null);
		parentExecutionEntity.setActivity(curActivityImpl);
		parentExecutionEntity.setEventSource(curActivityImpl);
		parentExecutionEntity.setActive(true);

		// 触发全局事件转发器TASK_COMPLETED事件
		if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
			Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder
					.createEntityWithVariablesEvent(ActivitiEventType.TASK_COMPLETED, this, variables, false));
		}

		// 删除任务
		List childExecutionEntityList = parentExecutionEntity.getExecutions();
		if(childExecutionEntityList.size() == 0) {
			//普通任务
			taskEntityManager.deleteTask(taskEntity, TaskEntity.DELETE_REASON_COMPLETED, false);	
		}
		for(ExecutionEntity childExecutionEntity : childExecutionEntityList) {
			List childExecutionEntityList1 = childExecutionEntity.getExecutions();
			if(childExecutionEntityList1.size() == 0) {
				//串行多实例任务处理
				List taskList = childExecutionEntity.getTasks();
				for(TaskEntity task : taskList) {
					task.fireEvent(TaskListener.EVENTNAME_COMPLETE);
					taskEntityManager.deleteTask(task, TaskEntity.DELETE_REASON_COMPLETED, false);	
				}
			}else {
				//并行多实例任务处理
				for(ExecutionEntity childExecutionEntity1 : childExecutionEntityList1) {
					List taskList1 = childExecutionEntity1.getTasks();
					for(TaskEntity task : taskList1) {
						task.fireEvent(TaskListener.EVENTNAME_COMPLETE);
						taskEntityManager.deleteTask(task, TaskEntity.DELETE_REASON_COMPLETED, false);	
					}
				}
			}
		}

		ExecutionEntityManager executionEntityManager = Context.getCommandContext().getExecutionEntityManager();
		List childExecutionList = executionEntityManager.findChildExecutionsByParentExecutionId(parentExecutionEntity.getId());
		for(ExecutionEntity executionEntityChild : childExecutionList) {
			List childExecutionList1 = executionEntityManager.findChildExecutionsByParentExecutionId(executionEntityChild.getId());
			for(ExecutionEntity executionEntityChild1 : childExecutionList1) {
				executionEntityChild1.remove();
				Context.getCommandContext().getHistoryManager().recordActivityEnd(executionEntityChild1);
			}
			executionEntityChild.remove();
			Context.getCommandContext().getHistoryManager().recordActivityEnd(executionEntityChild);
		}
		
		commandContext.getIdentityLinkEntityManager().deleteIdentityLinksByProcInstance(parentExecutionEntity.getId());
		ActivityImpl desActivityimpl = processDefinitionEntity.findActivity(desActivityId);	
		
		parentExecutionEntity.removeVariable("nrOfInstances");
		parentExecutionEntity.removeVariable("nrOfActiveInstances");
		parentExecutionEntity.removeVariable("nrOfCompletedInstances");
		parentExecutionEntity.removeVariable("loopCounter");
		
		parentExecutionEntity.setActivity(desActivityimpl);
		parentExecutionEntity.performOperation(AtomicOperation.TRANSITION_CREATE_SCOPE);

		return null;
	}
}

46-52行判断节点是串行多实例、并行多实例还是普通任务节点,分情况获取分支的父execution。68-92行也是分情况删除其execution下对应的task。如果还是像之前多实例任务跳转那样处理,就会把另一条分支上的task也删除了。另外59行要把状态设置成活动,因为多实例任务的父execution的isActive是false,跳转到普通任务节点,之后会导致普通任务节点的execution的usActive状态也是false,这就不对了。其他操作与前面的跳转是类似的,就不重复叙述了。

你可能感兴趣的:(Activiti)