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

com.opendynamic.ff.service.impl.oracle.FfServiceImpl Maven / Gradle / Ivy

package com.opendynamic.ff.service.impl.oracle;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.imageio.ImageIO;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
import com.opendynamic.OdUtils;
import com.opendynamic.ff.FfOperation;
import com.opendynamic.ff.handler.NodeHandler;
import com.opendynamic.ff.query.ChildNodeQuery;
import com.opendynamic.ff.query.DelegateQuery;
import com.opendynamic.ff.query.InvolvedProcQuery;
import com.opendynamic.ff.query.NodeQuery;
import com.opendynamic.ff.query.NodeVarQuery;
import com.opendynamic.ff.query.OperationQuery;
import com.opendynamic.ff.query.ParentNodeQuery;
import com.opendynamic.ff.query.ProcQuery;
import com.opendynamic.ff.query.TaskQuery;
import com.opendynamic.ff.service.FfAdjustProcDefService;
import com.opendynamic.ff.service.FfDelegateService;
import com.opendynamic.ff.service.FfHelper;
import com.opendynamic.ff.service.FfNodeService;
import com.opendynamic.ff.service.FfNodeVarService;
import com.opendynamic.ff.service.FfOperationService;
import com.opendynamic.ff.service.FfProcDefService;
import com.opendynamic.ff.service.FfProcService;
import com.opendynamic.ff.service.FfService;
import com.opendynamic.ff.service.FfTaskService;
import com.opendynamic.ff.vo.CandidateList;
import com.opendynamic.ff.vo.Delegate;
import com.opendynamic.ff.vo.DiamondShape;
import com.opendynamic.ff.vo.FfResult;
import com.opendynamic.ff.vo.FfUser;
import com.opendynamic.ff.vo.FlowDef;
import com.opendynamic.ff.vo.LineShape;
import com.opendynamic.ff.vo.Node;
import com.opendynamic.ff.vo.NodeDef;
import com.opendynamic.ff.vo.NodeOp;
import com.opendynamic.ff.vo.NodeVar;
import com.opendynamic.ff.vo.NodeVarOp;
import com.opendynamic.ff.vo.NoteDef;
import com.opendynamic.ff.vo.Operation;
import com.opendynamic.ff.vo.OvalShape;
import com.opendynamic.ff.vo.Proc;
import com.opendynamic.ff.vo.ProcDef;
import com.opendynamic.ff.vo.ProcOp;
import com.opendynamic.ff.vo.ProcVarDef;
import com.opendynamic.ff.vo.RectangleShape;
import com.opendynamic.ff.vo.RunningNodeDef;
import com.opendynamic.ff.vo.RunningProcDef;
import com.opendynamic.ff.vo.Shape;
import com.opendynamic.ff.vo.Task;
import com.opendynamic.ff.vo.TaskOp;

import de.odysseus.el.ExpressionFactoryImpl;
import de.odysseus.el.util.SimpleContext;
import sun.misc.BASE64Encoder;

