package com.pty.workflow.service.extend;
import java.util.List;
import org.activiti.bpmn.model.ExclusiveGateway;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.delegate.event.ActivitiEventDispatcher;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.cmd.NeedsActiveTaskCmd;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.IdentityLinkEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import com.pty.workflow.api.RollbackPosition;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class RollbackTaskCmd extends NeedsActiveTaskCmd<Void> {
/**
*
*/
private static final long serialVersionUID = 1264547749014497759L;
private RollbackPosition _position;
private String _designatedNodeId;
public RollbackTaskCmd(String taskId, RollbackPosition position, String... designatedNodeId) {
super(taskId);
_position = position;
if (designatedNodeId.length > 0) {
_designatedNodeId = designatedNodeId[0];
}
}
@Override
protected Void execute(CommandContext commandContext, TaskEntity task) {
ActivitiEventDispatcher eventDispatcher = Context.getProcessEngineConfiguration().getEventDispatcher();
// TODO(liubo): 增加退回的enum
if (eventDispatcher.isEnabled()) {
eventDispatcher
.dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.TASK_COMPLETED, task));
}
if (task.getExecutionId() != null) {
ExecutionEntity executionEntity = commandContext.getExecutionEntityManager()
.findExecutionById(task.getExecutionId());
if (_position.equals(RollbackPosition.START)) {
rollback2Start(commandContext, task, executionEntity);
} else if (_position.equals(RollbackPosition.PREVIOUS)) {
rollback2Previous(commandContext, task, executionEntity);
} else if (_position.equals(RollbackPosition.DESIGNATED)) {
rollback2Designated(commandContext, task, executionEntity);
}
// Context.getAgenda().planTriggerExecutionOperation(executionEntity);
}
return null;
}
// 退回到流程初始的任务节点
private void rollback2Start(CommandContext commandContext, TaskEntity task, ExecutionEntity executionEntity) {
// TODO(liubo): 设置creator
task.setVariable("creator", this.getProcessCreator(task, commandContext));
List<TaskEntity> tasks = commandContext.getTaskEntityManager().findTasksByExecutionId(task.getExecutionId());
tasks.forEach(taskEntity -> {
//commandContext.getTaskEntityManager().delete(taskEntity);
commandContext.getTaskEntityManager().deleteTask(taskEntity, null, false);
});
Process process = Context.getProcessEngineConfiguration().getRepositoryService()
.getBpmnModel(task.getProcessDefinitionId()).getMainProcess();
String firstUserTaskNode = process.findFlowElementsOfType(StartEvent.class).get(0).getOutgoingFlows().get(0)
.getTargetRef();
task.fireEvent("rollback");
executionEntity.removeTask(task);
executionEntity.executeActivity(executionEntity.getProcessDefinition().findActivity(firstUserTaskNode));
}
// 退回到上一个任务节点
private void rollback2Previous(CommandContext commandContext, TaskEntity task, ExecutionEntity executionEntity) {
commandContext.getTaskEntityManager().deleteTask(task, null, false);
Process process = Context.getProcessEngineConfiguration().getRepositoryService()
.getBpmnModel(task.getProcessDefinitionId()).getMainProcess();
FlowNode prevNode = getPrevousNode(task, process);
if (prevNode == null) {
throw new RuntimeException("前置任务节点未找到");
}
if (prevNode.getIncomingFlows().stream().anyMatch(ele -> {
return StartEvent.class.isAssignableFrom(process.getFlowElement(ele.getSourceRef()).getClass());
})) {
task.setVariable("creator", this.getProcessCreator(task, commandContext));
}
// TODO(liubo):如果退回的是第一个任务节点,将creator注入
task.fireEvent("rollback");
executionEntity.removeTask(task);
executionEntity.executeActivity(executionEntity.getProcessDefinition().findActivity(prevNode.getId()));
}
private void rollback2Designated(CommandContext commandContext, TaskEntity task, ExecutionEntity executionEntity) {
throw new RuntimeException("暂不支持退回到任一指定节点");
}
private FlowNode getPrevousNode(TaskEntity task, Process process) {
// Process process =
// ProcessDefinitionUtil.getProcess(task.getProcessDefinitionId());
// FlowNode currentNode = (FlowNode)
// process.getFlowElement(task.getTaskDefinitionKey());
// HistoryService historyService =
// Context.getProcessEngineConfiguration().getHistoryService();
// return getPrevTaskNode(task.getProcessInstanceId(), currentNode, process,
// historyService);
HistoricTaskInstance taskHis = Context.getProcessEngineConfiguration().getHistoryService()
.createHistoricTaskInstanceQuery().executionId(task.getExecutionId()).finished()
.orderByHistoricTaskInstanceEndTime().desc().list().get(0);
return (FlowNode) process.getFlowElement(taskHis.getTaskDefinitionKey());
}
private String getProcessCreator(TaskEntity task, CommandContext commandContext) {
List<IdentityLinkEntity> links = commandContext.getIdentityLinkEntityManager()
.findIdentityLinksByProcessInstanceId(task.getProcessInstanceId());
return links.stream().filter(link -> {
return "starter".equals(link.getType());
}).findFirst().get().getUserId();
}
@Deprecated
private FlowNode getPrevTaskNode(String processId, FlowElement curNode, Process process,
HistoryService historyService) {
if (curNode == null) {
return null;
}
if (!FlowNode.class.isAssignableFrom(curNode.getClass())) {
return null;
}
List<SequenceFlow> sequences = ((FlowNode) curNode).getIncomingFlows();
for (SequenceFlow seq : sequences) {
FlowElement ele = process.getFlowElement(seq.getSourceRef());
if (UserTask.class.isAssignableFrom(ele.getClass())) {
try {
HistoricActivityInstance his = historyService.createHistoricActivityInstanceQuery()
.processDefinitionId(processId).activityId(ele.getId())
.orderByHistoricActivityInstanceEndTime().desc().singleResult();
return (FlowNode) ele;
} catch (Exception ex) {
log.error("error", ex);
}
} else if (ExclusiveGateway.class.isAssignableFrom(ele.getClass())) {
return getPrevTaskNode(processId, ele, process, historyService);
}
}
return null;
}
}
package com.pty.workflow.service;
import com.pty.workflow.api.IPtyWfRuntimeService;
import com.pty.workflow.api.IWfEventCallback;
import com.pty.workflow.api.RollbackPosition;
import com.pty.workflow.dao.ActHiActInstDao;
import com.pty.workflow.dao.ActHiVarInstDao;
import com.pty.workflow.dao.ActRuTaskDao;
import com.pty.workflow.dao.WfTaskDao;
import com.pty.workflow.entity.ActRuExecution;
import com.pty.workflow.entity.ActRuTask;
import com.pty.workflow.entity.WfTask;
import com.pty.workflow.service.extend.RollbackTaskCmd;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.event.ActivitiEventListener;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RuntimeServiceImpl;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class PtyWfRuntimeService implements IPtyWfRuntimeService {
@Autowired
private ProcessEngine activitiEngine;
@Autowired
private PtyWfDeployService ptyWfDeployService;
@Autowired
private WfTaskDao taskDao;
@Autowired
private ActRuTaskDao actRuTaskDao;
@Autowired
private ActHiVarInstDao actHiVarInstDao;
@Autowired
private ActHiActInstDao actHiActInstDao;
@Override
public WfTask startProcess(String tenantId, String processKey, String businessId, String submitter, Map vars,
IWfEventCallback eventCallback) {
ActivitiEventListener eventListener = null;
if (eventCallback != null) {
eventListener = new PtyWfEventListener(eventCallback);
activitiEngine.getRuntimeService().addEventListener(eventListener);
}
try {
//vars.put("creator", submitter);
// 设置流程发起人
activitiEngine.getIdentityService().setAuthenticatedUserId(submitter);
ProcessInstance pi = activitiEngine.getRuntimeService().startProcessInstanceByKeyAndTenantId(processKey,
businessId, vars, tenantId);
Task task = activitiEngine.getTaskService().createTaskQuery().processInstanceId(pi.getProcessInstanceId())
/*.taskAssignee(submitter)*/.singleResult();
task.setAssignee(submitter);
activitiEngine.getTaskService().saveTask(task);
WfTask wfTask = new WfTask();
wfTask.setTaskId(task.getId());
wfTask.setProcessInstanceId(task.getProcessInstanceId());
wfTask.setTodo(1);
return wfTask;
} catch (ActivitiException ex) {
throw new RuntimeException(ex.getMessage() + "->" + ex.getCause().getMessage());
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if (eventListener != null) {
activitiEngine.getRuntimeService().removeEventListener(eventListener);
}
}
}
@Override
// todo(李世超):同一个单据是否可以重复启动,以及重复启动的条件???
public WfTask startProcess(String tenantId, String processKey, String businessId, String submitter, Map vars) {
return startProcess(tenantId, processKey, businessId, submitter, vars, null);
}
@Override
public void submitTask(String taskId, String submitter, String comment, Map vars, IWfEventCallback eventCallback) {
ActivitiEventListener eventListener = null;
if (eventCallback != null) {
eventListener = new PtyWfEventListener(eventCallback);
activitiEngine.getRuntimeService().addEventListener(eventListener);
}
try {
TaskService taskService = activitiEngine.getTaskService();
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
// throw new RuntimeException("待办任务" + taskId + "不存在");
throw new RuntimeException("单据号:" + vars.get("billNo") + "已提交");//billNo
}
if (comment != null && !comment.isEmpty()) {
taskService.addComment(taskId, task.getProcessInstanceId(), comment);
}
String assignee = taskService.createTaskQuery().taskId(taskId).singleResult().getAssignee();
if (assignee == null) {
taskService.claim(taskId, submitter);
}
taskService.complete(taskId, vars, true);
} catch (ActivitiException ex) {
throw new RuntimeException(ex.getMessage() + "->" + ex.getCause().getMessage());
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if (eventListener != null) {
activitiEngine.getRuntimeService().removeEventListener(eventListener);
}
}
}
@Override
public void submitTask(String taskId, String submitter, String comment, Map vars) {
submitTask(taskId, submitter, comment, vars, null);
}
@Deprecated
public void rollBack(String taskId, String submitter, String comment) {
try {
Task task = activitiEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
Execution execution = activitiEngine.getRuntimeService().createExecutionQuery()
.executionId(task.getExecutionId()).singleResult();
String executionId = execution.getId();
String processInstanceId = execution.getProcessInstanceId();
List<Task> listTask = activitiEngine.getTaskService().createTaskQuery().processInstanceId(processInstanceId)
.list();
if (listTask.size() >= 2) {
throw new RuntimeException("此任务不可进行回退");
}
List<HistoricTaskInstance> list = activitiEngine.getHistoryService().createHistoricTaskInstanceQuery()
.executionId(executionId).orderByHistoricTaskInstanceEndTime().desc().list();
HistoricTaskInstance currTask = list.get(0);
String processDefinitionId = currTask.getProcessDefinitionId();
BpmnModel bpmnModel = ptyWfDeployService.getBpmnModel(processDefinitionId);
String myActivityId = null;
List<HistoricActivityInstance> haiList = activitiEngine.getHistoryService()
.createHistoricActivityInstanceQuery().executionId(currTask.getExecutionId()).finished().list();
for (HistoricActivityInstance hai : haiList) {
if (currTask.getId().equals(hai.getTaskId())) {
myActivityId = hai.getActivityId();
break;
}
}
FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
String activityId = execution.getActivityId();
// logger.warn("------->> activityId:" + activityId);
FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
// 记录原活动方向
List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
oriSequenceFlows.addAll(flowNode.getOutgoingFlows());
// 清理活动方向
flowNode.getOutgoingFlows().clear();
// 建立新方向
List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setSourceRef(flowNode.getId());
newSequenceFlow.setTargetRef(myFlowNode.getId());
newSequenceFlowList.add(newSequenceFlow);
flowNode.setOutgoingFlows(newSequenceFlowList);
Authentication.setAuthenticatedUserId(submitter);
activitiEngine.getTaskService().addComment(task.getId(), task.getProcessInstanceId(), comment);
activitiEngine.getTaskService().claim(taskId, submitter);
// 完成任务
activitiEngine.getTaskService().complete(task.getId());
// 恢复原方向
flowNode.setOutgoingFlows(oriSequenceFlows);
} catch (ActivitiException ex) {
throw new RuntimeException(ex.getMessage() + "->" + ex.getCause().getMessage());
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@Override
public void terminate(String busiKey, String submitter, String comment) {
HistoricProcessInstance instance = activitiEngine.getHistoryService().createHistoricProcessInstanceQuery()
.processInstanceBusinessKey(busiKey).singleResult();
if (instance != null) {
RuntimeService runtimeService = activitiEngine.getRuntimeService();
runtimeService.deleteProcessInstance(instance.getId(), comment);
}
}
@Override
public void rollBack(String taskId, String submitter, String comment, RollbackPosition position,
String designatedNodeId,IWfEventCallback eventCallback) {
ActivitiEventListener eventListener = null;
if (eventCallback != null) {
eventListener = new PtyWfEventListener(eventCallback);
activitiEngine.getRuntimeService().addEventListener(eventListener);
}
try {
TaskService taskService = activitiEngine.getTaskService();
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (comment != null && !comment.isEmpty()) {
taskService.addComment(taskId, task.getProcessInstanceId(), comment);
}
String assignee = taskService.createTaskQuery().taskId(taskId).singleResult().getAssignee();
if (assignee == null) {
taskService.claim(taskId, submitter);
}
RuntimeServiceImpl runtimeService = (RuntimeServiceImpl) activitiEngine.getRuntimeService();
runtimeService.getCommandExecutor().execute(new RollbackTaskCmd(taskId, position, designatedNodeId));
Task newTask=activitiEngine.getTaskService().createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
ActRuTask actRuTask =new ActRuTask();
actRuTask.setId(newTask.getId());
actRuTask.setIsReturn("1");
actRuTaskDao.updateById(actRuTask);
} catch (ActivitiException ex) {
throw new RuntimeException(ex.getMessage() + "->" + ex.getCause().getMessage());
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
if (eventListener != null) {
activitiEngine.getRuntimeService().removeEventListener(eventListener);
}
}
}
@Override
public List<Map<String, Object>> findVariables(String processId) {
List<Map<String, Object>> vars = taskDao.findVariables(processId);
return vars;
}
@Override
public Map<String, Object> getProcessVariables(String processInstanceId) {
List<Map<String, Object>> vars = taskDao.findVariables(processInstanceId);
Map<String, Object> nameValueMap = new HashMap<String, Object>();
for (Map<String, Object> processMap : vars) {
String name = (String) processMap.get("name");
String value = (String) processMap.get("value");
nameValueMap.put(name, value);
}
String taskDefinitionKey=activitiEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().getProcessDefinitionKey();
nameValueMap.put("wfId", taskDefinitionKey);
return nameValueMap;
}
@Override
public Map<String, Object> getSubmitVariables(String processInstanceId) {
List<HistoricTaskInstance> list=activitiEngine.getHistoryService().createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
.orderByHistoricTaskInstanceEndTime().asc().list();
String taskId=list.get(0).getId();
List<Map<String, Object>> vars =taskDao.findLocalVariables(taskId);
Map<String, Object> nameValueMap = new HashMap<String, Object>();
for (Map<String, Object> processMap : vars) {
String name = (String) processMap.get("name");
String value = (String) processMap.get("value");
nameValueMap.put(name, value);
}
String taskDefinitionKey=activitiEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().getProcessDefinitionKey();
nameValueMap.put("wfId", taskDefinitionKey);
return nameValueMap;
}
@Override
public void updateVriables(String executionId,Map vars) {
activitiEngine.getRuntimeService().setVariables(executionId, vars);
}
@Override
public String getExecutionIdBytaskId(String taskId) {
return activitiEngine.getTaskService().createTaskQuery().taskId(taskId).list().get(0).getExecutionId();
}
@Override
public void deleteVriables(String procInstId) {
actHiVarInstDao.deleteVriables(procInstId);
}
@Override
public void deleteProcinst(String procInstId) {
actHiVarInstDao.deleteProcinst(procInstId);
}
@Override
public void lastRollBack(String wfTaskId, String processInstanceId) {
HistoricTaskInstance task=activitiEngine.getHistoryService().createHistoricTaskInstanceQuery().taskId(wfTaskId).singleResult();
ActRuTask actRuTask =new ActRuTask();
actRuTask.setId(task.getId());
actRuTask.setRev(2);
actRuTask.setExecutionId(task.getExecutionId());
actRuTask.setProcInstId(task.getProcessInstanceId());
actRuTask.setProcDefId(task.getProcessDefinitionId());
actRuTask.setName(task.getName());
actRuTask.setParentTaskId("");
actRuTask.setDescription("");
actRuTask.setTaskEefKey(task.getTaskDefinitionKey());
actRuTask.setOwner(task.getOwner());
actRuTask.setAssignee(task.getAssignee());
actRuTask.setDelegation("");
actRuTask.setPriority(50);
actRuTask.setCreateTime(task.getCreateTime());
//actRuTask.setDueDate(1);
actRuTask.setCategory(task.getCategory());
actRuTask.setSuspensionState(1);
actRuTask.setTenantId(task.getTenantId());
actRuTask.setFormKey(task.getFormKey());
actRuTask.setClaimTime(task.getClaimTime());
actRuTask.setIsReturn("1");
HistoricProcessInstance pi=activitiEngine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(processInstanceId)
.singleResult();
ActRuExecution actRuExecution=new ActRuExecution();
actRuExecution.setActId(pi.getEndActivityId());
actRuExecution.setBusinessKey(pi.getBusinessKey());
actRuExecution.setCachedEntState(2);
actRuExecution.setDeadletterJobCount(0);
actRuExecution.setEvtSubscrCount(0);
actRuExecution.setId(pi.getId());
actRuExecution.setIdLinkCount("");
actRuExecution.setIsActive(1);
actRuExecution.setIsConcurrent(0);
actRuExecution.setIsCountEnabled(0);
actRuExecution.setIsEventScope(0);
actRuExecution.setIsMiRoor(0);//
actRuExecution.setIsScope(1);
actRuExecution.setJobCount(0);//
actRuExecution.setLockTime("");//
actRuExecution.setName(pi.getName());
actRuExecution.setParentId("");//
actRuExecution.setProcDefId(pi.getProcessDefinitionId());
actRuExecution.setProcInstId(pi.getSuperProcessInstanceId());
actRuExecution.setRev(0);//
actRuExecution.setRootProcInstId("");//
actRuExecution.setStartTime(pi.getStartTime());
actRuExecution.setStartUserId(pi.getStartUserId());
actRuExecution.setSuperExec("");
actRuExecution.setSuspensionState(0);//
actRuTaskDao.insert(actRuTask);
actHiActInstDao.delByTaskId(wfTaskId);
}
@Override
public void suspendProcess(String processInstanceId) {
activitiEngine.getRuntimeService().suspendProcessInstanceById(processInstanceId);
}
@Override
public String getBussKey(String taskId) {
Task task=activitiEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
ProcessInstance pi = activitiEngine.getRuntimeService().createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
//3 通过流程实例获取“业务键”
return pi.getBusinessKey();
}
}
package com.pty.workflow.dao;
import com.pty.pub.common.anno.MyBatisDao;
@MyBatisDao
public interface ActHiActInstDao {
void delById(String taskId);
void del(String taskId);
void delByTaskId(String taskId);
}