关于并行任务的跳转,分享牛大神有他的代码。不过我觉得并行网关分支出来的任务,无论从现实业务还是逻辑实现上,都不应该可以随意跳转。
分享牛的跳转逻辑,无非是把并行分支的execution及其对应task都结束,然后跳转到目标节点上。然而这里其实涉及一些问题。从业务上来讲,某个分支流程,它自己是否要跳转到别的节点,不应该影响平行的其他任务节点,除非有明确的业务要求。从实现逻辑的角度来说,当存在多个并行网关多次分支的流程图中,跳转到某个节点时,到底需要提前结束哪些任务就会变得极难判断,如下图所示。综上所述,我认为并行网关中的任务不应该随意进行跳转。
实际业务可能不存在这样的流程,这里夸张了一点,纯粹举个例子。例如usertask6要跳转到usertask7,那根据图上来看,usertask5、usertask3的任务和execution必须删除。而且例如usertask4要跳转到usertask1,涉及的并行execution如何处理也是个问题。所以真不建议在并行网关中使用跳转。
只有一种情况的是可以进行跳转的,就是同一分支上的节点之间的跳转。例如下图这样:
usertask3跳转到usertask1,usertask2跳转到usertask6。类似这些在同一分支上的任务节点跳转,情况和普通的跳转类似,不过我们还是要对前面的例子改改
这次我们的流程图如下,会有分支、以及多实例任务,我们计划是usertask1和usertask3之间可来回跳转,usertask2和usertask4也是如此:
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,这就不对了。其他操作与前面的跳转是类似的,就不重复叙述了。