update - 调整 BPMN 协议转换逻辑, 解决针对部分情况的转换异常
This commit is contained in:
parent
76422ee9cc
commit
f04abb0960
@ -9,9 +9,8 @@ import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JSON 版本的 BPMN 协议模型
|
||||
@ -64,7 +63,7 @@ public class BpmnJsonNode {
|
||||
|
||||
|
||||
/* 内部使用,不需要外界传 */
|
||||
private transient Map incoming = new HashMap();
|
||||
private transient List<String> incoming = new ArrayList<>();
|
||||
/* 内部使用, 用于 JSON 格式转换 */
|
||||
private transient BpmnJsonNode preJsonNode;
|
||||
|
||||
@ -124,11 +123,11 @@ public class BpmnJsonNode {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getIncoming() {
|
||||
public List<String> getIncoming() {
|
||||
return incoming;
|
||||
}
|
||||
|
||||
public void setIncoming(Map incoming) {
|
||||
public void setIncoming(List<String> incoming) {
|
||||
this.incoming = incoming;
|
||||
}
|
||||
|
||||
|
||||
@ -11,16 +11,34 @@ import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.flowable.bpmn.BpmnAutoLayout;
|
||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.EndEvent;
|
||||
import org.flowable.bpmn.model.ExclusiveGateway;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.FlowableListener;
|
||||
import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.bpmn.model.SequenceFlow;
|
||||
import org.flowable.bpmn.model.ServiceTask;
|
||||
import org.flowable.bpmn.model.StartEvent;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.engine.repository.Model;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.*;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.END_EVENT_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.OR_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_META_DATA_FORMAT_ERROR;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_UNKNOW_NODE_TYPE;
|
||||
import static org.flowable.bpmn.model.ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION;
|
||||
@ -154,8 +172,7 @@ public class BpmTransformUtil {
|
||||
return createExclusiveGatewayBuilder(fromId, flowNode, process, bpmnModel, sequenceFlows, childNodeMap);
|
||||
} else if (BpmnFlowNodeType.NODE_TASK.isEqual(nodeType)) {
|
||||
childNodeMap.put(flowNode.getId(), flowNode);
|
||||
Map incoming = flowNode.getIncoming();
|
||||
incoming.put("incoming", Collections.singletonList(fromId));
|
||||
flowNode.setIncoming(Collections.singletonList(fromId));
|
||||
String id = createTask(process, flowNode, sequenceFlows, childNodeMap);
|
||||
// 如果当前任务还有后续任务,则遍历创建后续任务
|
||||
BpmnJsonNode children = flowNode.getChildren();
|
||||
@ -166,8 +183,7 @@ public class BpmTransformUtil {
|
||||
}
|
||||
} else if (BpmnFlowNodeType.NODE_STARTER.isEqual(nodeType)) {
|
||||
childNodeMap.put(flowNode.getId(), flowNode);
|
||||
Map incoming = flowNode.getIncoming();
|
||||
incoming.put("incoming", Collections.singletonList(fromId));
|
||||
flowNode.setIncoming(Collections.singletonList(fromId));
|
||||
String id = createTask(process, flowNode, sequenceFlows, childNodeMap);
|
||||
// 如果当前任务还有后续任务,则遍历创建后续任务
|
||||
BpmnJsonNode children = flowNode.getChildren();
|
||||
@ -236,8 +252,7 @@ public class BpmTransformUtil {
|
||||
continue;
|
||||
}
|
||||
// 只生成一个任务,同时设置当前任务的条件
|
||||
Map incomingObj = children.getIncoming();
|
||||
incomingObj.put("incoming", Collections.singletonList(exclusiveGatewayId));
|
||||
children.setIncoming(Collections.singletonList(exclusiveGatewayId));
|
||||
String identifier = create(exclusiveGatewayId, children, process, bpmnModel, sequenceFlows, childNodeMap);
|
||||
List<SequenceFlow> flows = sequenceFlows.stream().filter(flow -> StringUtils.equals(exclusiveGatewayId,
|
||||
flow.getSourceRef()))
|
||||
@ -273,9 +288,8 @@ public class BpmTransformUtil {
|
||||
return create(exclusiveGatewayId, childNode, process, bpmnModel, sequenceFlows,
|
||||
childNodeMap);
|
||||
} else {
|
||||
Map incomingObj = childNode.getIncoming();
|
||||
// 所有 service task 连接 end exclusive gateway
|
||||
incomingObj.put("incoming", incoming);
|
||||
childNode.setIncoming(incoming);
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(incoming.get(0));
|
||||
// 1.0 先进行边连接, 暂存 nextNode
|
||||
BpmnJsonNode nextNode = childNode.getChildren();
|
||||
@ -332,8 +346,7 @@ public class BpmTransformUtil {
|
||||
|
||||
private static String createTask(Process process, BpmnJsonNode flowNode, List<SequenceFlow> sequenceFlows,
|
||||
Map<String, BpmnJsonNode> childNodeMap) {
|
||||
Map incomingJson = flowNode.getIncoming();
|
||||
List<String> incoming = (List<String>) incomingJson.get("incoming");
|
||||
List<String> incoming = flowNode.getIncoming();
|
||||
// 自动生成id
|
||||
// String id = id("serviceTask");
|
||||
String id = flowNode.getId();
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnFieldConf;
|
||||
@ -51,6 +52,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -82,6 +84,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.START_EVENT_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_NOTICE_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_PENDING_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_SMS_MESSAGE_ID;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CONDITION;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_COMMON_ERROR;
|
||||
|
||||
@ -96,19 +99,21 @@ public final class BpmnJsonConverterUtil {
|
||||
}
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BpmnJsonConverterUtil.class);
|
||||
private static Map<Class<? extends BaseElement>, AbstractBpmnJsonConverter<? extends BaseElement>> converters =
|
||||
private static final Map<Class<? extends BaseElement>, AbstractBpmnJsonConverter<? extends BaseElement>> CONVERTERS =
|
||||
new HashMap<>();
|
||||
private static final Map<String, BpmnJsonNode> FLAT_NODE_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
converters.put(StartEvent.class, new StartEventJsonConverter());
|
||||
converters.put(SequenceFlow.class, new SequenceFlowJsonConverter());
|
||||
converters.put(EndEvent.class, new EndEventJsonConverter());
|
||||
CONVERTERS.put(NotSupportConverter.NotSupportFlowElement.class, new NotSupportConverter());
|
||||
CONVERTERS.put(StartEvent.class, new StartEventJsonConverter());
|
||||
CONVERTERS.put(SequenceFlow.class, new SequenceFlowJsonConverter());
|
||||
CONVERTERS.put(EndEvent.class, new EndEventJsonConverter());
|
||||
|
||||
converters.put(ExclusiveGateway.class, new ExclusiveGatewayJsonConverter());
|
||||
converters.put(ParallelGateway.class, new ParallelGatewayJsonConverter());
|
||||
converters.put(UserTask.class, new UserTaskJsonConverter());
|
||||
converters.put(ServiceTask.class, new ServiceTaskJsonConverter());
|
||||
converters.put(ReceiveTask.class, new ReceiveTaskJsonConverter());
|
||||
CONVERTERS.put(ExclusiveGateway.class, new ExclusiveGatewayJsonConverter());
|
||||
CONVERTERS.put(ParallelGateway.class, new ParallelGatewayJsonConverter());
|
||||
CONVERTERS.put(UserTask.class, new UserTaskJsonConverter());
|
||||
CONVERTERS.put(ServiceTask.class, new ServiceTaskJsonConverter());
|
||||
CONVERTERS.put(ReceiveTask.class, new ReceiveTaskJsonConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -338,11 +343,9 @@ public final class BpmnJsonConverterUtil {
|
||||
*/
|
||||
private static String create(BpmnJsonNode bpmnJsonNode, Process mainProcess,
|
||||
BpmnModel bpmnModel, String... preNodeIds) {
|
||||
FLAT_NODE_MAP.put(bpmnJsonNode.getId(), bpmnJsonNode);
|
||||
// 设置来源节点
|
||||
Map<String, List<String>> incoming = bpmnJsonNode.getIncoming();
|
||||
List<String> preNodeIdList = Lists.newArrayList(preNodeIds);
|
||||
incoming.put("incoming", preNodeIdList);
|
||||
bpmnJsonNode.setIncoming(incoming);
|
||||
bpmnJsonNode.setIncoming(Lists.newArrayList(preNodeIds));
|
||||
|
||||
Class<? extends BaseElement> clz;
|
||||
switch (bpmnJsonNode.getType()) {
|
||||
@ -358,6 +361,7 @@ public final class BpmnJsonConverterUtil {
|
||||
clz = ParallelGateway.class;
|
||||
break;
|
||||
case NODE_CONDITION:
|
||||
// 这个节点非常特殊,整个协议转换完全不会走到这里
|
||||
clz = SequenceFlow.class;
|
||||
break;
|
||||
case NODE_BUSINESS:
|
||||
@ -365,7 +369,7 @@ public final class BpmnJsonConverterUtil {
|
||||
// 一种是: 可以不配置人, 当运行到该节点时, 需要由外部发送信号来触发(这个信号的发送方通常是程序应用), 流程继续运行.
|
||||
// 另外一种是: 可以配置人, 当运行到该节点时, 有需要人为来处理. 这种情况下, 该节点就是一个普通的任务节点.
|
||||
clz = ReceiveTask.class;
|
||||
if (!Objects.equals("nobody", bpmnJsonNode.getProperty().getApprovalMethod())) {
|
||||
if (!Objects.equals(ApprovalMethodEnum.nobody, bpmnJsonNode.getProperty().getApprovalMethod())) {
|
||||
clz = UserTask.class;
|
||||
}
|
||||
break;
|
||||
@ -376,49 +380,49 @@ public final class BpmnJsonConverterUtil {
|
||||
clz = ServiceTask.class;
|
||||
break;
|
||||
default:
|
||||
clz = UserTask.class;
|
||||
clz = NotSupportConverter.NotSupportFlowElement.class;
|
||||
break;
|
||||
}
|
||||
|
||||
// 根据 BpmnJsonNode 创建节点
|
||||
FlowElement flowElement = convertJsonToElement(clz, bpmnJsonNode, mainProcess);
|
||||
mainProcess.addFlowElement(flowElement);
|
||||
// 通用链接当前节点和前一个节点的 SequenceFlow
|
||||
if (preNodeIdList.size() > 1) {
|
||||
// 如果涉及到网关,那么 incoming 就是大于 1
|
||||
preNodeIdList.stream()
|
||||
// 过滤掉自己
|
||||
.filter(income -> !Objects.equals(bpmnJsonNode.getId(), income))
|
||||
.forEach(income -> {
|
||||
Map<String, List<String>> tmpIncomeMap = new HashMap<>();
|
||||
tmpIncomeMap.put("incoming", Lists.newArrayList(income));
|
||||
bpmnJsonNode.setIncoming(tmpIncomeMap);
|
||||
|
||||
if (Lists.newArrayList(preNodeIds).isEmpty()) {
|
||||
// first time entrance, nothing to do.
|
||||
} else if (Lists.newArrayList(preNodeIds).size() == 1 && !NODE_CONDITION.equals(bpmnJsonNode.getType())) {
|
||||
mainProcess.addFlowElement(convertJsonToElement(SequenceFlow.class, bpmnJsonNode, mainProcess));
|
||||
});
|
||||
} else {
|
||||
// 网关的 SequenceFlow, 需要在这里设置网关的 DefaultFlow, 同时也需要解析这些 SequenceFlow 的条件
|
||||
Arrays.stream(preNodeIds).forEach(income -> {
|
||||
bpmnJsonNode.setIncoming(Lists.newArrayList(income));
|
||||
FlowElement sequenceFlow = convertJsonToElement(SequenceFlow.class, bpmnJsonNode, mainProcess);
|
||||
mainProcess.addFlowElement(sequenceFlow);
|
||||
|
||||
String preNodeId = preNodeIds[0];
|
||||
FlowElement preFlowNode;
|
||||
if (Objects.nonNull(preFlowNode = mainProcess.getFlowElement(preNodeId, true))
|
||||
&& preFlowNode instanceof Gateway) {
|
||||
BpmnJsonNode preJsonNode = bpmnJsonNode.getPreJsonNode();
|
||||
if (Boolean.TRUE.equals(preJsonNode.getProperty().getDefaultBranch())) {
|
||||
Gateway gateway = (Gateway) preFlowNode;
|
||||
gateway.setDefaultFlow(sequenceFlow.getId());
|
||||
}
|
||||
}
|
||||
setDefaultFlow(bpmnJsonNode, mainProcess, sequenceFlow);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// 只有网关才会涉及到 branch
|
||||
List<String> gatewayPreIds = new ArrayList<>();
|
||||
List<String> conditions = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(bpmnJsonNode.getBranches())) {
|
||||
for (BpmnJsonNode branch : bpmnJsonNode.getBranches()) {
|
||||
BpmnJsonNode children = Objects.isNull(branch.getChildren()) ? bpmnJsonNode.getChildren() :
|
||||
branch.getChildren();
|
||||
if (Objects.nonNull(children)) {
|
||||
children.setPreJsonNode(branch);
|
||||
gatewayPreIds.add(create(children, mainProcess, bpmnModel, flowElement.getId()));
|
||||
|
||||
// branch == node_condition
|
||||
if (Objects.nonNull(branch.getChildren())) {
|
||||
conditions.add(create(branch.getChildren(), mainProcess, bpmnModel, flowElement.getId()));
|
||||
} else {
|
||||
bpmnJsonNode.getChildren().setIncoming(Lists.newArrayList(bpmnJsonNode.getId()));
|
||||
FlowElement sequenceFlow = convertJsonToElement(SequenceFlow.class, bpmnJsonNode.getChildren(),
|
||||
mainProcess);
|
||||
mainProcess.addFlowElement(sequenceFlow);
|
||||
|
||||
// 判断这个是不是默认流
|
||||
if (Objects.nonNull(branch.getProperty()) && Boolean.TRUE.equals(branch.getProperty().getDefaultBranch())) {
|
||||
Gateway gateway = (Gateway) flowElement;
|
||||
gateway.setDefaultFlow(sequenceFlow.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -428,11 +432,26 @@ public final class BpmnJsonConverterUtil {
|
||||
if (Objects.isNull(children) || Objects.equals(NODE_EMPTY, children.getType()) || !StringUtils.hasLength(children.getId())) {
|
||||
return flowElement.getId();
|
||||
} else {
|
||||
String[] preIds = new String[]{flowElement.getId()};
|
||||
if (!CollectionUtils.isEmpty(gatewayPreIds)) {
|
||||
preIds = gatewayPreIds.toArray(new String[0]);
|
||||
if (!CollectionUtils.isEmpty(conditions)) {
|
||||
// 由于不是通过 create 方法解析 node_condition, 所以单独用一个字段来传递它
|
||||
children.setPreJsonNode(bpmnJsonNode);
|
||||
return create(children, mainProcess, bpmnModel, conditions.toArray(new String[0]));
|
||||
}
|
||||
return create(children, mainProcess, bpmnModel, flowElement.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private static void setDefaultFlow(BpmnJsonNode bpmnJsonNode, Process mainProcess, FlowElement sequenceFlow) {
|
||||
// 查找并设置网关的默认流
|
||||
if (Objects.nonNull(bpmnJsonNode.getPreJsonNode()) && Objects.nonNull(bpmnJsonNode.getPreJsonNode().getProperty())
|
||||
&& Boolean.TRUE.equals(bpmnJsonNode.getPreJsonNode().getProperty().getDefaultBranch())) {
|
||||
FlowElement preFlowNode;
|
||||
if (Objects.nonNull(preFlowNode =
|
||||
mainProcess.getFlowElement(bpmnJsonNode.getPreJsonNode().getId(), true))
|
||||
&& preFlowNode instanceof Gateway) {
|
||||
Gateway gateway = (Gateway) preFlowNode;
|
||||
gateway.setDefaultFlow(sequenceFlow.getId());
|
||||
}
|
||||
return create(children, mainProcess, bpmnModel, preIds);
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +462,7 @@ public final class BpmnJsonConverterUtil {
|
||||
|
||||
private static FlowElement convertJsonToElement(Class<? extends BaseElement> clz, BpmnJsonNode bpmnJsonNode,
|
||||
Process process) {
|
||||
AbstractBpmnJsonConverter converter = converters.getOrDefault(clz, new NotSupportConverter());
|
||||
AbstractBpmnJsonConverter converter = CONVERTERS.getOrDefault(clz, new NotSupportConverter());
|
||||
FlowElement flowElement = converter.convertJsonToElement(bpmnJsonNode, process);
|
||||
if (Objects.nonNull(bpmnJsonNode)) {
|
||||
converter.addNodeTypeAttribute(flowElement, copy(bpmnJsonNode));
|
||||
|
||||
@ -3,9 +3,6 @@ package cn.axzo.workflow.core.converter.json;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
|
||||
import org.flowable.bpmn.model.ExclusiveGateway;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 排它网关
|
||||
@ -20,19 +17,8 @@ public class ExclusiveGatewayJsonConverter extends AbstractBpmnJsonConverter<Exc
|
||||
ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
|
||||
exclusiveGateway.setId(node.getId());
|
||||
exclusiveGateway.setName(node.getName());
|
||||
if ((Objects.isNull(node.getChildren()) || !StringUtils.hasLength(node.getId()))
|
||||
&& Objects.isNull(node.getBranches())) {
|
||||
return exclusiveGateway;
|
||||
}
|
||||
// 条件分支, 只有一个默认流
|
||||
// if (!CollectionUtils.isEmpty(node.getBranches())) {
|
||||
// node.getBranches().forEach(branch -> {
|
||||
// BpmnJsonNodeProperty property = branch.getProperty();
|
||||
// if (Boolean.TRUE.equals(property.getDefaultCondition())) {
|
||||
// exclusiveGateway.setDefaultFlow(branch.getId());
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
return exclusiveGateway;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -13,10 +13,17 @@ import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_NODE_TY
|
||||
* @author wangli
|
||||
* @since 2023/10/13 15:13
|
||||
*/
|
||||
public class NotSupportConverter extends AbstractBpmnJsonConverter {
|
||||
public class NotSupportConverter extends AbstractBpmnJsonConverter<NotSupportConverter.NotSupportFlowElement> {
|
||||
|
||||
@Override
|
||||
public FlowElement convertJsonToElement(BpmnJsonNode node, Process process) {
|
||||
public NotSupportFlowElement convertJsonToElement(BpmnJsonNode node, Process process) {
|
||||
throw new WorkflowEngineException(CONVERTOR_NODE_TYPE_NOT_SUPPORT, node.getType().getType(), node.getId());
|
||||
}
|
||||
|
||||
public static class NotSupportFlowElement extends FlowElement {
|
||||
@Override
|
||||
public FlowElement clone() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ public class SequenceFlowJsonConverter extends AbstractBpmnJsonConverter<Sequenc
|
||||
|
||||
@Override
|
||||
public SequenceFlow convertJsonToElement(BpmnJsonNode node, Process process) {
|
||||
List<String> incoming = node.getIncoming().get("incoming");
|
||||
List<String> incoming = node.getIncoming();
|
||||
SequenceFlow sequenceFlow = new SequenceFlow();
|
||||
sequenceFlow.setId(id(SEQUENCE_FLOW_ID));
|
||||
sequenceFlow.setSourceRef(incoming.get(0));
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user