001/*
002 *    Copyright 2024-2025, Warm-Flow (290631660@qq.com).
003 *
004 *    Licensed under the Apache License, Version 2.0 (the "License");
005 *    you may not use this file except in compliance with the License.
006 *    You may obtain a copy of the License at
007 *
008 *       https://www.apache.org/licenses/LICENSE-2.0
009 *
010 *    Unless required by applicable law or agreed to in writing, software
011 *    distributed under the License is distributed on an "AS IS" BASIS,
012 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *    See the License for the specific language governing permissions and
014 *    limitations under the License.
015 */
016package org.dromara.warm.flow.core.service.impl;
017
018import org.dromara.warm.flow.core.FlowFactory;
019import org.dromara.warm.flow.core.constant.ExceptionCons;
020import org.dromara.warm.flow.core.dao.FlowNodeDao;
021import org.dromara.warm.flow.core.entity.Definition;
022import org.dromara.warm.flow.core.entity.Node;
023import org.dromara.warm.flow.core.entity.Skip;
024import org.dromara.warm.flow.core.enums.NodeType;
025import org.dromara.warm.flow.core.enums.PublishStatus;
026import org.dromara.warm.flow.core.orm.service.impl.WarmServiceImpl;
027import org.dromara.warm.flow.core.service.NodeService;
028import org.dromara.warm.flow.core.utils.*;
029
030import java.io.Serializable;
031import java.util.Collection;
032import java.util.Collections;
033import java.util.List;
034import java.util.Map;
035import java.util.stream.Collectors;
036
037/**
038 * 流程节点Service业务层处理
039 *
040 * @author warm
041 * @since 2023-03-29
042 */
043public class NodeServiceImpl extends WarmServiceImpl<FlowNodeDao<Node>, Node> implements NodeService {
044
045    @Override
046    public NodeService setDao(FlowNodeDao<Node> warmDao) {
047        this.warmDao = warmDao;
048        return this;
049    }
050
051    @Override
052    public List<Node> getByFlowCode(String flowCode) {
053        Definition definition = FlowFactory.defService().getOne(FlowFactory.newDef()
054                .setFlowCode(flowCode).setIsPublish(PublishStatus.PUBLISHED.getKey()));
055        if (ObjectUtil.isNotNull(definition)) {
056            return list(FlowFactory.newNode().setDefinitionId(definition.getId()));
057        }
058        return Collections.emptyList();
059    }
060
061    @Override
062    public List<Node> getByNodeCodes(List<String> nodeCodes, Long definitionId) {
063        return getDao().getByNodeCodes(nodeCodes, definitionId);
064    }
065
066    @Override
067    public List<Node> getNextNodeList(Long definitionId, String nowNodeCode, String anyNodeCode, String skipType,
068                                      Map<String, Object> variable) {
069        // 如果是网关节点,则根据条件判断
070        return getNextByCheckGateway(variable, getNextNode(definitionId, nowNodeCode, anyNodeCode, skipType));
071    }
072
073    @Override
074    public Node getNextNode(Long definitionId, String nowNodeCode, String anyNodeCode, String skipType) {
075        AssertUtil.isNull(definitionId, ExceptionCons.NOT_DEFINITION_ID);
076        AssertUtil.isEmpty(nowNodeCode, ExceptionCons.LOST_NODE_CODE);
077        AssertUtil.isEmpty(skipType, ExceptionCons.NULL_CONDITIONVALUE);
078
079        // 如果指定了跳转节点,直接获取节点
080        if (StringUtils.isNotEmpty(anyNodeCode)) {
081            return getOne(FlowFactory.newNode().setNodeCode(anyNodeCode).setDefinitionId(definitionId));
082        }
083        // 查询当前节点
084        Node nowNode = getOne(FlowFactory.newNode().setNodeCode(nowNodeCode).setDefinitionId(definitionId));
085        AssertUtil.isNull(nowNode, ExceptionCons.LOST_CUR_NODE);
086        // 获取跳转关系
087        List<Skip> skips = FlowFactory.skipService().list(FlowFactory.newSkip().setDefinitionId(definitionId)
088                .setNowNodeCode(nowNodeCode));
089        AssertUtil.isNull(skips, ExceptionCons.NULL_SKIP_TYPE);
090
091        Skip nextSkip = getSkipByCheck(nowNode, skips, skipType);
092        AssertUtil.isNull(nextSkip, ExceptionCons.NULL_SKIP_TYPE);
093
094        // 根据跳转查询出跳转到的那个节点
095        Node nextNode = getOne(FlowFactory.newNode().setNodeCode(nextSkip.getNextNodeCode()).setDefinitionId(definitionId));
096        AssertUtil.isNull(nextNode, ExceptionCons.NULL_NODE_CODE);
097        AssertUtil.isTrue(NodeType.isStart(nextNode.getNodeType()), ExceptionCons.FRIST_FORBID_BACK);
098        return nextNode;
099    }
100
101    /**
102     * 通过校验跳转类型获取跳转集合
103     *
104     * @param nowNode       当前节点信息
105     * @param skips         跳转集合
106     * @param skipType      跳转类型
107     * @return List<Skip>
108     * @author xiarg
109     * @since 2024/8/21 11:32
110     */
111    private Skip getSkipByCheck(Node nowNode, List<Skip> skips, String skipType) {
112        if (CollUtil.isEmpty(skips)) {
113            return null;
114        }
115        if (!NodeType.isStart(nowNode.getNodeType())) {
116            skips = skips.stream().filter(t -> {
117                if (StringUtils.isNotEmpty(t.getSkipType())) {
118                    return skipType.equals(t.getSkipType());
119                }
120                return true;
121            }).collect(Collectors.toList());
122        }
123        AssertUtil.isEmpty(skips, ExceptionCons.NULL_SKIP_TYPE);
124        return skips.get(0);
125    }
126
127    @Override
128    public List<Node> getNextByCheckGateway(Map<String, Object> variable, Node nextNode) {
129        // 网关节点处理
130        if (NodeType.isGateWay(nextNode.getNodeType())) {
131            List<Skip> skipsGateway = FlowFactory.skipService().list(FlowFactory.newSkip()
132                    .setDefinitionId(nextNode.getDefinitionId()).setNowNodeCode(nextNode.getNodeCode()));
133            if (CollUtil.isEmpty(skipsGateway)) {
134                return null;
135            }
136            // 过滤跳转
137            if (!NodeType.isStart(nextNode.getNodeType())) {
138                skipsGateway = skipsGateway.stream().filter(t -> {
139                    if (NodeType.isGateWaySerial(nextNode.getNodeType())) {
140                        AssertUtil.isEmpty(variable, ExceptionCons.MUST_CONDITIONVALUE_NODE);
141                        if (ObjectUtil.isNotNull(t.getSkipCondition())) {
142                            return ExpressionUtil.eval(t.getSkipCondition(), variable);
143                        }
144                    }
145                    // 并行网关返回多个跳转
146                    return true;
147                }).collect(Collectors.toList());
148            }
149            AssertUtil.isEmpty(skipsGateway, ExceptionCons.NULL_CONDITIONVALUE_NODE);
150            List<String> nextNodeCodes = StreamUtils.toList(skipsGateway, Skip::getNextNodeCode);
151            List<Node> nextNodes = FlowFactory.nodeService()
152                    .getByNodeCodes(nextNodeCodes, nextNode.getDefinitionId());
153            AssertUtil.isEmpty(nextNodes, ExceptionCons.NOT_NODE_DATA);
154            return nextNodes;
155        }
156        // 非网关节点直接返回
157        return CollUtil.toList(nextNode);
158    }
159
160    @Override
161    public int deleteNodeByDefIds(Collection<? extends Serializable> defIds) {
162        return getDao().deleteNodeByDefIds(defIds);
163    }
164
165}