¶Ô±ÈÐÂÎļþ |
| | |
| | | package org.dromara.workflow.utils; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.collection.CollectionUtil; |
| | | import cn.hutool.core.io.IoUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.AccessLevel; |
| | | import lombok.NoArgsConstructor; |
| | | import org.dromara.common.core.utils.SpringUtils; |
| | | import org.dromara.common.core.utils.StreamUtils; |
| | | import org.dromara.common.core.utils.StringUtils; |
| | | import org.dromara.common.json.utils.JsonUtils; |
| | | import org.dromara.workflow.domain.vo.MultiInstanceVo; |
| | | import org.flowable.bpmn.converter.BpmnXMLConverter; |
| | | import org.flowable.bpmn.model.*; |
| | | import org.flowable.bpmn.model.Process; |
| | | import org.flowable.editor.language.json.converter.BpmnJsonConverter; |
| | | import org.flowable.engine.ProcessEngine; |
| | | |
| | | import javax.xml.stream.XMLInputFactory; |
| | | import javax.xml.stream.XMLStreamException; |
| | | import javax.xml.stream.XMLStreamReader; |
| | | import java.io.ByteArrayInputStream; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.rmi.ServerException; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 模åå·¥å
· |
| | | * |
| | | * @author may |
| | | */ |
| | | @NoArgsConstructor(access = AccessLevel.PRIVATE) |
| | | public class ModelUtils { |
| | | |
| | | private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class); |
| | | |
| | | public static BpmnModel xmlToBpmnModel(String xml) throws IOException { |
| | | if (xml == null) { |
| | | throw new ServerException("xmlä¸è½ä¸ºç©º"); |
| | | } |
| | | try { |
| | | InputStream inputStream = new ByteArrayInputStream(StrUtil.utf8Bytes(xml)); |
| | | XMLInputFactory factory = XMLInputFactory.newInstance(); |
| | | XMLStreamReader reader = factory.createXMLStreamReader(inputStream); |
| | | return new BpmnXMLConverter().convertToBpmnModel(reader); |
| | | } catch (XMLStreamException e) { |
| | | throw new ServerException(e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * bpmnModel转为xml |
| | | * |
| | | * @param jsonBytes json |
| | | */ |
| | | public static byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException { |
| | | if (jsonBytes == null) { |
| | | return new byte[0]; |
| | | } |
| | | // 1. jsonåèç 转æ BpmnModel 对象 |
| | | ObjectMapper objectMapper = JsonUtils.getObjectMapper(); |
| | | JsonNode jsonNode = objectMapper.readTree(jsonBytes); |
| | | BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode); |
| | | |
| | | if (bpmnModel.getProcesses().isEmpty()) { |
| | | return new byte[0]; |
| | | } |
| | | // 2.å°bpmnModel转为xml |
| | | return new BpmnXMLConverter().convertToXML(bpmnModel); |
| | | } |
| | | |
| | | /** |
| | | * xml转为bpmnModel |
| | | * |
| | | * @param xmlBytes xml |
| | | */ |
| | | public static BpmnModel xmlToBpmnModel(byte[] xmlBytes) throws XMLStreamException { |
| | | ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(xmlBytes); |
| | | XMLInputFactory xif = XMLInputFactory.newInstance(); |
| | | XMLStreamReader xtr = xif.createXMLStreamReader(byteArrayInputStream); |
| | | return new BpmnXMLConverter().convertToBpmnModel(xtr); |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªæ¨¡å |
| | | * |
| | | * @param bpmnModel bpmn模å |
| | | */ |
| | | public static void checkBpmnModel(BpmnModel bpmnModel) throws ServerException { |
| | | Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements(); |
| | | |
| | | checkBpmnNode(flowElements, false); |
| | | |
| | | List<SubProcess> subProcessList = flowElements.stream().filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList()); |
| | | if (!CollUtil.isEmpty(subProcessList)) { |
| | | for (SubProcess subProcess : subProcessList) { |
| | | Collection<FlowElement> subProcessFlowElements = subProcess.getFlowElements(); |
| | | checkBpmnNode(subProcessFlowElements, true); |
| | | } |
| | | } |
| | | List<MultiInstanceVo> multiInstanceVoList = new ArrayList<>(); |
| | | for (FlowElement flowElement : flowElements) { |
| | | if (flowElement instanceof UserTask && ObjectUtil.isNotEmpty(((UserTask) flowElement).getLoopCharacteristics()) && StringUtils.isNotBlank(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem())) { |
| | | MultiInstanceVo multiInstanceVo = new MultiInstanceVo(); |
| | | multiInstanceVo.setAssigneeList(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem()); |
| | | multiInstanceVoList.add(multiInstanceVo); |
| | | } |
| | | } |
| | | |
| | | if (CollectionUtil.isNotEmpty(multiInstanceVoList) && multiInstanceVoList.size() > 1) { |
| | | Map<String, List<MultiInstanceVo>> assigneeListGroup = StreamUtils.groupByKey(multiInstanceVoList, MultiInstanceVo::getAssigneeList); |
| | | for (Map.Entry<String, List<MultiInstanceVo>> entry : assigneeListGroup.entrySet()) { |
| | | List<MultiInstanceVo> value = entry.getValue(); |
| | | if (CollectionUtil.isNotEmpty(value) && value.size() > 1) { |
| | | String key = entry.getKey(); |
| | | throw new ServerException("ä¼ç¾äººåéåã" + key + "ãéå¤,è¯·éæ°è®¾ç½®éåKEY"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ ¡éªbpmnèç¹æ¯å¦åæ³ |
| | | * |
| | | * @param flowElements èç¹éå |
| | | * @param subtask æ¯å¦åæµç¨ |
| | | */ |
| | | private static void checkBpmnNode(Collection<FlowElement> flowElements, boolean subtask) throws ServerException { |
| | | |
| | | if (CollUtil.isEmpty(flowElements)) { |
| | | throw new ServerException(subtask ? "åæµç¨å¿
é¡»åå¨èç¹" : "å¿
é¡»åå¨èç¹ï¼"); |
| | | } |
| | | |
| | | List<StartEvent> startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList()); |
| | | if (CollUtil.isEmpty(startEventList)) { |
| | | throw new ServerException(subtask ? "åæµç¨å¿
é¡»åå¨å¼å§èç¹" : "å¿
é¡»åå¨å¼å§èç¹ï¼"); |
| | | } |
| | | |
| | | if (startEventList.size() > 1) { |
| | | throw new ServerException(subtask ? "åæµç¨åªè½åå¨ä¸ä¸ªå¼å§èç¹" : "åªè½åå¨ä¸ä¸ªå¼å§èç¹ï¼"); |
| | | } |
| | | |
| | | StartEvent startEvent = startEventList.get(0); |
| | | List<SequenceFlow> outgoingFlows = startEvent.getOutgoingFlows(); |
| | | if (CollUtil.isEmpty(outgoingFlows)) { |
| | | throw new ServerException(subtask ? "åæµç¨æµç¨èç¹ä¸ºç©ºï¼è¯·è³å°è®¾è®¡ä¸æ¡ä¸»çº¿æµç¨ï¼" : "æµç¨èç¹ä¸ºç©ºï¼è¯·è³å°è®¾è®¡ä¸æ¡ä¸»çº¿æµç¨ï¼"); |
| | | } |
| | | |
| | | FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); |
| | | if (!(targetFlowElement instanceof UserTask) && !subtask) { |
| | | throw new ServerException("å¼å§èç¹å第ä¸ä¸ªèç¹å¿
é¡»æ¯ç¨æ·ä»»å¡ï¼"); |
| | | } |
| | | //å¼å§èç¹å第ä¸ä¸ªèç¹ç³è¯·äººèç¹ |
| | | if ((targetFlowElement instanceof UserTask) && !subtask) { |
| | | UserTask userTask = (UserTask) targetFlowElement; |
| | | if (StringUtils.isBlank(userTask.getFormKey())) { |
| | | throw new ServerException("ç³è¯·äººèç¹å¿
é¡»éæ©è¡¨åï¼"); |
| | | } |
| | | } |
| | | List<EndEvent> endEventList = flowElements.stream().filter(EndEvent.class::isInstance).map(EndEvent.class::cast).collect(Collectors.toList()); |
| | | if (CollUtil.isEmpty(endEventList)) { |
| | | throw new ServerException(subtask ? "åæµç¨å¿
é¡»åå¨ç»æèç¹ï¼" : "å¿
é¡»åå¨ç»æèç¹ï¼"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·åæµç¨å
¨é¨ç¨æ·èç¹ |
| | | * |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | */ |
| | | public static List<UserTask> getUserTaskFlowElements(String processDefinitionId) { |
| | | BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); |
| | | List<UserTask> list = new ArrayList<>(); |
| | | List<Process> processes = bpmnModel.getProcesses(); |
| | | Collection<FlowElement> flowElements = processes.get(0).getFlowElements(); |
| | | buildUserTaskFlowElements(flowElements, list); |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * éå½è·åææèç¹ |
| | | * |
| | | * @param flowElements èç¹ä¿¡æ¯ |
| | | * @param list éå |
| | | */ |
| | | private static void buildUserTaskFlowElements(Collection<FlowElement> flowElements, List<UserTask> list) { |
| | | for (FlowElement flowElement : flowElements) { |
| | | if (flowElement instanceof SubProcess) { |
| | | Collection<FlowElement> subFlowElements = ((SubProcess) flowElement).getFlowElements(); |
| | | buildUserTaskFlowElements(subFlowElements, list); |
| | | } else if (flowElement instanceof UserTask) { |
| | | list.add((UserTask) flowElement); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·åæµç¨å
¨é¨èç¹ |
| | | * |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | */ |
| | | public static List<FlowElement> getFlowElements(String processDefinitionId) { |
| | | BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); |
| | | List<FlowElement> list = new ArrayList<>(); |
| | | List<Process> processes = bpmnModel.getProcesses(); |
| | | Collection<FlowElement> flowElements = processes.get(0).getFlowElements(); |
| | | buildFlowElements(flowElements, list); |
| | | return list; |
| | | } |
| | | |
| | | /** |
| | | * éå½è·åææèç¹ |
| | | * |
| | | * @param flowElements èç¹ä¿¡æ¯ |
| | | * @param list éå |
| | | */ |
| | | private static void buildFlowElements(Collection<FlowElement> flowElements, List<FlowElement> list) { |
| | | for (FlowElement flowElement : flowElements) { |
| | | list.add(flowElement); |
| | | if (flowElement instanceof SubProcess) { |
| | | Collection<FlowElement> subFlowElements = ((SubProcess) flowElement).getFlowElements(); |
| | | buildFlowElements(subFlowElements, list); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·åå
¨é¨æ©å±ä¿¡æ¯ |
| | | * |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | */ |
| | | public static Map<String, List<ExtensionElement>> getExtensionElements(String processDefinitionId) { |
| | | Map<String, List<ExtensionElement>> map = new HashMap<>(); |
| | | List<FlowElement> flowElements = getFlowElements(processDefinitionId); |
| | | for (FlowElement flowElement : flowElements) { |
| | | if (flowElement instanceof UserTask && CollUtil.isNotEmpty(flowElement.getExtensionElements())) { |
| | | map.putAll(flowElement.getExtensionElements()); |
| | | } |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** |
| | | * è·åæä¸ªèç¹çæ©å±ä¿¡æ¯ |
| | | * |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @param flowElementId èç¹id |
| | | */ |
| | | public static Map<String, List<ExtensionElement>> getExtensionElement(String processDefinitionId, String flowElementId) { |
| | | BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); |
| | | Process process = bpmnModel.getMainProcess(); |
| | | FlowElement flowElement = process.getFlowElement(flowElementId); |
| | | return flowElement.getExtensionElements(); |
| | | } |
| | | |
| | | /** |
| | | * 夿å½åèç¹æ¯å¦ä¸ºç¨æ·ä»»å¡ |
| | | * |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @param taskDefinitionKey æµç¨å®ä¹id |
| | | */ |
| | | public static boolean isUserTask(String processDefinitionId, String taskDefinitionKey) { |
| | | BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); |
| | | FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey); |
| | | return flowNode instanceof UserTask; |
| | | } |
| | | |
| | | /** |
| | | * è·åç³è¯·äººèç¹ |
| | | * |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @return ç»æ |
| | | */ |
| | | public static UserTask getApplyUserTask(String processDefinitionId) { |
| | | BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId); |
| | | Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements(); |
| | | List<StartEvent> startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList()); |
| | | StartEvent startEvent = startEventList.get(0); |
| | | List<SequenceFlow> outgoingFlows = startEvent.getOutgoingFlows(); |
| | | FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement(); |
| | | return (UserTask) targetFlowElement; |
| | | } |
| | | } |