All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.flowable.engine.service.impl.AbstractTenantFlowEngineServiceImpl Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package org.zodiac.flowable.engine.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.Process;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntityImpl;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.engine.task.Comment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zodiac.commons.util.Func;
import org.zodiac.commons.util.lang.Strings;
import org.zodiac.core.service.exception.ServiceException;
import org.zodiac.flowable.core.model.ProcessFlowModeEnum;
import org.zodiac.flowable.core.util.ProcessTaskUtil;
import org.zodiac.flowable.core.model.PlatformProcessFlow;
import org.zodiac.flowable.engine.constants.FlowEngineConstants;
import org.zodiac.flowable.engine.mapper.TenantFlowModelEntityMapper;
import org.zodiac.flowable.engine.model.FlowExecution;
import org.zodiac.flowable.engine.model.TenantFlowProcessModel;
import org.zodiac.flowable.engine.model.entity.TenantFlowModelEntity;
import org.zodiac.flowable.engine.service.TenantFlowEngineService;
import org.zodiac.flowable.engine.service.ProcessFlowStartUserSupplier;
import org.zodiac.flowable.engine.util.ProcessFlowCacheUtil;
import org.zodiac.flowable.engine.util.FlowCategoryNameSupplier;
import org.zodiac.mybatisplus.base.BaseEnhancedServiceImpl;
import org.zodiac.sdk.toolkit.io.FileObject;
import org.zodiac.sdk.toolkit.util.AssertUtil;
import org.zodiac.sdk.toolkit.util.DateTimeUtil;
import org.zodiac.sdk.toolkit.util.ExceptionUtil;
import org.zodiac.sdk.toolkit.util.collection.CollUtil;
import org.zodiac.sdk.toolkit.util.io.IOStreamUtil;
import org.zodiac.sdk.toolkit.util.lang.StrUtil;
import org.zodiac.security.SecurityAuthOperations;
import org.zodiac.tenant.model.entity.TenantUserEntity;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

/**
 * 工作流服务实现类。
 *
 */
