package jnpf.workflow.flowable.util; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import org.flowable.bpmn.model.EndEvent; import org.flowable.bpmn.model.FlowElement; import org.flowable.bpmn.model.FlowNode; import org.flowable.bpmn.model.Gateway; import org.flowable.bpmn.model.SequenceFlow; import org.flowable.bpmn.model.StartEvent; import org.flowable.bpmn.model.SubProcess; import org.flowable.bpmn.model.UserTask; import cn.hutool.core.collection.CollectionUtil; import jnpf.workflow.common.model.vo.FlowVo; /** * BPMN 拓扑推导工具(back/jump/next/prev 等接口的核心)。 * 由黑盒 jar 反编译逐行保真还原,勿做"顺手优化"。 */ public class FlowableUtil { public static Collection getAllElements(Collection flowElements, Collection allElements) { allElements = allElements == null ? new ArrayList<>() : allElements; for (FlowElement flowElement : flowElements) { allElements.add(flowElement); if (!(flowElement instanceof SubProcess)) { continue; } allElements = getAllElements(((SubProcess) flowElement).getFlowElements(), allElements); } return allElements; } public static List getElementIncomingFlows(FlowElement element) { List flows = null; if (element instanceof FlowNode) { flows = ((FlowNode) element).getIncomingFlows(); } return flows; } public static List getElementOutgoingFlows(FlowElement element) { List flows = null; if (element instanceof FlowNode) { flows = ((FlowNode) element).getOutgoingFlows(); } return flows; } public static List getPassActs(FlowElement source, Set passFlows, List passActs) { passFlows = passFlows == null ? new HashSet<>() : passFlows; passActs = passActs == null ? new ArrayList<>() : passActs; List sequenceFlows = getElementIncomingFlows(source); if (null != sequenceFlows && !sequenceFlows.isEmpty()) { for (SequenceFlow sequenceFlow : sequenceFlows) { if (passFlows.contains(sequenceFlow.getId())) { continue; } passFlows.add(sequenceFlow.getId()); if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { passActs.add(sequenceFlow.getSourceFlowElement().getId()); } if (sequenceFlow.getSourceFlowElement() instanceof StartEvent) { passActs.add(sequenceFlow.getSourceFlowElement().getId()); continue; } getPassActs(sequenceFlow.getSourceFlowElement(), passFlows, passActs); } } return passActs; } public static List getChildUserTasks(FlowElement source, List runTaskKeyList, Set passFlows, List userTasks) { passFlows = passFlows == null ? new HashSet<>() : passFlows; userTasks = userTasks == null ? new ArrayList<>() : userTasks; List sequenceFlows = getElementOutgoingFlows(source); if (null != sequenceFlows && !sequenceFlows.isEmpty()) { for (SequenceFlow sequenceFlow : sequenceFlows) { if (passFlows.contains(sequenceFlow.getId())) { continue; } passFlows.add(sequenceFlow.getId()); if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains(sequenceFlow.getTargetFlowElement().getId())) { userTasks.add((UserTask) sequenceFlow.getTargetFlowElement()); continue; } if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { FlowElement flowElement = (FlowElement) ((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]; List tasks = getChildUserTasks(flowElement, runTaskKeyList, passFlows, null); if (!tasks.isEmpty()) { userTasks.addAll(tasks); continue; } } getChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, passFlows, userTasks); } } return userTasks; } public static List getParentActs(FlowElement source, Set passFlows, List parentActs) { passFlows = passFlows == null ? new HashSet<>() : passFlows; parentActs = parentActs == null ? new ArrayList<>() : parentActs; List sequenceFlows = getElementIncomingFlows(source); if (null != sequenceFlows && !sequenceFlows.isEmpty()) { for (SequenceFlow sequenceFlow : sequenceFlows) { if (passFlows.contains(sequenceFlow.getId())) { continue; } passFlows.add(sequenceFlow.getId()); if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { parentActs.add(sequenceFlow.getSourceFlowElement().getId()); continue; } if (sequenceFlow.getSourceFlowElement() instanceof StartEvent) { parentActs.add(sequenceFlow.getSourceFlowElement().getId()); continue; } getParentActs(sequenceFlow.getSourceFlowElement(), passFlows, parentActs); } } return parentActs; } public static List getNextUserTasks(FlowElement source, Set hasSequenceFlow, List userTaskList) { hasSequenceFlow = Optional.ofNullable(hasSequenceFlow).orElse(new HashSet<>()); userTaskList = Optional.ofNullable(userTaskList).orElse(new ArrayList<>()); List sequenceFlows = getElementOutgoingFlows(source); if (null != sequenceFlows) { for (SequenceFlow sequenceFlow : sequenceFlows) { if (hasSequenceFlow.contains(sequenceFlow.getId())) { continue; } hasSequenceFlow.add(sequenceFlow.getId()); FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement(); if (targetFlowElement instanceof UserTask) { userTaskList.add((UserTask) targetFlowElement); continue; } getNextUserTasks(targetFlowElement, hasSequenceFlow, userTaskList); } } return userTaskList; } public static List getAfter(FlowElement source, Set hasSequenceFlow, List list) { hasSequenceFlow = Optional.ofNullable(hasSequenceFlow).orElse(new HashSet<>()); list = Optional.ofNullable(list).orElse(new ArrayList<>()); List sequenceFlows = getElementOutgoingFlows(source); if (null != sequenceFlows) { for (SequenceFlow sequenceFlow : sequenceFlows) { if (hasSequenceFlow.contains(sequenceFlow.getId())) { continue; } hasSequenceFlow.add(sequenceFlow.getId()); FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement(); if (targetFlowElement instanceof UserTask) { list.add(targetFlowElement.getId()); } else if (targetFlowElement instanceof EndEvent) { list.add(targetFlowElement.getId()); continue; } getAfter(targetFlowElement, hasSequenceFlow, list); } } return list; } public static List getOutFlowsWithGateway(FlowElement source, List flows) { flows = flows == null ? new ArrayList<>() : flows; List sequenceFlows = getElementOutgoingFlows(source); if (null != sequenceFlows) { for (SequenceFlow sequenceFlow : sequenceFlows) { flows.add(sequenceFlow); FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement(); if (targetFlowElement instanceof UserTask || !(targetFlowElement instanceof Gateway)) { continue; } Gateway gateway = (Gateway) targetFlowElement; List outgoingFlows = gateway.getOutgoingFlows(); flows.addAll(outgoingFlows); getOutFlowsWithGateway(gateway, flows); } } return flows; } public static List getOutFlows(FlowElement source, List flows) { flows = flows == null ? new ArrayList<>() : flows; List sequenceFlows = getElementOutgoingFlows(source); if (null != sequenceFlows) { for (SequenceFlow sequenceFlow : sequenceFlows) { FlowVo vo = new FlowVo(); vo.setKey(sequenceFlow.getId()); FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement(); if (targetFlowElement instanceof Gateway) { Gateway gateway = (Gateway) targetFlowElement; List list = getOutFlows(gateway, null); vo.setChildren(list); } flows.add(vo); } } return flows; } public static List getBefore(FlowElement source, Set passFlows, List keys) { passFlows = passFlows == null ? new HashSet<>() : passFlows; keys = keys == null ? new ArrayList<>() : keys; List sequenceFlows = getElementIncomingFlows(source); if (null != sequenceFlows && !sequenceFlows.isEmpty()) { for (SequenceFlow sequenceFlow : sequenceFlows) { if (passFlows.contains(sequenceFlow.getId())) { continue; } passFlows.add(sequenceFlow.getId()); keys.add(sequenceFlow.getSourceFlowElement().getId()); if (sequenceFlow.getSourceFlowElement() instanceof StartEvent) { continue; } getBefore(sequenceFlow.getSourceFlowElement(), passFlows, keys); } } return keys; } public static String getTaskKeyAfterFlow(FlowElement source) { if (source instanceof SequenceFlow) { SequenceFlow sequenceFlow = (SequenceFlow) source; FlowElement target = sequenceFlow.getTargetFlowElement(); if (target instanceof Gateway) { List outgoingFlows = ((Gateway) target).getOutgoingFlows(); if (CollectionUtil.isNotEmpty(outgoingFlows)) { SequenceFlow flow = outgoingFlows.get(0); return getTaskKeyAfterFlow(flow); } } if (target instanceof UserTask) { return target.getId(); } } return null; } }