/*
* Copyright 2023-2025 Licensed under the AGPL License
*/
package com.aizuda.bpm.mybatisplus.service;
import com.aizuda.bpm.engine.TaskAccessStrategy;
import com.aizuda.bpm.engine.TaskService;
import com.aizuda.bpm.engine.assist.Assert;
import com.aizuda.bpm.engine.assist.DateUtils;
import com.aizuda.bpm.engine.assist.ObjectUtils;
import com.aizuda.bpm.engine.core.Execution;
import com.aizuda.bpm.engine.core.FlowCreator;
import com.aizuda.bpm.engine.core.enums.EventType;
import com.aizuda.bpm.engine.core.enums.PerformType;
import com.aizuda.bpm.engine.core.enums.TaskState;
import com.aizuda.bpm.engine.core.enums.TaskType;
import com.aizuda.bpm.engine.entity.*;
import com.aizuda.bpm.engine.listener.TaskListener;
import com.aizuda.bpm.engine.model.NodeAssignee;
import com.aizuda.bpm.engine.model.NodeModel;
import com.aizuda.bpm.engine.model.ProcessModel;
import com.aizuda.bpm.mybatisplus.mapper.*;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* 任务执行业务类
*
* <p>
* 尊重知识产权,不允许非法使用,后果自负
* </p>
*
* @author hubin
* @since 1.0
*/
public class TaskServiceImpl implements TaskService {
private final TaskAccessStrategy taskAccessStrategy;
private final FlwProcessMapper processMapper;
private final TaskListener taskListener;
private final FlwInstanceMapper instanceMapper;
private final FlwHisInstanceMapper hisInstanceMapper;
private final FlwTaskMapper taskMapper;
private final FlwTaskActorMapper taskActorMapper;
private final FlwHisTaskMapper hisTaskMapper;
private final FlwHisTaskActorMapper hisTaskActorMapper;
public TaskServiceImpl(TaskAccessStrategy taskAccessStrategy, TaskListener taskListener, FlwProcessMapper processMapper,
FlwInstanceMapper instanceMapper, FlwHisInstanceMapper hisInstanceMapper, FlwTaskMapper taskMapper,
FlwTaskActorMapper taskActorMapper, FlwHisTaskMapper hisTaskMapper,
FlwHisTaskActorMapper hisTaskActorMapper) {
this.taskAccessStrategy = taskAccessStrategy;
this.processMapper = processMapper;
this.taskListener = taskListener;
this.instanceMapper = instanceMapper;
this.hisInstanceMapper = hisInstanceMapper;
this.taskMapper = taskMapper;
this.taskActorMapper = taskActorMapper;
this.hisTaskMapper = hisTaskMapper;
this.hisTaskActorMapper = hisTaskActorMapper;
}
/**
* 更新当前执行节点信息
*
* @param flwTask 当前所在执行任务
*/
protected void updateCurrentNode(FlwTask flwTask) {
FlwInstance flwInstance = new FlwInstance();
flwInstance.setId(flwTask.getInstanceId());
flwInstance.setCurrentNode(flwTask.getTaskName());
flwInstance.setLastUpdateBy(flwTask.getCreateBy());
flwInstance.setLastUpdateTime(DateUtils.getCurrentDate());
instanceMapper.updateById(flwInstance);
FlwHisInstance flwHisInstance = new FlwHisInstance();
flwHisInstance.setId(flwInstance.getId());
flwHisInstance.setCurrentNode(flwInstance.getCurrentNode());
flwHisInstance.setLastUpdateBy(flwInstance.getLastUpdateBy());
flwHisInstance.setLastUpdateTime(flwInstance.getLastUpdateTime());
hisInstanceMapper.updateById(flwHisInstance);
}
/**
* 执行任务
*
* @param taskId 任务ID
* @param flowCreator 任务创建者
* @param args 执行参数
* @param taskState 任务状态
* @param eventType 执行事件
* @return {@link FlwTask}
*/
@Override
public FlwTask executeTask(Long taskId, FlowCreator flowCreator, Map<String, Object> args, TaskState taskState, EventType eventType) {
FlwTask flwTask = this.getAllowedFlwTask(taskId, flowCreator, args, taskState);
// 迁移任务至历史表
this.moveToHisTask(flwTask, taskState, flowCreator);
// 任务监听器通知
this.taskNotify(eventType, () -> flwTask, flowCreator);
return flwTask;
}
/**
* 执行节点跳转任务
*/
@Override
public boolean executeJumpTask(Long taskId, String nodeName, FlowCreator flowCreator, Function<FlwTask, Execution> executionFunction) {
FlwTask flwTask = this.getAllowedFlwTask(taskId, flowCreator, null, null);
// 执行跳转到目标节点
Execution execution = executionFunction.apply(flwTask);
ProcessModel processModel = execution.getProcessModel();
Assert.isNull(processModel, "当前任务未找到流程定义模型");
// 查找模型节点
NodeModel nodeModel;
if (null == nodeName) {
// 1,找到当前节点的父节点
nodeModel = processModel.getNode(flwTask.getTaskName()).getParentNode();
} else {
// 2,找到指定 nodeName 节点
nodeModel = processModel.getNode(nodeName);
}
Assert.isNull(nodeModel, "根据节点名称[" + nodeName + "]无法找到节点模型");
// 获取当前执行实例的所有正在执行的任务,强制终止执行并跳到指定节点
this.getTasksByInstanceId(flwTask.getInstanceId()).forEach(t -> this.moveToHisTask(t, TaskState.jump, flowCreator));
if (0 == nodeModel.getType()) {
// 发起节点,创建发起任务,分配发起人
FlwTask initiationTask = this.createTaskBase(nodeModel, execution);
initiationTask.setPerformType(PerformType.start);
Assert.isFalse(taskMapper.insert(initiationTask) > 0, "Failed to create initiation task");
taskActorMapper.insert(FlwTaskActor.ofFlwInstance(execution.getFlwInstance(), initiationTask.getId()));
} else {
// 其它节点创建
this.createTask(nodeModel, execution);
}
// 任务监听器通知
this.taskNotify(EventType.jump, () -> flwTask, flowCreator);
return true;
}
/**
* 获取执行任务并验证合法性
*
* @param taskId 任务ID
* @param flowCreator 任务创建者
* @param args 执行参数
* @param taskState {@link TaskState}
* @return 流程任务
*/
protected FlwTask getAllowedFlwTask(Long taskId, FlowCreator flowCreator, Map<String, Object> args, TaskState taskState) {
FlwTask flwTask = taskMapper.getCheckById(taskId);
if (null != args) {
flwTask.setVariable(args);
}
if (null == taskState || TaskState.allowedCheck(taskState)) {
Assert.isFalse(isAllowed(flwTask, flowCreator.getCreateId()), () -> "当前参与者 [" + flowCreator.getCreateBy() + "]不允许执行任务[taskId=" + taskId + "]");
}
return flwTask;
}
/**
* 迁移任务至历史表
*
* @param flwTask 执行任务
* @param taskState 任务状态
* @param flowCreator 任务创建者
* @return true 成功 false 失败
*/
protected boolean moveToHisTask(FlwTask flwTask, TaskState taskState, FlowCreator flowCreator) {
// 迁移 task 信息到 flw_his_task
FlwHisTask hisTask = FlwHisTask.of(flwTask);
hisTask.setTaskState(taskState);
hisTask.setFlowCreator(flowCreator);
hisTask.calculateDuration();
Assert.isFalse(hisTaskMapper.insert(hisTask) > 0, "Migration to FlwHisTask table failed");
// 迁移任务参与者
List<FlwTaskActor> taskActors = taskActorMapper.selectListByTaskId(flwTask.getId());
if (ObjectUtils.isNotEmpty(taskActors)) {
// 将 task 参与者信息迁移到 flw_his_task_actor
taskActors.forEach(t -> Assert.isFalse(hisTaskActorMapper.insert(FlwHisTaskActor.