public abstract class AbstractTenantFlowEngineServiceImpl, E extends TenantFlowModelEntity, PE extends TenantFlowProcessModel>
    extends BaseEnhancedServiceImpl implements TenantFlowEngineService {

    private static final String ALREADY_IN_STATE = "already in state";
    private static final BpmnJsonConverter BPMN_JSON_CONVERTER = new BpmnJsonConverter();
    private static final BpmnXMLConverter BPMN_XML_CONVERTER = new BpmnXMLConverter();

    protected Logger log = LoggerFactory.getLogger(getClass());

    private final ObjectMapper objectMapper;
    private final RepositoryService repositoryService;
    private final RuntimeService runtimeService;
    private final HistoryService historyService;
    private final TaskService taskService;

    private final SecurityAuthOperations securityAuthOperations;

    public AbstractTenantFlowEngineServiceImpl(ObjectMapper objectMapper, RepositoryService repositoryService,
        RuntimeService runtimeService, HistoryService historyService, TaskService taskService,
        SecurityAuthOperations securityAuthOperations) {
        this.objectMapper = objectMapper;
        this.repositoryService = repositoryService;
        this.runtimeService = runtimeService;
        this.historyService = historyService;
        this.taskService = taskService;
        this.securityAuthOperations = securityAuthOperations;
    }

    @Override
    public IPage selectFlowPage(IPage page, E flowModel) {
        return page.setRecords(baseMapper.selectFlowPage(page, flowModel));
    }

    @Override
    public IPage selectProcessPage(IPage page, String category, Integer mode,
        FlowCategoryNameSupplier flowCategoryNameSupplier) {
        ProcessDefinitionQuery processDefinitionQuery =
            repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionKey().asc();
        if (mode == ProcessFlowModeEnum.COMMON.getMode()) {
            /*通用流程。*/
            processDefinitionQuery.processDefinitionWithoutTenantId();
        } else if (!securityAuthOperations.isAdministrator()) {
            /*定制流程。*/
            processDefinitionQuery.processDefinitionTenantId(securityAuthOperations.getTenantId());
        }
        if (StrUtil.isNotEmpty(category)) {
            processDefinitionQuery.processDefinitionCategory(category);
        }
        List processDefinitionList = processDefinitionQuery
            .listPage(Func.toInt((page.getCurrent() - 1) * page.getSize()), Func.toInt(page.getSize()));
        List flowProcessList = CollUtil.list();
        processDefinitionList.forEach(processDefinition -> {
            String deploymentId = processDefinition.getDeploymentId();
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            PE flowProcess = obtainFlowProcessModel((ProcessDefinitionEntityImpl)processDefinition, flowCategoryNameSupplier);
            flowProcess.setDeploymentTime(deployment.getDeploymentTime());
            flowProcessList.add(flowProcess);
        });
        page.setTotal(processDefinitionQuery.count());
        page.setRecords(flowProcessList);
        return page;
    }

    @Override
    public IPage selectFollowPage(IPage page, String processInstanceId,
        String processDefinitionKey, ProcessFlowStartUserSupplier startUserSupplier, FlowCategoryNameSupplier flowCategoryNameSupplier) {
        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
        if (StrUtil.isNotBlank(processInstanceId)) {
            processInstanceQuery.processInstanceId(processInstanceId);
        }
        if (StrUtil.isNotBlank(processDefinitionKey)) {
            processInstanceQuery.processDefinitionKey(processDefinitionKey);
        }
        List flowList = CollUtil.list();
        List procInsList = processInstanceQuery
            .listPage(Func.toInt((page.getCurrent() - 1) * page.getSize()), Func.toInt(page.getSize()));
        procInsList.forEach(processInstance -> {
            ExecutionEntityImpl execution = (ExecutionEntityImpl)processInstance;
            FlowExecution flowExecution = new FlowExecution().setId(execution.getId()).setName(execution.getName())
                .setStartUserId(execution.getStartUserId());
            TenantUserEntity tenantUser = startUserSupplier.getStartUserByTaskUserId(execution.getStartUserId());
            if (tenantUser != null) {
                flowExecution.setStartUser(tenantUser.getName());
            }
            flowExecution.setStartTime(execution.getStartTime()).setExecutionId(execution.getId())
                .setProcessInstanceId(execution.getProcessInstanceId())
                .setProcessDefinitionId(execution.getProcessDefinitionId())
                .setProcessDefinitionKey(execution.getProcessDefinitionKey())
                .setSuspensionState(execution.getSuspensionState());
            ProcessDefinition processDefinition =
                ProcessFlowCacheUtil.getProcessDefinition(execution.getProcessDefinitionId());
            flowExecution.setCategory(processDefinition.getCategory()).setCategoryName(
                ProcessFlowCacheUtil.getCategoryName(processDefinition.getCategory(), flowCategoryNameSupplier));
            flowList.add(flowExecution);
        });
        page.setTotal(processInstanceQuery.count());
        page.setRecords(flowList);
        return page;
    }

    @Override
    public List historyFlowList(String processInstanceId, String startActivityId, String endActivityId,
        ProcessFlowStartUserSupplier startUserSupplier) {
        List flowList = CollUtil.linkedList();
        List historicActivityInstanceList =
            historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime().asc().orderByHistoricActivityInstanceEndTime().asc().list();
        boolean start = false;
        Map activityMap = CollUtil.map(16);
        for (int i = 0; i < historicActivityInstanceList.size(); i++) {
            HistoricActivityInstance historicActivityInstance = historicActivityInstanceList.get(i);
            /*过滤开始节点前的节点。*/
            if (StrUtil.isNotBlank(startActivityId)
                && startActivityId.equals(historicActivityInstance.getActivityId())) {
                start = true;
            }
            if (StrUtil.isNotBlank(startActivityId) && !start) {
                continue;
            }
            /*显示开始节点和结束节点,并且执行人不为空的任务。*/
            if (StrUtil.isNotBlank(historicActivityInstance.getAssignee())
                || FlowEngineConstants.START_EVENT.equals(historicActivityInstance.getActivityType())
                || FlowEngineConstants.END_EVENT.equals(historicActivityInstance.getActivityType())) {
                /*给节点增加序号。*/
                Integer activityNum = activityMap.get(historicActivityInstance.getActivityId());
                if (activityNum == null) {
                    activityMap.put(historicActivityInstance.getActivityId(), activityMap.size());
                }
                PlatformProcessFlow flow = new PlatformProcessFlow().setHistoryActivityId(historicActivityInstance.getActivityId())
                    .setHistoryActivityName(historicActivityInstance.getActivityName())
                    .setCreateTime(historicActivityInstance.getStartTime())
                    .setEndTime(historicActivityInstance.getEndTime());
                String durationTime =
                    DateTimeUtil.secondToTime(Func.toLong(historicActivityInstance.getDurationInMillis(), 0L) / 1000);
                flow.setHistoryActivityDurationTime(durationTime);
                /*获取流程发起人名称。*/
                if (FlowEngineConstants.START_EVENT.equals(historicActivityInstance.getActivityType())) {
                    List processInstanceList =
                        historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId)
                            .orderByProcessInstanceStartTime().asc().list();
                    if (processInstanceList.size() > 0) {
                        if (StrUtil.isNotBlank(processInstanceList.get(0).getStartUserId())) {
                             String taskUser = processInstanceList.get(0).getStartUserId();
                            // User user = UserCache.getUser(ProcessTaskUtil.getUserId(taskUser));
                            TenantUserEntity tenantUser = startUserSupplier.getStartUserByTaskUserId(
                                String.valueOf(ProcessTaskUtil.getUserId(taskUser)));
                            if (tenantUser != null) {
                                flow.setAssignee(historicActivityInstance.getAssignee());
                                flow.setAssigneeName(tenantUser.getName());
                            }
                        }
                    }
                }
                /*获取任务执行人名称。*/
                if (StrUtil.isNotBlank(historicActivityInstance.getAssignee())) {
                    // User user = UserCache.getUser(ProcessTaskUtil.getUserId(historicActivityInstance.getAssignee()));
                    TenantUserEntity tenantUser = startUserSupplier.getStartUserByTaskUserId(
                        String.valueOf(ProcessTaskUtil.getUserId(historicActivityInstance.getAssignee())));
                    if (tenantUser != null) {
                        flow.setAssignee(historicActivityInstance.getAssignee());
                        flow.setAssigneeName(tenantUser.getName());
                    }
                }
                /*获取意见评论内容。*/
                if (StrUtil.isNotBlank(historicActivityInstance.getTaskId())) {
                    List commentList = taskService.getTaskComments(historicActivityInstance.getTaskId());
                    if (commentList.size() > 0) {
                        flow.setComment(commentList.get(0).getFullMessage());
                    }
                }
                flowList.add(flow);
            }
            /*过滤结束节点后的节点。*/
            if (StrUtil.isNotBlank(endActivityId)
                && endActivityId.equals(historicActivityInstance.getActivityId())) {
                boolean temp = false;
                Integer activityNum = activityMap.get(historicActivityInstance.getActivityId());
                /*该活动节点,后续节点是否在结束节点之前,在后续节点中是否存在。*/
                for (int j = i + 1; j < historicActivityInstanceList.size(); j++) {
                    HistoricActivityInstance hi = historicActivityInstanceList.get(j);
                    Integer activityNumA = activityMap.get(hi.getActivityId());
                    boolean numberTemp = activityNumA != null && activityNumA < activityNum;
                    boolean equalsTemp =
                        StrUtil.equalsCharSeq(hi.getActivityId(), historicActivityInstance.getActivityId());
                    if (numberTemp || equalsTemp) {
                        temp = true;
                    }
                }
                if (!temp) {
                    break;
                }
            }
        }
        return flowList;
    }

    @Override
    public String changeState(String state, String processId) {
        try {
            if (state.equals(FlowEngineConstants.ACTIVE)) {
                repositoryService.activateProcessDefinitionById(processId, true, null);
                return StrUtil.format("激活ID为 [{}] 的流程成功", processId);
            } else if (state.equals(FlowEngineConstants.SUSPEND)) {
                repositoryService.suspendProcessDefinitionById(processId, true, null);
                return StrUtil.format("挂起ID为 [{}] 的流程成功", processId);
            } else {
                return "暂无流程变更";
            }
        } catch (Exception e) {
            if (e.getMessage().contains(ALREADY_IN_STATE)) {
                return StrUtil.format("ID为 [{}] 的流程已是此状态,无需操作", processId);
            }
            return e.getMessage();
        }
    }

    @Override
    public boolean deleteDeployment(String deploymentIds) {
        Func.toStrList(deploymentIds).forEach(deploymentId -> repositoryService.deleteDeployment(deploymentId, true));
        return true;
    }

    @Override
    public boolean deployUpload(List files, String category, List tenantIdList) {
        files.forEach(file -> {
//            try {
//                String fileName = file.getOriginalFilename();
//                InputStream fileInputStream = file.getInputStream();
//                byte[] bytes = FileUtil.copyToByteArray(fileInputStream);
//                if (Func.isNotEmpty(tenantIdList)) {
//                    tenantIdList.forEach(tenantId -> {
//                        Deployment deployment =
//                            repositoryService.createDeployment().addBytes(fileName, bytes).tenantId(tenantId).deploy();
//                        deploy(deployment, category);
//                    });
//                } else {
//                    Deployment deployment = repositoryService.createDeployment().addBytes(fileName, bytes).deploy();
//                    deploy(deployment, category);
//                }
//            } catch (IOException e) {
//                log.error(ExceptionUtil.stackTrace(e));
//            }
            try {
                String fileName = file.getOriginalFilename();
                InputStream fileInputStream = file.getInputStream();
                /*Replaced on 2024-02-18. START.*/
                //byte[] bytes = FileUtil.copyToByteArray(fileInputStream);
                byte[] bytes = IOStreamUtil.readToByteArray(fileInputStream);
                /*Replaced on 2024-02-18. END.*/
                if (Func.isNotEmpty(tenantIdList)) {
                    tenantIdList.forEach(tenantId -> {
                        Deployment deployment =
                            repositoryService.createDeployment().addBytes(fileName, bytes).tenantId(tenantId).deploy();
                        deploy(deployment, category);
                    });
                } else {
                    Deployment deployment = repositoryService.createDeployment().addBytes(fileName, bytes).deploy();
                    deploy(deployment, category);
                }
            } catch (IOException e) {
                log.error(ExceptionUtil.stackTrace(e));
            }
        });
        return true;
    }

    @Override
    public boolean deployModel(String modelId, String category, List tenantIdList) {
        E model = this.getById(modelId);
        if (model == null) {
            throw new ServiceException("No model found with the given id: " + modelId);
        }
        byte[] bytes = getBpmnXML(model);
        String processName = model.getName();
        if (!Strings.endsWithIgnoreCase(processName, FlowEngineConstants.SUFFIX)) {
            processName += FlowEngineConstants.SUFFIX;
        }
        String finalProcessName = processName;
        if (Func.isNotEmpty(tenantIdList)) {
            tenantIdList.forEach(tenantId -> {
                Deployment deployment = repositoryService.createDeployment().addBytes(finalProcessName, bytes)
                    .name(model.getName()).key(model.getModelKey()).tenantId(tenantId).deploy();
                deploy(deployment, category);
            });
        } else {
            Deployment deployment = repositoryService.createDeployment().addBytes(finalProcessName, bytes)
                .name(model.getName()).key(model.getModelKey()).deploy();
            deploy(deployment, category);
        }
        return true;
    }

    @Override
    public boolean deleteProcessInstance(String processInstanceId, String deleteReason) {
        runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
        return true;
    }

    private boolean deploy(Deployment deployment, String category) {
        log.debug("流程部署--------deploy:  " + deployment + "  分类---------->" + category);
        List list =
            repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
        StringBuilder logBuilder = new StringBuilder(500);
        List logArgs = CollUtil.list();
        /*设置流程分类。*/
        for (ProcessDefinition processDefinition : list) {
            if (StrUtil.isNotBlank(category)) {
                repositoryService.setProcessDefinitionCategory(processDefinition.getId(), category);
            }
            logBuilder.append("部署成功,流程ID={} \n");
            logArgs.add(processDefinition.getId());
        }
        if (list.size() == 0) {
            throw new ServiceException("部署失败,未找到流程");
        } else {
            log.info(logBuilder.toString(), logArgs.toArray());
            return true;
        }
    }

    private byte[] getBpmnXML(E model) {
        BpmnModel bpmnModel = getBpmnModel(model);
        return getBpmnXML(bpmnModel);
    }

    private byte[] getBpmnXML(BpmnModel bpmnModel) {
        for (Process process : bpmnModel.getProcesses()) {
            if (StrUtil.isNotEmpty(process.getId())) {
                char firstCharacter = process.getId().charAt(0);
                if (Character.isDigit(firstCharacter)) {
                    process.setId("a" + process.getId());
                }
            }
        }
        return BPMN_XML_CONVERTER.convertToXML(bpmnModel);
    }

    private BpmnModel getBpmnModel(E model) {
        BpmnModel bpmnModel;
        try {
            Map formMap = CollUtil.map(16);
            Map decisionTableMap = CollUtil.map(16);

            List referencedModels = baseMapper.findByParentModelId(model.getId());
            for (E childModel : referencedModels) {
                if (TenantFlowModelEntity.MODEL_TYPE_FORM == childModel.getModelType()) {
                    formMap.put(childModel.getId(), childModel);

                } else if (TenantFlowModelEntity.MODEL_TYPE_DECISION_TABLE == childModel.getModelType()) {
                    decisionTableMap.put(childModel.getId(), childModel);
                }
            }
            bpmnModel = getBpmnModel(model, formMap, decisionTableMap);
        } catch (Exception e) {
            log.error("Could not generate BPMN 2.0 model for {}", model.getId(), e);
            throw new ServiceException("Could not generate BPMN 2.0 model");
        }
        return bpmnModel;
    }

    private BpmnModel getBpmnModel(E model, Map formMap,
        Map decisionTableMap) {
        try {
            ObjectNode editorJsonNode = (ObjectNode)objectMapper.readTree(model.getModelEditorJson());
            Map formKeyMap = CollUtil.map(16);
            for (E formModel : formMap.values()) {
                formKeyMap.put(formModel.getId(), formModel.getModelKey());
            }
            Map decisionTableKeyMap = CollUtil.map(16);
            for (E decisionTableModel : decisionTableMap.values()) {
                decisionTableKeyMap.put(decisionTableModel.getId(), decisionTableModel.getModelKey());
            }
            return BPMN_JSON_CONVERTER.convertToBpmnModel(editorJsonNode, formKeyMap, decisionTableKeyMap);
        } catch (Exception e) {
            log.error("Could not generate BPMN 2.0 model for {}", model.getId(), e);
            throw new ServiceException("Could not generate BPMN 2.0 model");
        }
    }

    protected abstract PE obtainFlowProcessModel(ProcessDefinitionEntity entity, FlowCategoryNameSupplier flowCategoryNameSupplier);
}