一、什么是多实例减签,多实例加签
比如配置了一个多实例用户实例,由三人串行或者并行执行,那么现在的需求是某个个例不需要那么多人了,只需要两个人也就是减少一个人,这样的操作称为减签操作。
反之,当需要添加一个人员参与会签时的操作,就称之为加签操作。
二、多实例减签(仅支持6版本)
思路
通过多实例运转过程很容易能够理清如何实现减签操作,如果需要明白运转过程可以参考activiti6.0源码剖析之多实例运转过程
以该流程图为例说明
减签可以从两种角度去看:被减掉的是以已经执行成功来做,还是压根就当作没有存在过
根据上述两种角度可以大致理清以下思路
首先根据需要减掉的任务Id获取到该任务ID所属的三级执行实例
然后根据三级执行实例ID或者多多实例执行实例的父级实例(二级实例)
通过二级执行实例删除需要减掉的三级执行实例数据,任务数据
-
根据二级执行实例获取nrOfInstances,nrOfCompletedInstances,nrOfActiveInstances,loopCounter变量,并根据并行或者串行多实例,根据上述两种角度进行相应的变更
如果是串行多实例减签
正常执行完成的角度上:nrOfCompletedInstances 加 1,nrOfActiveInstances保持1不变,loopCounter 加 1
非正常完成的角度上:nrOfInstances 减 1,loopCounter 加 1如果是并行多实例减签
正常执行完成的角度上:nrOfCompletedInstances 加 1,nrOfActiveInstances 减 1,
非正常完成的角度上:nrOfInstances 减 1,nrOfActiveInstances 减 1,
实战
public class DeleteMultiInstanceCmd implements Command {
protected final String NUMBER_OF_INSTANCES = "nrOfInstances";
protected final String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
protected final String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances";
protected String collectionElementIndexVariable = "loopCounter";
private String taskId;
private Boolean isNormalComplete;
public DeleteMultiInstanceCmd(String taskId,boolean isNormalComplete) {
this.taskId = taskId;
this.isNormalComplete = isNormalComplete;
}
public Object execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
//根据任务id获取任务实例
TaskEntity taskEntity = taskEntityManager.findById(taskId);
//根据执行实例ID获取三级执行实例
ExecutionEntity execution = executionEntityManager.findById(taskEntity.getExecutionId());
//首先判断当前任务是否是属于多实例节点
String processDefinitionId = execution.getProcessDefinitionId();
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
Activity activityElement = (Activity)bpmnModel.getFlowElement(execution.getCurrentActivityId());
MultiInstanceLoopCharacteristics loopCharacteristics = activityElement.getLoopCharacteristics();
if(loopCharacteristics == null){
throw new RuntimeException("没有找到多实例");
}
if(!(activityElement.getBehavior() instanceof MultiInstanceActivityBehavior)){
throw new RuntimeException("此节点不是多实例节点");
}
DeploymentManager deploymentManager = commandContext.getProcessEngineConfiguration().getDeploymentManager();
ProcessDefinition definition = deploymentManager.findDeployedProcessDefinitionById(processDefinitionId);
//判断是否是5的版本
if(Activiti5Util.isActiviti5ProcessDefinition(commandContext,definition)){
throw new RuntimeException("不支持5版本");
}
boolean isSequential = loopCharacteristics.isSequential();
//获取二级执行实例
ExecutionEntity sencondExecution = execution.getParent();
//删除所要删除的实例相关数据
if(!isSequential){
//并行多实例
executionEntityManager.deleteChildExecutions(execution,"减签",false);
executionEntityManager.deleteExecutionAndRelatedData(execution,"减签",true);
}
//获取二级执行实例关联的变量
Integer nrOfInstances = (Integer) sencondExecution.getVariable(NUMBER_OF_INSTANCES);
Integer nrOfActiveInstances = (Integer) sencondExecution.getVariable(NUMBER_OF_ACTIVE_INSTANCES);
Integer nrOfCompletedInstances = (Integer) sencondExecution.getVariable(NUMBER_OF_COMPLETED_INSTANCES);
//更新二级执行实例关联的变量
if(isNormalComplete){
//正常完成
sencondExecution.setVariable(NUMBER_OF_COMPLETED_INSTANCES,nrOfCompletedInstances+1 );
if(isSequential){
//串行多实例
Integer loopCounter =getLoopVariable(execution,collectionElementIndexVariable);
execution.setVariableLocal(collectionElementIndexVariable,loopCounter+1);
}else{
//并行多实例
sencondExecution.setVariableLocal(NUMBER_OF_ACTIVE_INSTANCES,nrOfActiveInstances-1);
}
}else{
//非正常(就当作没有过此任务)
sencondExecution.setVariableLocal(NUMBER_OF_INSTANCES,nrOfInstances-1);
if(isSequential){
//串行多实例
Integer loopCounter = (Integer) execution.getVariable(collectionElementIndexVariable);
execution.setVariableLocal(collectionElementIndexVariable,loopCounter+1);
}else{
//并行多实例
//并行多实例
sencondExecution.setVariableLocal(NUMBER_OF_ACTIVE_INSTANCES,nrOfActiveInstances-1);
}
}
//删除任务
taskEntityManager.delete(taskId);
//触发流程运转
ActivitiEngineAgenda agenda = commandContext.getAgenda();
agenda.planContinueProcessInCompensation(execution);
return null;
}
protected Integer getLoopVariable(DelegateExecution execution, String variableName) {
Object value = execution.getVariableLocal(variableName);
DelegateExecution parent = execution.getParent();
while (value == null && parent != null) {
value = parent.getVariableLocal(variableName);
parent = parent.getParent();
}
return (Integer) (value != null ? value : 0);
}
}
三、并行多实例加签
思路
- 根据业务需求获取到多实例父级执行实例
- 判断当前节点是否是并行多实例
- 根据多实例父级实例创建多实例执行实例(也就是新加的人员所在执行实例)
- 为新建的多实例执行实例设置当前处理节点
- 更改多实例父级执行实例的变量
nrOfInstances+1
nrOfActiveInstances+1 - 通知该活动开始
- 获取行为类
- 执行行为类
实战
public class AddMultiInstanceCmd implements Command {
protected final String NUMBER_OF_INSTANCES = "nrOfInstances";
protected final String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
private String multiRootExecutionId;
private String addUserTaskAssign;
public AddMultiInstanceCmd(String multiRootExecutionId, String addUserTaskAssign) {
this.multiRootExecutionId = multiRootExecutionId;
this.addUserTaskAssign = addUserTaskAssign;
}
public Object execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
//获取多实例父级执行实例
ExecutionEntity multiExecutionEntity = executionEntityManager.findById(multiRootExecutionId);
//判断当前执行实例的节点是否是多实例节点
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(multiExecutionEntity.getProcessDefinitionId());
Activity miActivityElement = (Activity) bpmnModel.getFlowElement(multiExecutionEntity.getCurrentActivityId());
MultiInstanceLoopCharacteristics loopCharacteristics = miActivityElement.getLoopCharacteristics();
if(loopCharacteristics == null){
throw new ActivitiException("此节点不是多实例节点");
}
//判断是否是并行多实例
if(loopCharacteristics.isSequential()){
throw new ActivitiException("此节点为串行节点");
}
//创建新的子实例
ExecutionEntity childExecution = executionEntityManager.createChildExecution(multiExecutionEntity);
//获取并为新的执行实例设置当前活动节点
UserTask currentFlowElement = (UserTask) multiExecutionEntity.getCurrentFlowElement();
//设置处理人
currentFlowElement.setAssignee(addUserTaskAssign);
childExecution.setCurrentFlowElement(currentFlowElement);
//获取设置变量
Integer nrOfInstances = (Integer) multiExecutionEntity.getVariableLocal(NUMBER_OF_INSTANCES);
Integer nrOfActiveInstances = (Integer) multiExecutionEntity.getVariableLocal(NUMBER_OF_ACTIVE_INSTANCES);
multiExecutionEntity.setVariableLocal(NUMBER_OF_INSTANCES,nrOfInstances+1);
multiExecutionEntity.setVariableLocal(NUMBER_OF_ACTIVE_INSTANCES,nrOfActiveInstances+1);
//通知活动开始
HistoryManager historyManager = commandContext.getHistoryManager();
historyManager.recordActivityStart(childExecution);
//获取处理行为类
ParallelMultiInstanceBehavior prallelMultiInstanceBehavior = (ParallelMultiInstanceBehavior) miActivityElement.getBehavior();
AbstractBpmnActivityBehavior innerActivityBehavior = prallelMultiInstanceBehavior.getInnerActivityBehavior();
//执行
innerActivityBehavior.execute(childExecution);
return null;
}
}