@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class FfServiceImpl implements FfService, ApplicationContextAware {
    private ApplicationContext applicationContext;

    private static List procDefList;
    private static Queue adjustProcDefList = new LinkedList<>();
    private static Map nodeHandlerMap;
    private static Map internalServiceMap;
    private static Map externalServiceMap;

    @Autowired
    private FfProcDefService ffProcDefService;
    @Autowired
    private FfAdjustProcDefService ffAdjustProcDefService;
    @Autowired
    private FfProcService ffProcService;
    @Autowired
    private FfNodeService ffNodeService;
    @Autowired
    private FfTaskService ffTaskService;
    @Autowired
    private FfNodeVarService ffNodeVarService;
    @Autowired
    private FfDelegateService ffDelegateService;
    @Autowired
    private FfOperationService ffOperationService;
    @Autowired
    private FfHelper ffHelper;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @PostConstruct
    @Override
    public boolean refreshProcDefCache() {
        System.out.println("Initializing workflow definition...");

        List> procDefList = ffProcDefService.selectProcDef(null, null, null, null, null, null, null, null, null, null, null, null, 1, -1);
        List latestProcDefList = new ArrayList<>(procDefList.size());
        for (Map procDef : procDefList) {
            latestProcDefList.add(new ProcDef(procDef));
        }
        FfServiceImpl.procDefList = latestProcDefList;

        return true;
    }

    @PostConstruct
    private void initNodeHandler() {
        System.out.println("Initializing node handler...");

        FfServiceImpl.nodeHandlerMap = new HashMap<>();
        Map nodeHandlerMap = applicationContext.getBeansOfType(NodeHandler.class);// 装配节点处理器
        for (Map.Entry entry : nodeHandlerMap.entrySet()) {
            FfServiceImpl.nodeHandlerMap.put(entry.getValue().getNodeType(), entry.getValue());
        }
    }

    @Override
    public NodeHandler getNodeHandler(String nodeType) {
        return nodeHandlerMap.get(nodeType);
    }

    @PostConstruct
    private void initJuel() {
        internalServiceMap = new HashMap<>();
        externalServiceMap = new HashMap<>();

        internalServiceMap.put("ffService", this);
        internalServiceMap.put("ffProcDefService", ffProcDefService);// 装配默认的service bean
        internalServiceMap.put("ffProcService", ffProcService);
        internalServiceMap.put("ffNodeService", ffNodeService);
        internalServiceMap.put("ffTaskService", ffTaskService);
        internalServiceMap.put("ffNodeVarService", ffNodeVarService);
        internalServiceMap.put("ffDelegateService", ffDelegateService);
        internalServiceMap.put("ffOperationService", ffOperationService);

        internalServiceMap = Collections.unmodifiableMap(internalServiceMap);
    }

    @Override
    public Map getInternalServiceMap() {
        return FfServiceImpl.internalServiceMap;
    }

    @Override
    public Map getExternalServiceMap() {
        return FfServiceImpl.externalServiceMap;
    }

    @Override
    public void addExternalService(String serviceName, Object service) {
        FfServiceImpl.externalServiceMap.put(serviceName, service);
    }

    @Override
    public ProcDef loadProcDef(String procDefId) {
        for (ProcDef procDef : procDefList) {// 在流程定义缓存中查找
            if (procDef.getProcDefId().equals(procDefId)) {
                return procDef;
            }
        }
        for (ProcDef procDef : adjustProcDefList) {// 在调整流程定义缓存中查找
            if (procDef.getProcDefId().equals(procDefId)) {
                return procDef;
            }
        }
        // 在数据库中查找调整流程定义,如找到返回并加入到缓存中,缓存不超过200条,先进先出。
        Map adjustProcDef = ffAdjustProcDefService.loadAdjustProcDef(procDefId);
        if (adjustProcDef != null) {
            ProcDef procDef = new ProcDef(adjustProcDef);
            adjustProcDefList.offer(procDef);
            if (adjustProcDefList.size() > 200) {
                adjustProcDefList.poll();
            }
            return procDef;
        }

        throw new RuntimeException("errors.procDefNotFound");
    }

    @Override
    public ProcDef loadProcDefByCode(String procDefCode) {
        for (ProcDef procDef : procDefList) {
            if (procDef.getProcDefCode().equals(procDefCode) && procDef.getProcDefStatus().equals("1")) {
                return procDef;
            }
        }

        throw new RuntimeException("errors.procDefNotFound");
    }

    @Override
    public InputStream loadProcDefDiagramFile(String procDefId) {
        return new ByteArrayInputStream(loadProcDef(procDefId).getProcDefDiagramFile());
    }

    @Override
    public List selectProcDef(String procDefId, String procDefCode, String procDefName, String procDefCat, List procDefStatusList, Integer page, Integer limit) {
        List subProcDefList = selectProcDef(procDefId, procDefCode, procDefName, procDefCat, procDefStatusList);

        if (page != null && limit != null && limit > 0) {// 分页
            int start = (page - 1) * limit;
            int end = page * limit;
            if (end > subProcDefList.size()) {
                end = subProcDefList.size();
            }
            subProcDefList = subProcDefList.subList(start, end);
        }

        return subProcDefList;
    }

    @Override
    public int countProcDef(String procDefId, String procDefCode, String procDefName, String procDefCat, List procDefStatusList) {
        return selectProcDef(procDefId, procDefCode, procDefName, procDefCat, procDefStatusList).size();
    }

    private List selectProcDef(String procDefId, String procDefCode, String procDefName, String procDefCat, List procDefStatusList) {
        if (StringUtils.isEmpty(procDefId) && StringUtils.isEmpty(procDefCode) && StringUtils.isEmpty(procDefName) && StringUtils.isEmpty(procDefCat) && (procDefStatusList == null || procDefStatusList.size() == 0)) {
            return procDefList;
        }

        List subProcDefList = new ArrayList<>();
        subProcDefList.addAll(procDefList);
        ProcDef procDef;
        if (StringUtils.isNotEmpty(procDefId)) {
            for (int i = subProcDefList.size() - 1; i >= 0; i--) {
                procDef = subProcDefList.get(i);
                if (!procDefId.equals(procDef.getProcDefId())) {
                    subProcDefList.remove(procDef);
                }
            }
        }
        if (StringUtils.isNotEmpty(procDefCode)) {
            for (int i = subProcDefList.size() - 1; i >= 0; i--) {
                procDef = subProcDefList.get(i);
                if (!procDefCode.equals(procDef.getProcDefCode())) {
                    subProcDefList.remove(procDef);
                }
            }
        }
        if (StringUtils.isNotEmpty(procDefName)) {
            for (int i = subProcDefList.size() - 1; i >= 0; i--) {
                procDef = subProcDefList.get(i);
                if (!procDef.getProcDefName().contains(procDefName)) {
                    subProcDefList.remove(procDef);
                }
            }
        }
        if (StringUtils.isNotEmpty(procDefCat)) {
            for (int i = subProcDefList.size() - 1; i >= 0; i--) {
                procDef = subProcDefList.get(i);
                if (!procDef.getProcDefCat().startsWith(procDefCat)) {
                    subProcDefList.remove(procDef);
                }
            }
        }
        if (procDefStatusList != null && procDefStatusList.size() > 0) {
            for (int i = subProcDefList.size() - 1; i >= 0; i--) {
                procDef = subProcDefList.get(i);
                if (!procDefStatusList.contains(procDef.getProcDefStatus())) {
                    subProcDefList.remove(procDef);
                }
            }
        }

        return subProcDefList;
    }

    @Override
    public boolean deployProcDef(String procDefId, String procDef, InputStream procDefDiagramFile, String procDefDiagramFileName, Integer procDefDiagramFileLength, String operatorId, String operatorName) {
        RuntimeTypeAdapterFactory runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class, "type");
        runtimeTypeAdapterFactory.registerSubtype(RectangleShape.class, "rectangle");
        runtimeTypeAdapterFactory.registerSubtype(OvalShape.class, "oval");
        runtimeTypeAdapterFactory.registerSubtype(DiamondShape.class, "diamond");
        runtimeTypeAdapterFactory.registerSubtype(LineShape.class, "line");
        Gson gson = new GsonBuilder().registerTypeAdapterFactory(runtimeTypeAdapterFactory).create();

        ProcDef _procDef = gson.fromJson(procDef, ProcDef.class);

        if (procDefDiagramFile == null || procDefDiagramFileLength == null || procDefDiagramFileLength == 0) {// 根据定义生成流程图
            _procDef.init();

            BufferedImage image = new BufferedImage(_procDef.getProcDefDiagramWidth(), _procDef.getProcDefDiagramHeight(), BufferedImage.TYPE_INT_ARGB); // 创建BufferedImage对象
            Graphics2D g2d = image.createGraphics(); // 获取Graphics2D
            g2d.setComposite(AlphaComposite.Clear);// 绘制透明背景
            g2d.fillRect(0, 0, _procDef.getProcDefDiagramWidth(), _procDef.getProcDefDiagramHeight());
            g2d.setComposite(AlphaComposite.Src);// 准备绘制其它内容,非透明
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 抗锯齿

            for (NodeDef nodeDef : _procDef.getNodeDefList()) {
                nodeDef.getShape().draw(g2d, nodeDef.getNodeName());
            }
            for (FlowDef flowDef : _procDef.getFlowDefList()) {
                flowDef.getShape().draw(g2d, flowDef.getFlowName());
            }
            for (NoteDef noteDef : _procDef.getNoteDefList()) {
                if (noteDef.getDynamic().equals(FfService.BOOLEAN_FALSE)) {
                    noteDef.getShape().draw(g2d, noteDef.getNoteName());
                }
            }

            g2d.dispose(); // 释放对象

            image = OdUtils.applyShadow(image, 1, Color.BLACK, 0.2f);// 添加阴影

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                ImageIO.write(image, "png", baos);
            }
            catch (IOException e) {
                throw new RuntimeException(e);
            }
            procDefDiagramFile = new ByteArrayInputStream(baos.toByteArray());
            procDefDiagramFileName = "procDef.png";
            procDefDiagramFileLength = baos.size();
        }

        ffProcDefService.insertProcDef(procDefId, _procDef.getProcDefCode(), _procDef.getProcDefName(), _procDef.getProcDefCat(), procDef, procDefDiagramFile, procDefDiagramFileName, procDefDiagramFileLength, _procDef.getProcDefDiagramWidth(), _procDef.getProcDefDiagramHeight(), _procDef.getMemo(), FfService.PROC_DEF_STATUS_ACTIVE, new Date(), new Date(), operatorId, operatorName);

        refreshProcDefCache();

        return true;
    }

    @Override
    public boolean updateProcDefDiagramFile(String procDefId, InputStream procDefDiagramFile, String procDefDiagramFileName, Integer procDefDiagramFileLength, Integer procDefDiagramWidth, Integer procDefDiagramHeight, String operatorId, String operatorName) {
        if (ffProcDefService.updateProcDefDiagramFile(procDefId, procDefDiagramFile, procDefDiagramFileName, procDefDiagramFileLength, procDefDiagramWidth, procDefDiagramHeight, new Date(), operatorId, operatorName) == 1) {
            refreshProcDefCache();
            return true;
        }

        return false;
    }

    @Override
    public boolean disableProcDef(String procDefId, String operatorId, String operatorName) {
        if (ffProcDefService.disableProcDef(procDefId, new Date(), operatorId, operatorName) == 1) {
            refreshProcDefCache();
            return true;
        }

        return false;
    }

    @Override
    public boolean enableProcDef(String procDefId, String operatorId, String operatorName) {
        if (ffProcDefService.enableProcDef(procDefId, new Date(), operatorId, operatorName) == 1) {
            refreshProcDefCache();
            return true;
        }

        return false;
    }

    @Override
    public boolean deleteProcDef(String procDefId, String operatorId, String operatorName) {
        if (ffProcDefService.deleteProcDef(procDefId, new Date(), operatorId, operatorName) == 1) {
            refreshProcDefCache();
            return true;
        }

        return false;
    }

    @Override
    @FfOperation(nodeId = "${branchId}", operator = "${operatorId}")
    public FfResult adjustBranchProcDef(String branchId, String procDef, InputStream procDefDiagramFile, String procDefDiagramFileName, Integer procDefDiagramFileLength, String operatorId, String operatorName) {
        FfResult ffResult = new FfResult();

        Node branch = loadNode(branchId);
        String adjustSubProcDefId = branch.getAdjustSubProcDefId();

        if (StringUtils.isEmpty(procDef)) {
            if (adjustSubProcDefId != null) {
                ffNodeService.updateBranchAdjustSubProcDefId(branchId, null);
                ffAdjustProcDefService.deleteAdjustProcDef(adjustSubProcDefId, new Date(), operatorId, operatorName);
                return ffResult;
            }
            else {
                throw new RuntimeException("errors.procDefIsRequired");
            }
        }

        RuntimeTypeAdapterFactory runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class, "type");
        runtimeTypeAdapterFactory.registerSubtype(RectangleShape.class, "rectangle");
        runtimeTypeAdapterFactory.registerSubtype(OvalShape.class, "oval");
        runtimeTypeAdapterFactory.registerSubtype(DiamondShape.class, "diamond");
        runtimeTypeAdapterFactory.registerSubtype(LineShape.class, "line");
        Gson gson = new GsonBuilder().registerTypeAdapterFactory(runtimeTypeAdapterFactory).create();

        ProcDef _procDef = gson.fromJson(procDef, ProcDef.class);

        if (procDefDiagramFile == null || procDefDiagramFileLength == null || procDefDiagramFileLength == 0) {// 根据定义生成流程图
            _procDef.init();

            BufferedImage image = new BufferedImage(_procDef.getProcDefDiagramWidth(), _procDef.getProcDefDiagramHeight(), BufferedImage.TYPE_INT_ARGB); // 创建BufferedImage对象
            Graphics2D g2d = image.createGraphics(); // 获取Graphics2D
            g2d.setComposite(AlphaComposite.Clear);// 绘制透明背景
            g2d.fillRect(0, 0, _procDef.getProcDefDiagramWidth(), _procDef.getProcDefDiagramHeight());
            g2d.setComposite(AlphaComposite.Src);// 准备绘制其它内容,非透明
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 抗锯齿

            for (NodeDef nodeDef : _procDef.getNodeDefList()) {
                nodeDef.getShape().draw(g2d, nodeDef.getNodeName());
            }
            for (FlowDef flowDef : _procDef.getFlowDefList()) {
                flowDef.getShape().draw(g2d, flowDef.getFlowName());
            }
            for (NoteDef noteDef : _procDef.getNoteDefList()) {
                if (noteDef.getDynamic().equals(FfService.BOOLEAN_FALSE)) {
                    noteDef.getShape().draw(g2d, noteDef.getNoteName());
                }
            }

            g2d.dispose(); // 释放对象

            image = OdUtils.applyShadow(image, 1, Color.BLACK, 0.2f);// 添加阴影

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                ImageIO.write(image, "png", baos);
            }
            catch (IOException e) {
                throw new RuntimeException(e);
            }
            procDefDiagramFile = new ByteArrayInputStream(baos.toByteArray());
            procDefDiagramFileName = "procDef.png";
            procDefDiagramFileLength = baos.size();
        }

        if (adjustSubProcDefId == null) {
            adjustSubProcDefId = OdUtils.getUuid();
            ffAdjustProcDefService.insertAdjustProcDef(adjustSubProcDefId, branch.getSubProcDefId(), procDef, procDefDiagramFile, procDefDiagramFileName, procDefDiagramFileLength, _procDef.getProcDefDiagramWidth(), _procDef.getProcDefDiagramHeight(), new Date(), new Date(), operatorId, operatorName);
            ffNodeService.updateBranchAdjustSubProcDefId(branchId, adjustSubProcDefId);
        }
        else {
            ffAdjustProcDefService.updateAdjustProcDef(adjustSubProcDefId, procDef, procDefDiagramFile, procDefDiagramFileName, procDefDiagramFileLength, _procDef.getProcDefDiagramWidth(), _procDef.getProcDefDiagramHeight(), new Date(), operatorId, operatorName);
        }

        return ffResult;
    }

    @Override
    public boolean deleteAdjustProcDef(String adjustProcDefId, Date updateDate, String operatorId, String operatorName) {
        if (ffAdjustProcDefService.deleteAdjustProcDef(adjustProcDefId, updateDate, operatorId, operatorName) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public ProcDef getNodeProcDef(Node node) {
        if (node.getAdjustSubProcDefId() == null) {
            return loadProcDef(node.getSubProcDefId());
        }
        else {
            return loadProcDef(node.getAdjustSubProcDefId());
        }
    }

    @Override
    public List getStartRunningNodeDefList(String subProcPath, ProcDef procDef, Map nodeVarMap) {
        return getNextRunningNodeDefList(subProcPath, null, null, procDef, nodeVarMap, nodeVarMap);
    }

    @Override
    public List getNextRunningNodeDefList(String taskId, Map nodeVarMap) {
        List nextRunningNodeDefList = new ArrayList<>();

        Task task = loadTask(taskId);
        if (task.getTaskType().equals(FfService.TASK_TYPE_FORWARD_TASK)) {
            return nextRunningNodeDefList;
        }

        Node node = loadNode(task.getNodeId());
        Map fullNodeVarMap = new HashMap<>();
        for (Map.Entry entry : internalServiceMap.entrySet()) {// 添加内部服务
            fullNodeVarMap.put(entry.getKey(), entry.getValue());
        }
        for (Map.Entry entry : externalServiceMap.entrySet()) {// 添加外部服务
            fullNodeVarMap.put(entry.getKey(), entry.getValue());
        }
        fullNodeVarMap.put("proc", loadProc(node.getProcId()));
        fullNodeVarMap.put("branch", loadNode(node.getParentNodeId()));
        fullNodeVarMap.put("node", node);
        fullNodeVarMap.putAll(createNodeVarQuery().setNodeId(node.getParentNodeId()).setRecursive(true).queryForMap());
        if (nodeVarMap != null) {
            fullNodeVarMap.putAll(nodeVarMap);
        }
        NodeDef nodeDef = getNodeProcDef(node).getNodeDef((node.getNodeCode()));// 获取当前节点所属节点定义
        nextRunningNodeDefList.addAll(getNextRunningNodeDefList(getSubProcPath(node), node, nodeDef, null, fullNodeVarMap, nodeVarMap));

        return nextRunningNodeDefList;
    }

    private List getNextRunningNodeDefList(String subProcPath, Node node, NodeDef nodeDef, ProcDef procDef, Map fullNodeVarMap, Map nodeVarMap) {
        List nextRunningNodeDefList = new ArrayList<>();

        List nextNodeDefList;
        if (nodeDef == null) {// 主流程取开始节点定义
            nextNodeDefList = procDef.getStartNodeDefList();
        }
        else {
            nextNodeDefList = nodeDef.getNextNodeDefList(fullNodeVarMap);// 查找下一个节点定义
        }

        if (nextNodeDefList.size() > 0) {// 如果有下一个节点定义,添加RunningNodeDef
            for (NodeDef nextNodeDef : nextNodeDefList) {
                nextRunningNodeDefList.addAll(getRunningNodeDef(subProcPath, nextNodeDef, fullNodeVarMap));
            }
        }
        else {// 如果没有下一个节点定义
            String completeReturn = node.getCompleteReturn();
            if (completeReturn != null && completeReturn.indexOf("${") != -1) {// JUEL解析
                nodeVarMap.putAll(ffNodeService.getTaskStatistic(node.getNodeId()));// 获取节点任务完成信息

                // 设置JUEL解析环境
                ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
                SimpleContext simpleContext = new SimpleContext();
                for (Map.Entry entry : nodeVarMap.entrySet()) {
                    simpleContext.setVariable(entry.getKey(), expressionFactory.createValueExpression(entry.getValue(), Object.class));
                }
                // JUEL解析
                ValueExpression expression = expressionFactory.createValueExpression(simpleContext, completeReturn, String.class);
                completeReturn = (String) expression.getValue(simpleContext);
            }

            if (FfService.BOOLEAN_TRUE.equals(completeReturn)) {// 完成返回节点,获取其前一个节点
                Node previousNode = loadNode(node.getPreviousNodeIds());// 获取前一个节点。
                NodeDef previousNodeDef = getNodeProcDef(previousNode).getNodeDef((previousNode.getNodeCode()));// 获取当前节点所属节点定义

                // 计算激活的办理人,为上一次该节点任务的办理人。
                List taskList = createTaskQuery().setNodeId(previousNode.getNodeId()).queryForObjectList();
                List assigneeList = new ArrayList<>();
                for (Task task : taskList) {
                    assigneeList.add(task.getAssignee());
                }
                RunningNodeDef runningNodeDef = new RunningNodeDef(previousNodeDef, null);
                runningNodeDef.setSubProcPath(subProcPath);
                runningNodeDef.setAssigneeList(getAssigneeList(StringUtils.join(assigneeList, ",")));
                nextRunningNodeDefList.add(runningNodeDef);
            }
            else {// 非完成返回节点,继续处理其上一级节点。
                Node parentTaskNode = getParentTaskNode(node);
                if (parentTaskNode != null) {
                    fullNodeVarMap.put("proc", loadProc(parentTaskNode.getProcId()));
                    fullNodeVarMap.put("branch", loadNode(parentTaskNode.getParentNodeId()));
                    fullNodeVarMap.put("node", parentTaskNode);
                    fullNodeVarMap.putAll(createNodeVarQuery().setNodeId(parentTaskNode.getParentNodeId()).setRecursive(true).queryForMap());
                    if (nodeVarMap != null) {
                        fullNodeVarMap.putAll(nodeVarMap);
                    }
                    NodeDef parentTaskNodeDef = getNodeProcDef(parentTaskNode).getNodeDef((parentTaskNode.getNodeCode()));// 获取当前节点所属节点定义
                    if (parentTaskNodeDef.getNodeType().equals(FfService.NODE_TYPE_SUB_PROC)) { // 上级节点类型为子流程时,计算子流程路径
                        if (StringUtils.isNotEmpty(subProcPath)) {
                            String[] splits = subProcPath.split("\\.");
                            subProcPath = StringUtils.join(splits, ".", 0, splits.length - 1);
                        }
                    }
                    nextRunningNodeDefList.addAll(getNextRunningNodeDefList(subProcPath, parentTaskNode, parentTaskNodeDef, procDef, fullNodeVarMap, nodeVarMap));
                }
            }
        }

        return nextRunningNodeDefList;
    }

    private Node getParentTaskNode(Node node) {
        if (node.getParentNodeId() == null) {
            return null;
        }

        Node parentNode = loadNode(node.getParentNodeId());
        if (parentNode.getNodeType().equals(FfService.NODE_TYPE_STAGE) || parentNode.getNodeType().equals(FfService.NODE_TYPE_SUB_PROC)) {
            return parentNode;
        }
        else {
            return getParentTaskNode(parentNode);
        }
    }

    @SuppressWarnings("unchecked")
    private List getRunningNodeDef(String subProcPath, NodeDef nodeDef, Map nodeVarMap) {
        List runningNodeDefList = new ArrayList<>();

        // 设置JUEL解析环境
        HashMap allNodeVarMap = new HashMap<>();
        allNodeVarMap.putAll(getInternalServiceMap());
        allNodeVarMap.putAll(getExternalServiceMap());
        if (nodeVarMap != null) {
            allNodeVarMap.putAll(nodeVarMap);
        }
        ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
        SimpleContext simpleContext = new SimpleContext();
        for (Map.Entry entry : allNodeVarMap.entrySet()) {
            simpleContext.setVariable(entry.getKey(), expressionFactory.createValueExpression(entry.getValue(), Object.class));
        }
        // JUEL解析
        // Stage取其内部的开始节点定义
        if (nodeDef.getNodeType().equals(FfService.NODE_TYPE_STAGE)) {
            List nextNodeDefList = nodeDef.getStartChildNodeDefList();
            for (NodeDef nextNodeDef : nextNodeDefList) {
                runningNodeDefList.addAll(getRunningNodeDef(subProcPath, nextNodeDef, nodeVarMap));
            }
        }
        // GATEWAY取其下一个节点定义
        if (nodeDef.getNodeType().equals(FfService.NODE_TYPE_GATEWAY)) {
            List nextNodeDefList = nodeDef.getNextNodeDefList(allNodeVarMap);// 查找下一个节点定义
            for (NodeDef nextNodeDef : nextNodeDefList) {
                runningNodeDefList.addAll(getRunningNodeDef(subProcPath, nextNodeDef, nodeVarMap));
            }
        }
        // TASK,CENTER_FORWARD_TASK候选人解析
        if ((nodeDef.getNodeType().equals(FfService.NODE_TYPE_TASK) || nodeDef.getNodeType().equals(FfService.NODE_TYPE_CENTER_FORWARD_TASK)) && StringUtils.isNotEmpty(nodeDef.getCandidateAssignee())) {
            ValueExpression expression = expressionFactory.createValueExpression(simpleContext, nodeDef.getCandidateAssignee(), Object.class);
            Object object = expression.getValue(simpleContext);// 获取候选人
            List candidateAssigneeList;// 解析后候选人列表
            if (object instanceof List) {
                candidateAssigneeList = (List) object;
            }
            else {
                candidateAssigneeList = new ArrayList<>();
                if (StringUtils.isNotEmpty((String) object)) {
                    String[] assignees = ((String) object).split(",");
                    for (int i = 0; i < assignees.length; i++) {
                        FfUser ffUser = new FfUser();
                        ffUser.setId(assignees[i]);
                        ffUser.setUserName(ffHelper.getUserName(assignees[i]));
                        candidateAssigneeList.add(ffUser);
                    }
                }
            }

            RunningNodeDef runningNodeDef = new RunningNodeDef(nodeDef, null);
            runningNodeDef.setSubProcPath(subProcPath);
            runningNodeDef.setCandidateAssigneeList(candidateAssigneeList);
            runningNodeDefList.add(runningNodeDef);
        }
        // SUB_PROC候选子流程定义解析
        if ((nodeDef.getNodeType().equals(FfService.NODE_TYPE_SUB_PROC) || nodeDef.getNodeType().equals(FfService.NODE_TYPE_ISOLATE_SUB_PROC)) && StringUtils.isNotEmpty(nodeDef.getCandidateSubProcDef())) {
            ValueExpression expression = expressionFactory.createValueExpression(simpleContext, nodeDef.getCandidateSubProcDef(), Object.class);
            Object object = expression.getValue(simpleContext);// 获取候选子流程定义
            List candidateSubProcDefList = new ArrayList<>();// 解析后候选子流程定义列表
            if (object instanceof List) {
                List procDefList = (List) object;
                for (ProcDef procDef : procDefList) {
                    candidateSubProcDefList.add(new RunningProcDef(procDef));
                }
            }
            else {
                if (StringUtils.isNotEmpty((String) object)) {
                    String[] assignSubProcDefs = ((String) object).split(",");
                    for (int i = 0; i < assignSubProcDefs.length; i++) {
                        RunningProcDef runningProcDef = new RunningProcDef(loadProcDefByCode(assignSubProcDefs[i]));
                        candidateSubProcDefList.add(runningProcDef);
                    }
                }
            }

            // 递归处理内部子流程定义起始节点定义列表
            for (RunningProcDef runningProcDef : candidateSubProcDefList) {
                Map subProcAllNodeVarMap = new HashMap<>();
                subProcAllNodeVarMap.putAll(allNodeVarMap);
                subProcAllNodeVarMap.putAll(runningProcDef.getProcVarDefMap());
                List startRunningNodeDefList = getStartRunningNodeDefList(StringUtils.isNotEmpty(subProcPath) ? subProcPath + "." + nodeDef.getNodeCode() + ":" + runningProcDef.getProcDefCode() : nodeDef.getNodeCode() + ":" + runningProcDef.getProcDefCode(), runningProcDef, subProcAllNodeVarMap);
                runningProcDef.setNextRunningNodeDefList(startRunningNodeDefList);
            }

            RunningNodeDef runningNodeDef = new RunningNodeDef(nodeDef, null);
            runningNodeDef.setSubProcPath(subProcPath);
            runningNodeDef.setCandidateSubProcDefList(candidateSubProcDefList);
            runningNodeDefList.add(runningNodeDef);
        }
        // TASK,CENTER_FORWARD_TASK办理人解析
        if ((nodeDef.getNodeType().equals(FfService.NODE_TYPE_TASK) || nodeDef.getNodeType().equals(FfService.NODE_TYPE_CENTER_FORWARD_TASK)) && StringUtils.isNotEmpty(nodeDef.getAssignee())) {
            ValueExpression expression = expressionFactory.createValueExpression(simpleContext, nodeDef.getAssignee(), Object.class);
            Object object;
            try {
                object = expression.getValue(simpleContext);
            }
            catch (Exception e) {
                object = (String) null;
            }
            List assigneeList;// 解析后办理人列表
            if (object instanceof List) {
                assigneeList = (List) object;
            }
            else {
                assigneeList = getAssigneeList((String) object);
            }

            RunningNodeDef runningNodeDef = new RunningNodeDef(nodeDef, null);
            runningNodeDef.setSubProcPath(subProcPath);
            runningNodeDef.setAssigneeList(assigneeList);
            runningNodeDefList.add(runningNodeDef);
        }
        // SUB_PROC子流程定义解析
        if ((nodeDef.getNodeType().equals(FfService.NODE_TYPE_SUB_PROC) || nodeDef.getNodeType().equals(FfService.NODE_TYPE_ISOLATE_SUB_PROC)) && StringUtils.isNotEmpty(nodeDef.getAssignSubProcDef())) {
            ValueExpression expression = expressionFactory.createValueExpression(simpleContext, nodeDef.getAssignSubProcDef(), Object.class);
            Object object = null;
            try {
                object = expression.getValue(simpleContext);
            }
            catch (Exception e) {
                object = (String) null;
            }
            List assignSubProcDefList;// 解析后办理子流程定义列表
            if (object instanceof List) {
                assignSubProcDefList = (List) object;
            }
            else {
                assignSubProcDefList = new ArrayList<>();
                if (StringUtils.isNotEmpty((String) object)) {
                    String[] assignSubProcDefs = ((String) object).split(",");
                    for (int i = 0; i < assignSubProcDefs.length; i++) {
                        RunningProcDef runningProcDef = new RunningProcDef(loadProcDefByCode(assignSubProcDefs[i]));
                        assignSubProcDefList.add(runningProcDef);

                        // 递归处理内部子流程定义起始节点定义列表
                        Map subProcAllNodeVarMap = new HashMap<>();
                        subProcAllNodeVarMap.putAll(allNodeVarMap);
                        subProcAllNodeVarMap.putAll(runningProcDef.getProcVarDefMap());
                        List startRunningNodeDefList = getStartRunningNodeDefList(StringUtils.isNotEmpty(subProcPath) ? subProcPath + "." + nodeDef.getNodeCode() + ":" + runningProcDef.getProcDefCode() : nodeDef.getNodeCode() + ":" + runningProcDef.getProcDefCode(), runningProcDef, subProcAllNodeVarMap);
                        runningProcDef.setNextRunningNodeDefList(startRunningNodeDefList);
                    }
                }
            }

            RunningNodeDef runningNodeDef = new RunningNodeDef(nodeDef, null);
            runningNodeDef.setSubProcPath(subProcPath);
            runningNodeDef.setAssignSubProcDefList(assignSubProcDefList);
            runningNodeDefList.add(runningNodeDef);
        }

        return runningNodeDefList;
    }

    @Override
    public Proc loadProc(String procId) {
        return createProcQuery().setProcId(procId).queryForObject();
    }

    @Override
    public ProcQuery createProcQuery() {
        return new ProcQuery(ffProcService);
    }

    public InvolvedProcQuery createInvolvedProcQuery() {
        return new InvolvedProcQuery(ffProcService);
    }

    @Override
    public boolean updateProcBizInfo(String procId, String bizId, String bizType, String bizCode, String bizName, String bizDesc) {
        if (ffProcService.updateProcBizInfo(procId, bizId, bizType, bizCode, bizName, bizDesc) == 1) {
            return true;
        }

        return false;
    }

    @Override
    @FfOperation(operator = "${procStartUser}")
    public FfResult startProc(ProcDef procDef, String bizId, String bizType, String bizCode, String bizName, String bizDesc, String procStartUser, Map nodeVarMap, CandidateList candidateList) {
        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        return startProc(procDef, bizId, bizType, bizCode, bizName, bizDesc, procStartUser, nodeVarMap, candidateList, null);
    }

    @Override
    @FfOperation(operator = "${procStartUser}")
    public FfResult startProcByProcDefCode(String procDefCode, String bizId, String bizType, String bizCode, String bizName, String bizDesc, String procStartUser, Map nodeVarMap, CandidateList candidateList) {
        ProcDef procDef = loadProcDefByCode(procDefCode);
        return startProc(procDef, bizId, bizType, bizCode, bizName, bizDesc, procStartUser, nodeVarMap, candidateList);
    }

    @Override
    @FfOperation(operator = "${procStartUser}")
    public FfResult startIsolateSubProc(String isolateSubProcNodeId, String bizId, String bizType, String bizCode, String bizName, String bizDesc, String procStartUser, Map nodeVarMap, CandidateList candidateList) {
        FfResult ffResult = new FfResult();

        Node isolateSubProcNode = loadNode(isolateSubProcNodeId);
        if (!isolateSubProcNode.getIsolateSubProcStatus().equals(FfService.PROC_STATUS_NOT_START) && !isolateSubProcNode.getIsolateSubProcStatus().equals(FfService.PROC_STATUS_TERMINATE)) {
            throw new RuntimeException("errors.isolateSubProcIsAlreadyStart");
        }

        for (Map.Entry entry : createNodeVarQuery().setNodeId(isolateSubProcNode.getNodeId()).setRecursive(false).queryForMap().entrySet()) {
            if (!nodeVarMap.containsKey(entry.getKey())) {
                nodeVarMap.put(entry.getKey(), entry.getValue());
            }
        }

        if (candidateList == null || candidateList.size() == 0) {// 如果没有candidateList,使用节点定义中的isolateSubProcCandidate
            String isolateSubProcCandidate = isolateSubProcNode.getIsolateSubProcCandidate();
            if (StringUtils.isNotEmpty(isolateSubProcCandidate)) {
                candidateList = new Gson().fromJson(isolateSubProcCandidate, CandidateList.class);
            }
        }

        ProcDef procDef = loadProcDefByCode(isolateSubProcNode.getIsolateSubProcDefCode());
        ffResult.addAll(startProc(procDef, bizId, bizType, bizCode, bizName, bizDesc, procStartUser, nodeVarMap, candidateList, isolateSubProcNodeId));

        ffNodeService.updateIsolateSubProcStatus(isolateSubProcNodeId, FfService.PROC_STATUS_ACTIVE);

        return ffResult;
    }

    private FfResult startProc(ProcDef procDef, String bizId, String bizType, String bizCode, String bizName, String bizDesc, String procStartUser, Map nodeVarMap, CandidateList candidateList, String isolateSubProcNodeId) {
        FfResult ffResult = new FfResult();

        if (procDef == null || procDef.getProcDefStatus().equals(FfService.PROC_DEF_STATUS_DISABLE)) {
            throw new RuntimeException("errors.procDefIsNotActive");
        }

        String procId = OdUtils.getUuid();
        ffProcService.insertProc(procId, procDef.getProcDefId(), null, isolateSubProcNodeId, bizId, bizType, bizCode, bizName, bizDesc, procStartUser, ffHelper.getUserName(procStartUser), null, null, null, FfService.PROC_STATUS_ACTIVE, new Date());// 新增主流程
        ffResult.addCreateProc(createProcQuery().setProcId(procId).queryForObject());
        ffNodeService.insertNode(procId, null, procId, null, null, procDef.getProcDefId(), null, FfService.NODE_TYPE_BRANCH, null, procDef.getProcDefName(), null, null, null, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, null, null, null, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, "5", null, null, null, null, null, null, null, FfService.NODE_STATUS_ACTIVE, new Date());
        Node branchNode = createNodeQuery().setNodeId(procId).queryForObject();
        ffResult.addCreateNode(branchNode);

        for (ProcVarDef procVarDef : procDef.getProcVarDefList()) {
            if (!nodeVarMap.containsKey(procVarDef.getVarName())) {
                nodeVarMap.put(procVarDef.getVarName(), procVarDef.getValue());
            }
        }

        updateNodeVar(procId, nodeVarMap);// 更新节点变量

        List startNodeDefList = procDef.getStartNodeDefList();
        for (NodeDef startNodeDef : startNodeDefList) {
            ffResult.addAll(getNodeHandler(startNodeDef.getNodeType()).insertNodeByNodeDef(startNodeDef, branchNode, null, candidateList, FfService.OPERATION_INSERT, procStartUser));
        }

        return ffResult;
    }

    @Override
    @FfOperation(operator = "${procStartUser}")
    public FfResult startProcToNode(ProcDef procDef, String subProcPath, String nodeCode, String bizId, String bizType, String bizCode, String bizName, String bizDesc, String procStartUser, Map nodeVarMap, CandidateList candidateList) {
        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        return startProcToNode(procDef, subProcPath, nodeCode, bizId, bizType, bizCode, bizName, bizDesc, procStartUser, nodeVarMap, candidateList, null);
    }

    @Override
    @FfOperation(operator = "${procStartUser}")
    public FfResult startProcToNodeByProcDefCode(String procDefCode, String subProcPath, String nodeCode, String bizId, String bizType, String bizCode, String bizName, String bizDesc, String procStartUser, Map nodeVarMap, CandidateList candidateList) {
        ProcDef procDef = loadProcDefByCode(procDefCode);
        return startProcToNode(procDef, subProcPath, nodeCode, bizId, bizType, bizCode, bizName, bizDesc, procStartUser, nodeVarMap, candidateList);
    }

    private FfResult startProcToNode(ProcDef procDef, String subProcPath, String nodeCode, String bizId, String bizType, String bizCode, String bizName, String bizDesc, String procStartUser, Map nodeVarMap, CandidateList candidateList, String isolateSubProcNodeId) {
        FfResult ffResult = new FfResult();

        if (procDef == null || procDef.getProcDefStatus().equals(FfService.PROC_DEF_STATUS_DISABLE)) {
            throw new RuntimeException("errors.procDefIsNotActive");
        }

        String procId = OdUtils.getUuid();
        ffProcService.insertProc(procId, procDef.getProcDefId(), null, isolateSubProcNodeId, bizId, bizType, bizCode, bizName, bizDesc, procStartUser, ffHelper.getUserName(procStartUser), null, null, null, FfService.PROC_STATUS_ACTIVE, new Date());// 新增主流程
        ffResult.addCreateProc(createProcQuery().setProcId(procId).queryForObject());
        ffNodeService.insertNode(procId, null, procId, null, null, procDef.getProcDefId(), null, FfService.NODE_TYPE_BRANCH, null, procDef.getProcDefName(), null, null, null, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, null, null, null, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, "5", null, null, null, null, null, null, null, FfService.NODE_STATUS_ACTIVE, new Date());
        Node branchNode = createNodeQuery().setNodeId(procId).queryForObject();
        ffResult.addCreateNode(branchNode);

        for (ProcVarDef procVarDef : procDef.getProcVarDefList()) {
            if (!nodeVarMap.containsKey(procVarDef.getVarName())) {
                nodeVarMap.put(procVarDef.getVarName(), procVarDef.getValue());
            }
        }

        updateNodeVar(procId, nodeVarMap);// 更新节点变量

        ProcDef subProcDef = procDef;
        String branchNodeId;
        if (StringUtils.isNotEmpty(subProcPath)) {// 建立子流程路径上所有节点
            String[] splits = subProcPath.split("\\.");
            String[] path;

            for (int i = 0; i < splits.length; i++) {
                path = splits[i].split(":");

                // 创建上级节点
                ffResult.addAll(insertParentNodes(path[0], subProcDef, branchNode.getNodeId(), procId, true));
                List createNodeList = ffResult.getCreateNodeList();
                branchNode = createNodeList.get(createNodeList.size() - 1);

                // 新增子流程分支节点
                subProcDef = loadProcDefByCode(path[1]);
                branchNodeId = OdUtils.getUuid();
                ffNodeService.insertNode(branchNodeId, branchNode.getNodeId(), procId, null, null, subProcDef.getProcDefId(), null, FfService.NODE_TYPE_BRANCH, null, subProcDef.getProcDefName(), null, null, FfService.DEFAULT_COMPLETE_EXPRESSION_, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, null, null, null, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, "5", null, null, null, null, null, null, null, FfService.NODE_STATUS_ACTIVE, new Date());
                branchNode = createNodeQuery().setNodeId(branchNodeId).queryForObject();
                ffResult.addCreateNode(branchNode);
            }
        }

        ffResult.addAll(insertParentNodes(nodeCode, subProcDef, branchNode.getNodeId(), procId, false));
        List createNodeList = ffResult.getCreateNodeList();
        branchNode = createNodeList.get(createNodeList.size() - 1);

        NodeDef nodeDef = subProcDef.getNodeDef(nodeCode);
        ffResult.addAll(getNodeHandler(nodeDef.getNodeType()).insertNodeByNodeDef(nodeDef, branchNode, null, candidateList, FfService.OPERATION_INSERT, procStartUser));

        return ffResult;
    }

    /**
     * 根据指定的节点编码和流程定义创建上级节点。
     * 
     * @param nodeCode
     *        指定的节点编码
     * @param procDef
     *        流程定义
     * @param parentNodeId
     * @param procId
     * @param includeSelf
     *        是否包含自己
     * @return
     */
    private FfResult insertParentNodes(String nodeCode, ProcDef procDef, String parentNodeId, String procId, boolean includeSelf) {
        FfResult ffResult = new FfResult();

        NodeDef nodeDef = procDef.getNodeDef(nodeCode);
        List parentNodeDefList = nodeDef.getParentNodeDefList();// 获取节点的所有上级节点,包括自身,并新增这些节点
        NodeDef parentNodeDef;
        String nodeId;
        for (int i = 0; i < parentNodeDefList.size(); i++) {
            if (!includeSelf && i >= parentNodeDefList.size() - 1) {
                continue;
            }

            parentNodeDef = parentNodeDefList.get(i);
            nodeId = OdUtils.getUuid();
            ffNodeService.insertNode(nodeId, parentNodeId, procId, null, null, procDef.getProcDefId(), null, parentNodeDef.getNodeType(), parentNodeDef.getNodeCode(), parentNodeDef.getNodeName(), parentNodeDef.getParentNodeCode(), parentNodeDef.getCandidateAssignee(), parentNodeDef.getCompleteExpression(), parentNodeDef.getCompleteReturn(), parentNodeDef.getExclusive(), parentNodeDef.getAutoCompleteSameAssignee(), parentNodeDef.getAutoCompleteEmptyAssignee(), parentNodeDef.getInform(), parentNodeDef.getAssignee(), parentNodeDef.getAction(), parentNodeDef.getDueDate(), parentNodeDef.getClaim(), parentNodeDef.getForwardable(), parentNodeDef.getPriority(), null, null, null, null, null, null, null, FfService.NODE_STATUS_ACTIVE, new Date());
            ffResult.addCreateNode(createNodeQuery().setNodeId(nodeId).queryForObject());
            parentNodeId = nodeId;
        }

        return ffResult;
    }

    @Override
    public RunningProcDef getRunningProcDef(String procId, String currentTaskId, boolean drawOptional) {
        Node currentNode = null;
        if (StringUtils.isNotEmpty(currentTaskId)) {
            currentNode = loadNode(loadTask(currentTaskId).getNodeId());
        }

        return getBranchRunningProcDef(procId, currentNode, drawOptional);// 从主流程开始处理。
    }

    // 处理流程或子流程。
    private RunningProcDef getBranchRunningProcDef(String branchId, Node currentNode, boolean drawOptional) {
        Node branch = loadNode(branchId);
        ProcDef procDef = getNodeProcDef(branch); // 获取当前节点所属流程定义

        RunningProcDef runningProcDef = new RunningProcDef(procDef);

        // 设置流程状态。
        if (branch.getParentNodeId() == null) {
            runningProcDef.setProcStatus(branch.getProcStatus());
        }

        BufferedImage image = null;
        Graphics2D g2d = null;
        try {
            image = ImageIO.read(new ByteArrayInputStream(procDef.getProcDefDiagramFile()));// 绘流程定义图
            g2d = image.createGraphics();
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 递归处理子流程。
        List childNodeList = createChildNodeQuery().setNodeId(branchId).setRecursive(true).setIncludeSelf(true).queryForObjectList();
        for (Node childNode : childNodeList) {
            if (childNode.getNodeId().equals(branchId)) {
                handleChildNode(childNode, childNodeList, currentNode, runningProcDef, procDef, drawOptional, g2d);
            }

            if (runningProcDef.getNodeDef(childNode.getNodeCode()) != null) {
                ((RunningNodeDef) runningProcDef.getNodeDef(childNode.getNodeCode())).setNodeStatus(childNode.getNodeStatus());// 设置节点状态 。
            }
        }

        // 绘制动态注释
        Map nodeVarMap = createNodeVarQuery().setNodeId(branchId).queryForMap();
        drawDynamicNote(g2d, procDef, nodeVarMap);

        // 设置当前节点
        runningProcDef.setNodeVarMap(nodeVarMap);
        if (currentNode != null) {
            List parentNodeIdList = OdUtils.collectFromBean(createParentNodeQuery().setNodeId(currentNode.getNodeId()).setIncludeSelf(true).setRecursive(true).queryForObjectList(), "nodeId", String.class);
            if (parentNodeIdList.contains(branchId)) {
                runningProcDef.setCurrent(true);
            }
        }

        g2d.dispose();

        // 设置动态流程图
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "png", baos);
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
        String base64String = new BASE64Encoder().encodeBuffer(baos.toByteArray());
        runningProcDef.setDiagram(base64String);

        return runningProcDef;
    }

    // 递归处理子流程,绘制流程图节点状态,
    private void handleChildNode(Node node, List childNodeList, Node currentNode, RunningProcDef runningProcDef, ProcDef procDef, boolean drawOptional, Graphics2D g2d) {
        NodeDef nodeDef;
        Pattern outerPattern = Pattern.compile(FfService.CENTER_FORWARD_STEP + " *== *\\d+");
        Pattern innerPattern = Pattern.compile("\\d+");
        int centerForwardStep = 0;
        int maxCenterForwardStep = 0;
        for (Node childNode : childNodeList) {
            if (childNode.getParentNodeId() != null && childNode.getParentNodeId().equals(node.getNodeId())) {
                if (childNode.getNodeType().equals(FfService.NODE_TYPE_BRANCH)) {// 如果子节点为子流程,递归处理。
                    RunningProcDef childRunningProcDef = getBranchRunningProcDef(childNode.getNodeId(), currentNode, drawOptional);
                    Node parentNode = loadNode(childNode.getParentNodeId());
                    ((RunningNodeDef) runningProcDef.getNodeDef(parentNode.getNodeCode())).addSubProcRunningProcDef(childRunningProcDef);
                }
                else {// 如果子节点不是子流程,绘制状态。
                    if (childNode.getNodeStatus().equals(FfService.NODE_STATUS_ACTIVE) && childNode.getNodeCode() != null) {
                        nodeDef = procDef.getNodeDef(childNode.getNodeCode());
                        nodeDef.getShape().drawActive(g2d);// 绘制活动节点。

                        // 绘制可选节点。(围绕中心转发节点)
                        if (drawOptional && childNode.getNodeType().equals(FfService.NODE_TYPE_CENTER_FORWARD_TASK)) {
                            Map nodeVarMap = createNodeVarQuery().setNodeId(childNode.getParentNodeId()).queryForMap();
                            if (nodeVarMap.get(FfService.CENTER_FORWARD_STEP) != null) {
                                int currentCenterForwardStep = Integer.parseInt((String) nodeVarMap.get(FfService.CENTER_FORWARD_STEP));// 获取当前CENTER_FORWARD_STEP

                                Matcher matcher;
                                for (FlowDef flowDef : nodeDef.getOutgoingFlowDefList()) {// 判断中心转发节点相关的下一步转发节点,按当前和可选绘制其状态
                                    boolean isDefault = false;

                                    if (flowDef.getConditionExpression() == null) {
                                        continue;
                                    }
                                    matcher = outerPattern.matcher(flowDef.getConditionExpression());
                                    if (!matcher.find()) {
                                        continue;
                                    }
                                    matcher = innerPattern.matcher(matcher.group());
                                    if (!matcher.find()) {
                                        continue;
                                    }
                                    centerForwardStep = Integer.parseInt(matcher.group());
                                    if (centerForwardStep == currentCenterForwardStep) {
                                        isDefault = true;
                                    }

                                    ((RunningNodeDef) runningProcDef.getNodeDef(flowDef.getTargetNodeCode())).setCenterForwardStep(centerForwardStep);
                                    procDef.getNodeDef(flowDef.getTargetNodeCode()).getShape().drawOptional(g2d, isDefault);

                                    if (centerForwardStep > maxCenterForwardStep) {
                                        maxCenterForwardStep = centerForwardStep;
                                    }
                                }

                                // 绘制中心转发节点上级的STAGE节点相关的下一步节点,按当前和可选绘制其状态
                                maxCenterForwardStep++;
                                RunningNodeDef parentNodeDef = (RunningNodeDef) runningProcDef.getNodeDef(node.getNodeCode());
                                List parentOutgoingFlowDefList = parentNodeDef.getOutgoingFlowDefList();
                                for (FlowDef parentOutgoingFlowDef : parentOutgoingFlowDefList) {
                                    ((RunningNodeDef) runningProcDef.getNodeDef(parentOutgoingFlowDef.getTargetNodeCode())).setCenterForwardStep(maxCenterForwardStep);
                                    procDef.getNodeDef(parentOutgoingFlowDef.getTargetNodeCode()).getShape().drawOptional(g2d, maxCenterForwardStep == currentCenterForwardStep);
                                }
                            }
                        }
                    }

                    handleChildNode(childNode, childNodeList, currentNode, runningProcDef, procDef, drawOptional, g2d);
                }
            }
        }
    }

    /**
     * 绘制流程图动态注释
     * 
     * @param g2d
     * @param procDef
     * @param subProcDef
     * @param width
     * @param height
     */
    private void drawDynamicNote(Graphics2D g2d, ProcDef procDef, Map nodeVarMap) {
        // 设置JUEL解析环境
        HashMap allNodeVarMap = new HashMap<>();
        allNodeVarMap.putAll(getInternalServiceMap());
        allNodeVarMap.putAll(getExternalServiceMap());
        if (nodeVarMap != null) {
            allNodeVarMap.putAll(nodeVarMap);
        }
        ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
        SimpleContext simpleContext = new SimpleContext();
        for (Map.Entry entry : allNodeVarMap.entrySet()) {
            simpleContext.setVariable(entry.getKey(), expressionFactory.createValueExpression(entry.getValue(), Object.class));
        }

        BufferedImage noteImage = new BufferedImage(procDef.getProcDefDiagramWidth(), procDef.getProcDefDiagramHeight(), BufferedImage.TYPE_INT_ARGB); // 创建绘制动态注释图用BufferedImage
        Graphics2D noteG2d = noteImage.createGraphics(); // 获取Graphics2D
        noteG2d.setComposite(AlphaComposite.Clear);// 绘制透明背景
        noteG2d.fillRect(0, 0, procDef.getProcDefDiagramWidth(), procDef.getProcDefDiagramHeight());
        noteG2d.setComposite(AlphaComposite.Src);// 准备绘制其它内容,非透明
        noteG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 抗锯齿

        for (NoteDef noteDef : procDef.getNoteDefList()) {// 绘制动态注释
            if (noteDef.getDynamic().equals(FfService.BOOLEAN_TRUE) && StringUtils.isNotEmpty(noteDef.getNoteName())) {
                // JUEL解析
                ValueExpression expression = expressionFactory.createValueExpression(simpleContext, noteDef.getNoteName(), String.class);// 解析注释EL表达式
                noteDef.getShape().draw(noteG2d, (String) expression.getValue(simpleContext));
            }
        }

        noteImage = OdUtils.applyShadow(noteImage, 1, Color.BLACK, 0.2f);// 添加阴影
        g2d.drawImage(noteImage, 0, 0, null);// 绘制动态注释图到流程图
    }

    @Override
    @FfOperation(procId = "${procId}", taskId = "${taskId}", operator = "${executor}")
    public FfResult suspendProc(String procId, String taskId, String executor) {
        FfResult ffResult = new FfResult();

        List taskList = createTaskQuery().setProcId(procId).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE)).queryForObjectList();
        for (Task task : taskList) {
            Date COMPLETE_DATE_ = new Date();
            ffTaskService.updateTaskStatus(task.getTaskId(), executor, ffHelper.getUserName(executor), COMPLETE_DATE_, FfService.TASK_STATUS_SUSPEND);
            task.setTaskEndUser(executor);
            task.setTaskEndUserName(ffHelper.getUserName(executor));
            task.setTaskEndDate(COMPLETE_DATE_);
            task.setTaskStatus(FfService.TASK_STATUS_SUSPEND);
            ffResult.addSuspendTask(task);
        }
        List nodeList = createNodeQuery().setProcId(procId).setNodeStatusList(Arrays.asList(FfService.NODE_STATUS_ACTIVE)).queryForObjectList();
        for (Node node : nodeList) {
            Date COMPLETE_DATE_ = new Date();
            ffNodeService.updateNodeStatus(node.getNodeId(), executor, ffHelper.getUserName(executor), COMPLETE_DATE_, FfService.NODE_STATUS_SUSPEND);
            node.setNodeEndUser(executor);
            node.setNodeEndUserName(ffHelper.getUserName(executor));
            node.setNodeEndDate(COMPLETE_DATE_);
            node.setNodeStatus(FfService.NODE_STATUS_SUSPEND);
            ffResult.addSuspendNode(node);
        }

        ffProcService.updateProcStatus(procId, executor, ffHelper.getUserName(executor), new Date(), FfService.PROC_STATUS_SUSPEND);
        ffResult.addSuspendProc(loadProc(procId));

        return ffResult;
    }

    @Override
    @FfOperation(procId = "${procId}", taskId = "${taskId}", operator = "${executor}")
    public FfResult activateProc(String procId, String taskId, String executor) {
        FfResult ffResult = new FfResult();

        List taskList = createTaskQuery().setProcId(procId).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_SUSPEND)).queryForObjectList();
        for (Task task : taskList) {
            ffTaskService.updateTaskStatus(task.getTaskId(), FfService.TASK_STATUS_ACTIVE);
            task.setTaskStatus(FfService.TASK_STATUS_ACTIVE);
            ffResult.addActivateTask(task);
        }
        List nodeList = createNodeQuery().setProcId(procId).setNodeStatusList(Arrays.asList(FfService.NODE_STATUS_SUSPEND)).queryForObjectList();
        for (Node node : nodeList) {
            ffNodeService.updateNodeStatus(node.getNodeId(), FfService.NODE_STATUS_ACTIVE);
            node.setNodeStatus(FfService.NODE_STATUS_ACTIVE);
            ffResult.addActivateNode(node);
        }

        ffProcService.updateProcStatus(procId, FfService.PROC_STATUS_ACTIVE);
        ffResult.addActivateProc(loadProc(procId));

        return ffResult;
    }

    @Override
    @FfOperation(procId = "${procId}", taskId = "${taskId}", operator = "${executor}")
    public FfResult completeProc(String procId, String taskId, String executor) {
        FfResult ffResult = new FfResult();

        List taskList = createTaskQuery().setProcId(procId).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE)).queryForObjectList();
        for (Task task : taskList) {
            Date COMPLETE_DATE_ = new Date();
            ffTaskService.updateTaskStatus(task.getTaskId(), executor, ffHelper.getUserName(executor), COMPLETE_DATE_, FfService.TASK_STATUS_COMPLETE);
            task.setTaskEndUser(executor);
            task.setTaskEndUserName(ffHelper.getUserName(executor));
            task.setTaskEndDate(COMPLETE_DATE_);
            task.setTaskStatus(FfService.TASK_STATUS_COMPLETE);
            ffResult.addCompleteTask(task);
        }
        List nodeList = createNodeQuery().setProcId(procId).setNodeStatusList(Arrays.asList(FfService.NODE_STATUS_ACTIVE)).queryForObjectList();
        for (Node node : nodeList) {
            Date COMPLETE_DATE_ = new Date();
            ffNodeService.updateNodeStatus(node.getNodeId(), executor, ffHelper.getUserName(executor), COMPLETE_DATE_, FfService.NODE_STATUS_COMPLETE);
            node.setNodeEndUser(executor);
            node.setNodeEndUserName(ffHelper.getUserName(executor));
            node.setNodeEndDate(COMPLETE_DATE_);
            node.setNodeStatus(FfService.NODE_STATUS_COMPLETE);
            ffResult.addCompleteNode(node);
        }

        ffProcService.updateProcStatus(procId, executor, ffHelper.getUserName(executor), new Date(), FfService.PROC_STATUS_COMPLETE);
        ffResult.addSuspendProc(loadProc(procId));

        return ffResult;
    }

    @Override
    @FfOperation(procId = "${procId}", taskId = "${taskId}", operator = "${executor}")
    public FfResult terminateProc(String procId, String taskId, String executor) {
        FfResult ffResult = new FfResult();

        List taskList = createTaskQuery().setProcId(procId).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE)).queryForObjectList();
        for (Task task : taskList) {
            Date COMPLETE_DATE_ = new Date();
            ffTaskService.updateTaskStatus(task.getTaskId(), executor, ffHelper.getUserName(executor), COMPLETE_DATE_, FfService.TASK_STATUS_TERMINATE);
            task.setTaskEndUser(executor);
            task.setTaskEndUserName(ffHelper.getUserName(executor));
            task.setTaskEndDate(COMPLETE_DATE_);
            task.setTaskStatus(FfService.TASK_STATUS_TERMINATE);
            ffResult.addTerminateTask(task);
        }
        List nodeList = createNodeQuery().setProcId(procId).setNodeStatusList(Arrays.asList(FfService.NODE_STATUS_ACTIVE)).queryForObjectList();
        for (Node node : nodeList) {
            Date COMPLETE_DATE_ = new Date();
            ffNodeService.updateNodeStatus(node.getNodeId(), executor, ffHelper.getUserName(executor), COMPLETE_DATE_, FfService.NODE_STATUS_TERMINATE);
            node.setNodeEndUser(executor);
            node.setNodeEndUserName(ffHelper.getUserName(executor));
            node.setNodeEndDate(COMPLETE_DATE_);
            node.setNodeStatus(FfService.NODE_STATUS_TERMINATE);
            ffResult.addTerminateNode(node);
        }

        ffProcService.updateProcStatus(procId, executor, ffHelper.getUserName(executor), new Date(), FfService.PROC_STATUS_TERMINATE);
        ffResult.addTerminateProc(loadProc(procId));

        return ffResult;
    }

    @Override
    @FfOperation(procId = "${procId}", operator = "${executor}")
    public FfResult deleteProc(String procId, String executor) {
        FfResult ffResult = new FfResult();

        List nodeList = createChildNodeQuery().setNodeId(procId).setRecursive(true).setIncludeSelf(true).queryForObjectList();
        Node node;
        for (int i = nodeList.size() - 1; i >= 0; i--) {
            node = nodeList.get(i);

            List taskList = createTaskQuery().setNodeId(node.getNodeId()).queryForObjectList();
            for (Task task : taskList) {
                ffTaskService.deleteTask(task.getTaskId());
                ffResult.addDeleteTask(task);
            }

            ffNodeVarService.deleteNodeVarByNodeId(node.getNodeId());
            ffNodeService.deleteNode(node.getNodeId());
            ffResult.addDeleteNode(node);
        }

        Proc proc = loadProc(procId);
        ffProcService.deleteProc(procId);
        ffResult.addDeleteProc(proc);

        return ffResult;
    }

    @Override
    public Node loadNode(String nodeId) {
        return createNodeQuery().setNodeId(nodeId).queryForObject();
    }

    @Override
    public NodeQuery createNodeQuery() {
        return new NodeQuery(ffNodeService);
    }

    @Override
    public ParentNodeQuery createParentNodeQuery() {
        return new ParentNodeQuery(ffNodeService);
    }

    @Override
    public ChildNodeQuery createChildNodeQuery() {
        return new ChildNodeQuery(ffNodeService);
    }

    @Override
    @FfOperation(operator = "${executor}")
    public FfResult insertNode(NodeDef nodeDef, Node branchNode, String previousNodeIds, CandidateList candidateList, String executor) {
        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        return getNodeHandler(nodeDef.getNodeType()).insertNodeByNodeDef(nodeDef, branchNode, previousNodeIds, candidateList, FfService.OPERATION_INSERT, executor);
    }

    @Override
    @FfOperation(nodeId = "${nodeId}", operator = "${executor}")
    public FfResult activateNode(String nodeId, CandidateList candidateList, String executor) {
        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        Node node = loadNode(nodeId);
        return getNodeHandler(node.getNodeType()).activateNode(node, null, candidateList, FfService.OPERATION_ACTIVATE, executor);
    }

    @Override
    @FfOperation(nodeId = "${nodeId}", operator = "${executor}")
    public FfResult completeNode(String nodeId, CandidateList candidateList, String executor) {
        FfResult ffResult = new FfResult();

        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        Node node = loadNode(nodeId);
        List taskList = createTaskQuery().setNodeId(nodeId).setNodeStatusList(Arrays.asList(FfService.NODE_STATUS_ACTIVE)).queryForObjectList();
        for (Task task : taskList) {
            Date COMPLETE_DATE_ = new Date();
            ffTaskService.updateTaskStatus(task.getTaskId(), executor, ffHelper.getUserName(executor), COMPLETE_DATE_, FfService.TASK_STATUS_COMPLETE);
            task.setTaskEndUser(executor);
            task.setTaskEndUserName(ffHelper.getUserName(executor));
            task.setTaskEndDate(COMPLETE_DATE_);
            task.setNodeStatus(FfService.TASK_STATUS_COMPLETE);
            ffResult.addCompleteTask(task);
        }

        ffResult.addAll(getNodeHandler(node.getNodeType()).completeNode(node, null, candidateList, FfService.OPERATION_COMPLETE, executor));

        return ffResult;
    }

    @Override
    @FfOperation(nodeId = "${nodeId}", operator = "${executor}")
    public FfResult terminateNode(String nodeId, CandidateList candidateList, String executor) {
        FfResult ffResult = new FfResult();

        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        Node node = loadNode(nodeId);
        List taskList = createTaskQuery().setNodeId(nodeId).setNodeStatusList(Arrays.asList(FfService.NODE_STATUS_ACTIVE)).queryForObjectList();
        for (Task task : taskList) {
            Date COMPLETE_DATE_ = new Date();
            ffTaskService.updateTaskStatus(task.getTaskId(), executor, ffHelper.getUserName(executor), COMPLETE_DATE_, FfService.TASK_STATUS_TERMINATE);
            task.setTaskEndUser(executor);
            task.setTaskEndUserName(ffHelper.getUserName(executor));
            task.setTaskEndDate(COMPLETE_DATE_);
            task.setTaskStatus(FfService.TASK_STATUS_TERMINATE);
            ffResult.addTerminateTask(task);
        }

        ffResult.addAll(getNodeHandler(node.getNodeType()).completeNode(node, null, candidateList, FfService.OPERATION_TERMINATE, executor));

        List completeNodeList = ffResult.getCompleteNodeList();
        for (Node completeNode : completeNodeList) {
            if (completeNode.getNodeId().equals(nodeId)) {
                ffNodeService.updateNodeStatus(nodeId, FfService.NODE_STATUS_TERMINATE);

                completeNodeList.remove(completeNode);
                completeNode.setNodeStatus(FfService.NODE_STATUS_TERMINATE);
                ffResult.addTerminateNode(completeNode);
                break;
            }
        }

        return ffResult;
    }

    @FfOperation(nodeId = "${nodeId}", operator = "${executor}")
    public FfResult deleteNode(String nodeId, String executor) {
        FfResult ffResult = new FfResult();

        List childNodeList = createChildNodeQuery().setNodeId(nodeId).setRecursive(true).setIncludeSelf(true).queryForObjectList();
        Node childNode;
        for (int i = childNodeList.size() - 1; i >= 0; i--) {
            childNode = childNodeList.get(i);
            List taskList = createTaskQuery().setNodeId(childNode.getNodeId()).queryForObjectList();
            for (Task task : taskList) {
                ffTaskService.deleteTask(task.getTaskId());
                ffResult.addDeleteTask(task);
            }

            ffNodeVarService.deleteNodeVarByNodeId(childNode.getNodeId());
            ffNodeService.deleteNode(childNode.getNodeId());
            ffResult.addDeleteNode(childNode);
        }

        return ffResult;
    }

    @Override
    public String getSubProcPath(Node node) {
        // 递归查询上级节点,获取所有节点类型为NODE_TYPE_BRANCH和NODE_TYPE_SUB_PROC的节点。
        List parentNodeList = createParentNodeQuery().setNodeId(node.getNodeId()).setRecursive(true).setIncludeSelf(true).setNodeTypeList(Arrays.asList(FfService.NODE_TYPE_SUB_PROC, FfService.NODE_TYPE_BRANCH)).setDataScope(FfService.DATA_SCOPE_PROC_DEF).queryForObjectList();
        List subProcPathList = new ArrayList<>();
        for (Node parentNode : parentNodeList) {
            if (parentNode.getNodeType().equals(FfService.NODE_TYPE_SUB_PROC)) {
                subProcPathList.add(0, parentNode.getNodeCode());
            }
            if (parentNode.getNodeType().equals(FfService.NODE_TYPE_BRANCH)) {
                subProcPathList.add(0, parentNode.getSubProcDefCode());
            }
        }

        subProcPathList.remove(0);// 去掉根父节点。主流程的BRANCH节点
        if (subProcPathList.size() % 2 != 0) {// 如果节点个数为奇数,去掉最后一个子流程类型的节点
            subProcPathList.remove(subProcPathList.size() - 1);
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < subProcPathList.size(); i++) {
            stringBuilder.append(subProcPathList.get(i));
            if (i < subProcPathList.size() - 1) {
                if (i % 2 == 0) {
                    stringBuilder.append(":");
                }
                else {
                    stringBuilder.append(".");
                }
            }
        }

        return stringBuilder.toString();
    }

    @Override
    public Task loadTask(String taskId) {
        return createTaskQuery().setTaskId(taskId).queryForObject();
    }

    @Override
    public TaskQuery createTaskQuery() {
        return new TaskQuery(ffTaskService);
    }

    @Override
    @FfOperation(procId = "${task.procId}", nodeId = "${task.nodeId}", taskId = "${task.taskId}", operator = "${executor}")
    public FfResult insertTask(Task task, String executor) {
        FfResult ffResult = new FfResult();

        if (ffTaskService.insertTask(task.getTaskId(), task.getNodeId(), task.getPreviousTaskId(), task.getTaskType(), task.getAssignee(), task.getAssigneeName(), task.getAction(), task.getDueDate(), task.getClaim(), task.getForwardable(), task.getPriority(), task.getForwardStatus(), task.getTaskEndUser(), task.getTaskEndUserName(), task.getTaskEndDate(), task.getNextCandidate(), task.getTaskStatus(), task.getCreationDate()) == 1) {
            ffResult.addCreateTask(task);
        }

        return ffResult;
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult updateTaskAssignee(String taskId, String assignee, String assigneeName, String executor) {
        FfResult ffResult = new FfResult();

        ffTaskService.updateTaskAssignee(taskId, assignee, assigneeName);

        return ffResult;
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult suspendTask(String taskId, String executor) {
        FfResult ffResult = new FfResult();

        ffTaskService.updateTaskStatus(taskId, executor, ffHelper.getUserName(executor), new Date(), FfService.TASK_STATUS_SUSPEND);
        ffResult.addSuspendTask(loadTask(taskId));

        return ffResult;
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult activateTask(String taskId, String executor) {
        FfResult ffResult = new FfResult();

        ffTaskService.updateTaskStatus(taskId, FfService.TASK_STATUS_ACTIVE);
        ffResult.addActivateTask(loadTask(taskId));

        return ffResult;
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult terminateTask(String taskId, String executor) {
        FfResult ffResult = new FfResult();

        ffTaskService.updateTaskStatus(taskId, executor, ffHelper.getUserName(executor), new Date(), FfService.TASK_STATUS_TERMINATE);
        ffResult.addTerminateTask(loadTask(taskId));

        return ffResult;
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult deleteTask(String taskId, String executor) {
        FfResult ffResult = new FfResult();

        ffResult.addDeleteTask(loadTask(taskId));
        ffTaskService.deleteTask(taskId);

        return ffResult;
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult completeTask(String taskId, Map branchNodeVar, CandidateList candidateList, String executor) {
        FfResult ffResult = new FfResult();

        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        Task task = loadTask(taskId);
        if (task == null) {// 如果任务不存在,抛异常
            throw new RuntimeException("errors.taskNotExist");
        }
        if (!task.getTaskStatus().equals(FfService.TASK_STATUS_ACTIVE)) {// 任务状态不为待办中不能完成
            throw new RuntimeException("errors.taskHasBeenExecuted");
        }
        if (task.getClaim().equals(FfService.BOOLEAN_TRUE)) {// 需要认领不能完成
            throw new RuntimeException("errors.claimRequired");
        }

        if (task.getAssignee().equals(executor) || isDelegator(task.getAssignee(), executor)) {
            updateNodeVar(task.getParentNodeId(), branchNodeVar);// 更新当前分支节点变量

            String executorName = ffHelper.getUserName(executor);
            Date completeDate = new Date();
            ffTaskService.updateTaskStatus(taskId, executor, executorName, completeDate, candidateList.toJson(), FfService.TASK_STATUS_COMPLETE);// 完成任务
            task.setTaskEndUser(executor);
            task.setTaskEndUserName(executorName);
            task.setTaskEndDate(completeDate);
            task.setNextCandidate(candidateList.toJson());
            task.setTaskStatus(FfService.TASK_STATUS_COMPLETE);
            ffResult.addCompleteTask(task);

            if (task.getTaskType().equals(FfService.TASK_TYPE_FORWARD_TASK)) {
                if (createTaskQuery().setPreviousTaskId(task.getPreviousTaskId()).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE)).setDataScope(FfService.DATA_SCOPE_TASK).count() == 0) {
                    ffTaskService.updateTaskForwardStatus(task.getPreviousTaskId(), FfService.FORWARD_STATUS_FORWARDING_PROCESSING_COMPLETED);
                    ffResult.addForwardingProcessingCompletedTask(loadTask(task.getPreviousTaskId()));
                }

                return ffResult;
            }

            Node node = loadNode(task.getNodeId());
            String exclusive = node.getExclusive();
            if (exclusive != null && exclusive.indexOf("${") != -1) {// JUEL解析
                // 设置JUEL解析环境
                Map nodeVarMap = createNodeVarQuery().setNodeId(node.getParentNodeId()).setRecursive(true).queryForMap();// 获取节点变量
                nodeVarMap.putAll(getInternalServiceMap());
                nodeVarMap.putAll(getExternalServiceMap());
                nodeVarMap.put("proc", loadProc(node.getProcId()));
                nodeVarMap.put("branch", loadNode(node.getParentNodeId()));
                nodeVarMap.put("node", node);
                if (branchNodeVar != null) {
                    nodeVarMap.putAll(branchNodeVar);
                }
                nodeVarMap.putAll(ffNodeService.getTaskStatistic(node.getNodeId()));// 获取节点任务完成信息
                ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
                SimpleContext simpleContext = new SimpleContext();
                for (Map.Entry entry : nodeVarMap.entrySet()) {
                    simpleContext.setVariable(entry.getKey(), expressionFactory.createValueExpression(entry.getValue(), Object.class));
                }
                // JUEL解析
                ValueExpression expression = expressionFactory.createValueExpression(simpleContext, exclusive, String.class);
                exclusive = (String) expression.getValue(simpleContext);
            }
            if (FfService.BOOLEAN_TRUE.equals(exclusive)) {// 排他处理
                List remainActiveTaskList = createTaskQuery().setNodeId(node.getNodeId()).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE)).queryForObjectList();
                for (Task remainActiveTask : remainActiveTaskList) {
                    ffTaskService.updateTaskStatus(remainActiveTask.getTaskId(), executor, executorName, completeDate, FfService.TASK_STATUS_TERMINATE);
                    remainActiveTask.setTaskEndUser(executor);
                    remainActiveTask.setTaskEndUserName(executorName);
                    remainActiveTask.setTaskEndDate(completeDate);
                    remainActiveTask.setTaskStatus(FfService.TASK_STATUS_TERMINATE);
                    ffResult.addTerminateTask(remainActiveTask);
                }
            }

            ffResult.addAll(getNodeHandler(node.getNodeType()).completeNode(node, null, candidateList, FfService.OPERATION_COMPLETE, executor));

            return ffResult;
        }
        else {
            throw new RuntimeException("errrors.unauthorizedOperator");
        }
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult completeTaskToNode(String taskId, String subProcPath, String nodeCode, Map branchNodeVar, CandidateList candidateList, String executor) {
        FfResult ffResult = new FfResult();

        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        Task task = loadTask(taskId);
        if (task == null) {// 如果任务不存在,抛异常
            throw new RuntimeException("errors.taskNotExist");
        }
        if (!task.getTaskStatus().equals(FfService.TASK_STATUS_ACTIVE)) {// 任务状态不为待办中不能完成
            throw new RuntimeException("errors.taskHasBeenExecuted");
        }
        if (task.getClaim().equals(FfService.BOOLEAN_TRUE)) {// 需要认领不能完成
            throw new RuntimeException("errors.claimRequired");
        }

        if (task.getAssignee().equals(executor) || isDelegator(task.getAssignee(), executor)) {
            updateNodeVar(task.getParentNodeId(), branchNodeVar);// 更新当前分支节点变量

            String executorName = ffHelper.getUserName(executor);
            Date completeDate = new Date();
            ffTaskService.updateTaskStatus(taskId, executor, executorName, completeDate, candidateList.toJson(), FfService.TASK_STATUS_COMPLETE);// 完成任务
            task.setTaskEndUser(executor);
            task.setTaskEndUserName(executorName);
            task.setTaskEndDate(completeDate);
            task.setNextCandidate(candidateList.toJson());
            task.setTaskStatus(FfService.TASK_STATUS_COMPLETE);
            ffResult.addCompleteTask(task);

            Node node = loadNode(task.getNodeId());
            String exclusive = node.getExclusive();
            if (exclusive != null && exclusive.indexOf("${") != -1) {// JUEL解析
                // 设置JUEL解析环境
                Map nodeVarMap = createNodeVarQuery().setNodeId(node.getParentNodeId()).setRecursive(true).queryForMap();// 获取节点变量
                nodeVarMap.putAll(getInternalServiceMap());
                nodeVarMap.putAll(getExternalServiceMap());
                nodeVarMap.put("proc", loadProc(node.getProcId()));
                nodeVarMap.put("branch", loadNode(node.getParentNodeId()));
                nodeVarMap.put("node", node);
                if (branchNodeVar != null) {
                    nodeVarMap.putAll(branchNodeVar);
                }
                nodeVarMap.putAll(ffNodeService.getTaskStatistic(node.getNodeId()));// 获取节点任务完成信息
                ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
                SimpleContext simpleContext = new SimpleContext();
                for (Map.Entry entry : nodeVarMap.entrySet()) {
                    simpleContext.setVariable(entry.getKey(), expressionFactory.createValueExpression(entry.getValue(), Object.class));
                }
                // JUEL解析
                ValueExpression expression = expressionFactory.createValueExpression(simpleContext, exclusive, String.class);
                exclusive = (String) expression.getValue(simpleContext);
            }
            if (FfService.BOOLEAN_TRUE.equals(exclusive)) {// 排他处理
                List remainActiveTaskList = createTaskQuery().setNodeId(node.getNodeId()).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE)).queryForObjectList();
                for (Task remainActiveTask : remainActiveTaskList) {
                    ffTaskService.updateTaskStatus(remainActiveTask.getTaskId(), executor, executorName, completeDate, FfService.TASK_STATUS_TERMINATE);
                    remainActiveTask.setTaskEndUser(executor);
                    remainActiveTask.setTaskEndUserName(executorName);
                    remainActiveTask.setTaskEndDate(completeDate);
                    remainActiveTask.setTaskStatus(FfService.TASK_STATUS_TERMINATE);
                    ffResult.addTerminateTask(remainActiveTask);
                }
            }

            String nodeEndUserName = ffHelper.getUserName(executor);
            Date nodeEndDate = new Date();
            ffNodeService.updateNodeStatus(node.getNodeId(), executor, nodeEndUserName, nodeEndDate, FfService.NODE_STATUS_COMPLETE);// 完成节点
            node.setNodeEndUser(executor);
            node.setNodeEndUserName(nodeEndUserName);
            node.setNodeEndDate(nodeEndDate);
            node.setNodeStatus(FfService.NODE_STATUS_COMPLETE);
            ffResult.addCompleteNode(node);

            ffResult.addAll(jumpToNode(node, subProcPath, nodeCode, candidateList, false, executor));

            return ffResult;
        }
        else {
            throw new RuntimeException("errrors.unauthorizedOperator");
        }
    }

    /**
     * 任意跳转到其它节点
     * 
     * @param currentNode
     * @param subProcPath
     * @param nodeCode
     * @param candidateList
     * @param terminate
     * @param executor
     * @return
     */
    private FfResult jumpToNode(Node currentNode, String subProcPath, String nodeCode, CandidateList candidateList, boolean terminate, String executor) {
        FfResult ffResult = new FfResult();

        List parentNodeList = createParentNodeQuery().setNodeId(currentNode.getNodeId()).setRecursive(true).setIncludeSelf(false).queryForObjectList();
        Node branchNode = parentNodeList.get(parentNodeList.size() - 1);
        ProcDef subProcDef = loadProcDef(loadProc(currentNode.getProcId()).getProcDefId());
        String branchNodeId;
        int index = parentNodeList.size() - 2;
        boolean reserve = true;
        if (StringUtils.isNotEmpty(subProcPath)) {// 建立子流程路径上所有节点
            String[] splits = subProcPath.split("\\.");
            String[] path;

            for (int i = 0; i < splits.length; i++) {
                path = splits[i].split(":");

                // 创建上级节点
                NodeDef nodeDef = subProcDef.getNodeDef(path[0]);
                List parentNodeDefList = nodeDef.getParentNodeDefList();// 获取节点的所有上级节点,包括自身,并新增这些节点
                NodeDef parentNodeDef;
                String nodeId;
                for (int j = 0; j < parentNodeDefList.size(); j++) {
                    parentNodeDef = parentNodeDefList.get(j);

                    if (reserve) {// 任务节点和指定跳转节点的共用父节点不做处理,余下子节点需要完成。
                        if (index >= 0 && parentNodeDef.getNodeCode().equals(parentNodeList.get(index).getNodeCode())) {
                            branchNode = parentNodeList.get(index);
                            index--;
                            continue;
                        }
                        else {
                            ffResult.addAll(completeNode(parentNodeList, index, terminate, executor));
                            reserve = false;
                        }
                    }

                    nodeId = OdUtils.getUuid();
                    ffNodeService.insertNode(nodeId, branchNode.getNodeId(), currentNode.getProcId(), null, null, subProcDef.getProcDefId(), null, parentNodeDef.getNodeType(), parentNodeDef.getNodeCode(), parentNodeDef.getNodeName(), parentNodeDef.getParentNodeCode(), parentNodeDef.getCandidateAssignee(), parentNodeDef.getCompleteExpression(), parentNodeDef.getCompleteReturn(), parentNodeDef.getExclusive(), parentNodeDef.getAutoCompleteSameAssignee(), parentNodeDef.getAutoCompleteEmptyAssignee(), parentNodeDef.getInform(), parentNodeDef.getAssignee(), parentNodeDef.getAction(), parentNodeDef.getDueDate(), parentNodeDef.getClaim(), parentNodeDef.getForwardable(), parentNodeDef.getPriority(), null, null, null, null, null, null, null, FfService.NODE_STATUS_ACTIVE, new Date());
                    branchNode = createNodeQuery().setNodeId(nodeId).queryForObject();
                    ffResult.addCreateNode(branchNode);
                }

                // 新增子流程分支节点
                subProcDef = loadProcDefByCode(path[1]);
                branchNodeId = OdUtils.getUuid();
                ffNodeService.insertNode(branchNodeId, branchNode.getNodeId(), currentNode.getProcId(), null, null, subProcDef.getProcDefId(), null, FfService.NODE_TYPE_BRANCH, null, subProcDef.getProcDefName(), null, null, FfService.DEFAULT_COMPLETE_EXPRESSION_, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, null, null, null, FfService.BOOLEAN_FALSE, FfService.BOOLEAN_FALSE, "5", null, null, null, null, null, null, null, FfService.NODE_STATUS_ACTIVE, new Date());
                branchNode = createNodeQuery().setNodeId(branchNodeId).queryForObject();
                ffResult.addCreateNode(branchNode);
            }
        }

        NodeDef nodeDef = subProcDef.getNodeDef(nodeCode);
        List parentNodeDefList = nodeDef.getParentNodeDefList();// 获取节点的所有上级节点,包括自身,并新增这些节点
        NodeDef parentNodeDef;
        String nodeId;
        for (int j = 0; j < parentNodeDefList.size(); j++) {
            parentNodeDef = parentNodeDefList.get(j);

            if (reserve) {// 任务节点和指定跳转节点的共用父节点不做处理,余下子节点需要完成。
                if (index >= 0 && parentNodeDef.getNodeCode().equals(parentNodeList.get(index).getNodeCode())) {
                    branchNode = parentNodeList.get(index);
                    index--;
                    continue;
                }
                else {
                    ffResult.addAll(completeNode(parentNodeList, index, terminate, executor));
                    reserve = false;
                }
            }

            if (j < parentNodeDefList.size() - 1) {
                nodeId = OdUtils.getUuid();
                ffNodeService.insertNode(nodeId, branchNode.getNodeId(), currentNode.getProcId(), null, null, subProcDef.getProcDefId(), null, parentNodeDef.getNodeType(), parentNodeDef.getNodeCode(), parentNodeDef.getNodeName(), parentNodeDef.getParentNodeCode(), parentNodeDef.getCandidateAssignee(), parentNodeDef.getCompleteExpression(), parentNodeDef.getCompleteReturn(), parentNodeDef.getExclusive(), parentNodeDef.getAutoCompleteSameAssignee(), parentNodeDef.getAutoCompleteEmptyAssignee(), parentNodeDef.getInform(), parentNodeDef.getAssignee(), parentNodeDef.getAction(), parentNodeDef.getDueDate(), parentNodeDef.getClaim(), parentNodeDef.getForwardable(), parentNodeDef.getPriority(), null, null, null, null, null, null, null, FfService.NODE_STATUS_ACTIVE, new Date());
                branchNode = createNodeQuery().setNodeId(nodeId).queryForObject();
                ffResult.addCreateNode(branchNode);
            }
        }

        nodeDef = subProcDef.getNodeDef(nodeCode);
        ffResult.addAll(getNodeHandler(nodeDef.getNodeType()).insertNodeByNodeDef(nodeDef, branchNode, null, candidateList, FfService.OPERATION_INSERT, executor));

        return ffResult;
    }

    private FfResult completeNode(List parentNodeList, int index, boolean terminate, String executor) {
        FfResult ffResult = new FfResult();

        String nodeStatus = FfService.NODE_STATUS_COMPLETE;
        if (terminate) {
            nodeStatus = FfService.NODE_STATUS_TERMINATE;
        }

        Node node;
        for (int i = index; i >= 0; i--) {
            node = parentNodeList.get(i);
            String nodeEndUserName = ffHelper.getUserName(executor);
            Date nodeEndDate = new Date();
            ffNodeService.updateNodeStatus(node.getNodeId(), executor, nodeEndUserName, nodeEndDate, nodeStatus);// 完成节点
            node.setNodeEndUser(executor);
            node.setNodeEndUserName(nodeEndUserName);
            node.setNodeEndDate(nodeEndDate);
            node.setNodeStatus(nodeStatus);
            ffResult.addCompleteNode(node);
        }

        return ffResult;
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult claimTask(String taskId, String executor) {
        FfResult ffResult = new FfResult();

        Task task = loadTask(taskId);
        if (!FfService.BOOLEAN_TRUE.equals(task.getClaim())) {// 认领状态不为true不能认领
            throw new RuntimeException("notClaimable");
        }
        if (!task.getTaskStatus().equals(FfService.TASK_STATUS_ACTIVE)) {// 任务状态不为待办中不能认领
            throw new RuntimeException("errors.taskHasBeenExecuted");
        }

        ffTaskService.updateTaskClaim(taskId);

        String executorName = ffHelper.getUserName(executor);
        Date completeDate = new Date();
        List activeTaskList = createTaskQuery().setNodeId(task.getNodeId()).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE)).queryForObjectList();
        for (Task activeTask : activeTaskList) {
            if (activeTask.getTaskId().equals(taskId)) {
                continue;
            }

            ffTaskService.updateTaskStatus(activeTask.getTaskId(), executor, executorName, completeDate, FfService.TASK_STATUS_TERMINATE);
            activeTask.setTaskEndUser(executor);
            activeTask.setTaskEndUserName(executorName);
            activeTask.setTaskEndDate(completeDate);
            activeTask.setTaskStatus(FfService.TASK_STATUS_TERMINATE);
            ffResult.addTerminateTask(activeTask);
        }

        return ffResult;
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult forwardTask(String taskId, List assigneeList, String action, Date dueDate, String claim, String forwardable, Integer priority, String executor) {
        FfResult ffResult = new FfResult();

        Task task = loadTask(taskId);
        if (task == null) {// 如果任务不存在,抛异常
            throw new RuntimeException("errors.taskNotExist");
        }
        if (!createProcQuery().setProcId(task.getProcId()).queryForObject().getProcStatus().equals(FfService.PROC_STATUS_ACTIVE)) {// 如果流程不为运行中状态,抛异常
            throw new RuntimeException("errors.procNotActive");
        }
        if (!task.getTaskStatus().equals(FfService.TASK_STATUS_ACTIVE)) {// 任务状态不为待办中不能转发
            throw new RuntimeException("errors.taskHasBeenExecuted");
        }

        if (task.getAssignee().equals(executor) || isDelegator(task.getAssignee(), executor)) {
            Node node = loadNode(task.getNodeId());
            Node branchNode = loadNode(node.getParentNodeId());
            Proc proc = loadProc(node.getProcId());
            // 设置JUEL解析环境
            Map nodeVarMap = createNodeVarQuery().setNodeId(node.getParentNodeId()).setRecursive(true).queryForMap();// 获取节点变量
            nodeVarMap.putAll(getInternalServiceMap());
            nodeVarMap.putAll(getExternalServiceMap());
            nodeVarMap.put("proc", proc);
            nodeVarMap.put("branch", branchNode);
            nodeVarMap.put("node", node);
            ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
            SimpleContext simpleContext = new SimpleContext();
            for (Map.Entry entry : nodeVarMap.entrySet()) {
                simpleContext.setVariable(entry.getKey(), expressionFactory.createValueExpression(entry.getValue(), Object.class));
            }
            // JUEL解析
            ValueExpression expression;
            // 计算办理人
            for (String assignee : assigneeList) {
                Task forwardTask = new Task();
                forwardTask.setTaskId(OdUtils.getUuid());
                forwardTask.setNodeId(task.getNodeId());
                forwardTask.setPreviousTaskId(taskId);
                forwardTask.setTaskType(FfService.TASK_TYPE_FORWARD_TASK);
                forwardTask.setAssignee(assignee);
                forwardTask.setAssigneeName(ffHelper.getUserName(assignee));
                forwardTask.setAction(action);
                forwardTask.setDueDate(dueDate);
                forwardTask.setClaim(claim);
                forwardTask.setForwardable(forwardable);
                forwardTask.setPriority(priority);
                forwardTask.setForwardStatus(FfService.FORWARD_STATUS_NOT_FORWARDED);
                forwardTask.setTaskStatus(FfService.TASK_STATUS_ACTIVE);
                forwardTask.setCreationDate(new Date());
                simpleContext.setVariable("task", expressionFactory.createValueExpression(forwardTask, Object.class));
                if (StringUtils.isNotEmpty(action)) {// 解析JUEL,获取业务系统操作
                    expression = expressionFactory.createValueExpression(simpleContext, action, String.class);
                    forwardTask.setAction((String) expression.getValue(simpleContext));
                }

                insertTask(forwardTask, executor);
                ffResult.addCreateTask(loadTask(forwardTask.getTaskId()));
            }

            ffTaskService.updateTaskForwardStatus(taskId, FfService.FORWARD_STATUS_FORWARDING);
            task.setForwardStatus(FfService.FORWARD_STATUS_FORWARDING);
            ffResult.addForwardingTask(task);

            return ffResult;
        }
        else {
            throw new RuntimeException("errrors.unauthorizedOperator");
        }
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult rejectTask(String taskId, CandidateList candidateList, String executor) {
        FfResult ffResult = new FfResult();

        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        Task task = loadTask(taskId);
        if (task == null) {// 如果任务不存在,抛异常
            throw new RuntimeException("errors.taskNotExist");
        }
        if (!createProcQuery().setProcId(task.getProcId()).queryForObject().getProcStatus().equals(FfService.PROC_STATUS_ACTIVE)) {// 如果流程不为运行中状态,抛异常
            throw new RuntimeException("errors.procNotActive");
        }
        if (!task.getTaskStatus().equals(FfService.TASK_STATUS_ACTIVE)) {// 任务状态不为待办中不能完成
            throw new RuntimeException("errors.taskHasBeenExecuted");
        }

        if (task.getAssignee().equals(executor) || isDelegator(task.getAssignee(), executor)) {
            Node node = createNodeQuery().setNodeId(task.getNodeId()).queryForObject();
            List taskList = createTaskQuery().setNodeId(task.getNodeId()).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE, FfService.TASK_STATUS_SUSPEND, FfService.TASK_STATUS_COMPLETE)).queryForObjectList();

            String exclusive = node.getExclusive();
            if (exclusive != null && exclusive.indexOf("${") != -1) {// JUEL解析
                // 设置JUEL解析环境
                Map nodeVarMap = createNodeVarQuery().setNodeId(node.getParentNodeId()).setRecursive(true).queryForMap();// 获取节点变量
                nodeVarMap.putAll(getInternalServiceMap());
                nodeVarMap.putAll(getExternalServiceMap());
                nodeVarMap.put("proc", loadProc(node.getProcId()));
                nodeVarMap.put("branch", loadNode(node.getParentNodeId()));
                nodeVarMap.put("node", node);
                nodeVarMap.putAll(ffNodeService.getTaskStatistic(node.getNodeId()));// 获取节点任务完成信息
                ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
                SimpleContext simpleContext = new SimpleContext();
                for (Map.Entry entry : nodeVarMap.entrySet()) {
                    simpleContext.setVariable(entry.getKey(), expressionFactory.createValueExpression(entry.getValue(), Object.class));
                }
                // JUEL解析
                ValueExpression expression = expressionFactory.createValueExpression(simpleContext, exclusive, String.class);
                exclusive = (String) expression.getValue(simpleContext);
            }
            if (!FfService.BOOLEAN_TRUE.equals(exclusive) && taskList.size() > 1) {// 非独占任务不能驳回
                throw new RuntimeException("errors.cannotRejectInParallel");
            }
            for (Task _task : taskList) {// 设置其它任务状态为异常完成
                if (_task.getTaskStatus().equals(FfService.TASK_STATUS_ACTIVE)) {
                    String executorName = ffHelper.getUserName(executor);
                    Date completeDate = new Date();
                    ffTaskService.updateTaskStatus(_task.getTaskId(), executor, executorName, completeDate, FfService.TASK_STATUS_TERMINATE);
                    _task.setTaskEndUser(executor);
                    _task.setTaskEndUserName(executorName);
                    _task.setTaskEndDate(completeDate);
                    _task.setTaskStatus(FfService.TASK_STATUS_TERMINATE);
                    ffResult.addTerminateTask(_task);
                }
            }

            ffResult.addAll(getNodeHandler(node.getNodeType()).rejectNode(node, candidateList, FfService.OPERATION_REJECT, executor));// 驳回节点

            return ffResult;
        }
        else {
            throw new RuntimeException("errrors.unauthorizedOperator");
        }
    }

    @Override
    @FfOperation(taskId = "${taskId}", operator = "${executor}")
    public FfResult rejectTaskToNode(String taskId, String subProcPath, String nodeCode, CandidateList candidateList, String executor) {
        FfResult ffResult = new FfResult();

        if (candidateList == null) {
            candidateList = new CandidateList();
        }

        Task task = loadTask(taskId);
        if (task == null) {// 如果任务不存在,抛异常
            throw new RuntimeException("errors.taskNotExist");
        }
        if (!createProcQuery().setProcId(task.getProcId()).queryForObject().getProcStatus().equals(FfService.PROC_STATUS_ACTIVE)) {// 如果流程不为激活状态,抛异常
            throw new RuntimeException("errors.procNotActive");
        }
        if (!task.getTaskStatus().equals(FfService.TASK_STATUS_ACTIVE)) {// 任务状态不为激活不能驳回
            throw new RuntimeException("errors.taskHasBeenExecuted");
        }

        if (task.getAssignee().equals(executor) || isDelegator(task.getAssignee(), executor)) {
            Node node = createNodeQuery().setNodeId(task.getNodeId()).queryForObject();
            List taskList = createTaskQuery().setNodeId(task.getNodeId()).setTaskStatusList(Arrays.asList(FfService.TASK_STATUS_ACTIVE, FfService.TASK_STATUS_SUSPEND, FfService.TASK_STATUS_COMPLETE)).queryForObjectList();

            String exclusive = node.getExclusive();
            if (exclusive != null && exclusive.indexOf("${") != -1) {// JUEL解析
                // 设置JUEL解析环境
                Map nodeVarMap = createNodeVarQuery().setNodeId(node.getParentNodeId()).setRecursive(true).queryForMap();// 获取节点变量
                nodeVarMap.putAll(getInternalServiceMap());
                nodeVarMap.putAll(getExternalServiceMap());
                nodeVarMap.put("proc", loadProc(node.getProcId()));
                nodeVarMap.put("branch", loadNode(node.getParentNodeId()));
                nodeVarMap.put("node", node);
                nodeVarMap.putAll(ffNodeService.getTaskStatistic(node.getNodeId()));// 获取节点任务完成信息
                ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
                SimpleContext simpleContext = new SimpleContext();
                for (Map.Entry entry : nodeVarMap.entrySet()) {
                    simpleContext.setVariable(entry.getKey(), expressionFactory.createValueExpression(entry.getValue(), Object.class));
                }
                // JUEL解析
                ValueExpression expression = expressionFactory.createValueExpression(simpleContext, exclusive, String.class);
                exclusive = (String) expression.getValue(simpleContext);
            }
            if (!FfService.BOOLEAN_TRUE.equals(exclusive) && taskList.size() > 1) {// 非独占任务不能驳回
                throw new RuntimeException("errors.cannotRejectInParallel");
            }
            for (Task _task : taskList) {// 设置其它任务状态为异常完成
                if (_task.getTaskStatus().equals(FfService.TASK_STATUS_ACTIVE)) {
                    String executorName = ffHelper.getUserName(executor);
                    Date completeDate = new Date();
                    ffTaskService.updateTaskStatus(_task.getTaskId(), executor, executorName, completeDate, FfService.TASK_STATUS_TERMINATE);
                    _task.setTaskEndUser(executor);
                    _task.setTaskEndUserName(executorName);
                    _task.setTaskEndDate(completeDate);
                    _task.setTaskStatus(FfService.TASK_STATUS_TERMINATE);
                    ffResult.addTerminateTask(_task);
                }
            }

            String nodeEndUserName = ffHelper.getUserName(executor);
            Date nodeEndDate = new Date();
            ffNodeService.updateNodeStatus(node.getNodeId(), executor, nodeEndUserName, nodeEndDate, FfService.NODE_STATUS_TERMINATE);// 完成节点
            node.setNodeEndUser(executor);
            node.setNodeEndUserName(nodeEndUserName);
            node.setNodeEndDate(nodeEndDate);
            node.setNodeStatus(FfService.NODE_STATUS_TERMINATE);
            ffResult.addTerminateNode(node);

            ffResult.addAll(jumpToNode(node, subProcPath, nodeCode, candidateList, true, executor));

            return ffResult;
        }
        else {
            throw new RuntimeException("errrors.unauthorizedOperator");
        }
    }

    @Override
    @FfOperation(nodeId = "${nodeId}", operator = "${executor}")
    public FfResult appendCandidate(String nodeId, CandidateList candidateList, String executor) {
        FfResult ffResult = new FfResult();

        Node node = loadNode(nodeId);
        if (node == null) {
            throw new RuntimeException("errors.nodeNotExist");
        }

        if (candidateList == null) {
            return ffResult;
        }

        ffResult.addAll(getNodeHandler(node.getNodeType()).appendCandidate(node, candidateList, executor));

        return ffResult;
    }

    @Override
    public NodeVar loadNodeVar(String nodeVarId) {
        return createNodeVarQuery().setNodeVarId(nodeVarId).queryForObject();
    }

    @Override
    public NodeVarQuery createNodeVarQuery() {
        return new NodeVarQuery(ffNodeVarService);
    }

    @Override
    public boolean insertNodeVar(NodeVar nodeVar) {
        if (ffNodeVarService.insertNodeVar(nodeVar.getNodeVarId(), nodeVar.getNodeId(), nodeVar.getVarType(), nodeVar.getVarName(), nodeVar.getValue(), nodeVar.getObj(), nodeVar.getCreationDate()) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public boolean updateNodeVar(NodeVar nodeVar) {
        if (ffNodeVarService.updateNodeVar(nodeVar.getNodeVarId(), nodeVar.getVarType(), nodeVar.getVarName(), nodeVar.getValue(), nodeVar.getObj()) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public List updateNodeVar(String nodeId, Map nodeVarMap) {
        return ffNodeVarService.updateNodeVar(nodeId, nodeVarMap);
    }

    @Override
    public boolean deleteNodeVar(String nodeVarId) {
        if (ffNodeVarService.deleteNodeVar(nodeVarId) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public boolean deleteNodeVarByNodeId(String nodeId) {
        if (ffNodeVarService.deleteNodeVarByNodeId(nodeId) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public Delegate loadDelegate(String delegateId) {
        return createDelegateQuery().setDelegateId(delegateId).queryForObject();
    }

    @Override
    public DelegateQuery createDelegateQuery() {
        return new DelegateQuery(ffDelegateService);
    }

    @Override
    public boolean insertDelegate(String delegateId, String assignee, String assigneeName, String delegator, String delegatorName, Date startDate, Date endDate) {
        if (ffDelegateService.insertDelegate(delegateId, assignee, assigneeName, delegator, delegatorName, startDate, endDate) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public boolean updateDelegate(String delegateId, String assignee, String assigneeName, String delegator, String delegatorName, Date startDate, Date endDate) {
        if (ffDelegateService.updateDelegate(delegateId, assignee, assigneeName, delegator, delegatorName, startDate, endDate) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public boolean deleteDelegate(String delegateId) {
        if (ffDelegateService.deleteDelegate(delegateId) == 1) {
            return true;
        }

        return false;
    }

    @Override
    public boolean isDelegator(String assignee, String delegator) {
        List delegateList = createDelegateQuery().setDelegator(delegator).queryForObjectList();

        for (Delegate delegate : delegateList) {
            if (delegate.getAssignee() != null && !delegate.getAssignee().equals(assignee)) {
                continue;
            }
            if (delegate.getStartDate() != null && delegate.getStartDate().getTime() > System.currentTimeMillis()) {
                continue;
            }
            if (delegate.getEndDate() != null && delegate.getEndDate().getTime() < System.currentTimeMillis()) {
                continue;
            }

            return true;
        }

        return false;
    }

    @Override
    public Operation loadOperation(String operationId) {
        return createOperationQuery().setOperationId(operationId).queryForObject();
    }

    @Override
    public OperationQuery createOperationQuery() {
        return new OperationQuery(ffOperationService);
    }

    @Override
    public List selectProcOp(String operationId) {
        List procOpList = new ArrayList<>();

        List> result = ffOperationService.selectProcOp(operationId);
        for (int i = 0; i < result.size(); i++) {
            procOpList.add(new ProcOp(result.get(i)));
        }

        return procOpList;
    }

    @Override
    public List selectNodeOp(String operationId) {
        List nodeOpList = new ArrayList<>();

        List> result = ffOperationService.selectNodeOp(operationId);
        for (int i = 0; i < result.size(); i++) {
            nodeOpList.add(new NodeOp(result.get(i)));
        }

        return nodeOpList;
    }

    @Override
    public List selectTaskOp(String operationId) {
        List taskOpList = new ArrayList<>();

        List> result = ffOperationService.selectTaskOp(operationId);
        for (int i = 0; i < result.size(); i++) {
            taskOpList.add(new TaskOp(result.get(i)));
        }

        return taskOpList;
    }

    @Override
    public List selectNodeVarOp(String operationId) {
        List nodeVarOpList = new ArrayList<>();

        List> result = ffOperationService.selectNodeVarOp(operationId);
        for (int i = 0; i < result.size(); i++) {
            nodeVarOpList.add(new NodeVarOp(result.get(i)));
        }

        return nodeVarOpList;
    }

    @Override
    public FfResult undo(String operationId) {
        return ffOperationService.undo(operationId);
    }

    @Override
    public List getAssigneeList(String assigneeString) {
        List assigneeList = new ArrayList<>();

        if (StringUtils.isNotEmpty(assigneeString)) {
            String[] assignees = assigneeString.split(",");
            for (int i = 0; i < assignees.length; i++) {
                FfUser ffUser = new FfUser();
                ffUser.setId(assignees[i]);
                ffUser.setUserName(ffHelper.getUserName(assignees[i]));
                assigneeList.add(ffUser);
            }
        }

        return assigneeList;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy