// TODO - change the return type and the factory parameter to be Definitions and ObjectFactory, // and move to bpmn-schema public BpmnDefinitions correctFlowNodeRefs( final BpmnDefinitions definitions, final BpmnObjectFactory factory) throws JAXBException, TransformerException { JAXBContext context = JAXBContext.newInstance( factory.getClass(), com.processconfiguration.ObjectFactory.class, org.omg.spec.bpmn._20100524.di.ObjectFactory.class, org.omg.spec.bpmn._20100524.model.ObjectFactory.class, org.omg.spec.dd._20100524.dc.ObjectFactory.class, org.omg.spec.dd._20100524.di.ObjectFactory.class, com.signavio.ObjectFactory.class); // Marshal the BPMN into a DOM tree DOMResult intermediateResult = new DOMResult(); Marshaller marshaller = context.createMarshaller(); marshaller.marshal(factory.createDefinitions(definitions), intermediateResult); // Apply the XSLT transformation, generating a new DOM tree TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer( new StreamSource( getClass().getClassLoader().getResourceAsStream("xsd/fix-flowNodeRef.xsl"))); DOMSource finalSource = new DOMSource(intermediateResult.getNode()); DOMResult finalResult = new DOMResult(); transformer.transform(finalSource, finalResult); // Unmarshal back to JAXB Object def2 = context.createUnmarshaller().unmarshal(finalResult.getNode()); return ((JAXBElement<BpmnDefinitions>) def2).getValue(); }
private void rewriteFlowElements(List<JAXBElement<? extends TFlowElement>> jfel) throws CanoniserException { for (JAXBElement<? extends TFlowElement> flowElement : new ArrayList<JAXBElement<? extends TFlowElement>>(jfel)) { if (flowElement.getValue() instanceof TFlowNode && !(flowElement.getValue() instanceof TGateway)) { TFlowNode flowNode = (TFlowNode) flowElement.getValue(); if (flowNode.getIncoming().size() > 1) { // Create a converging XOR gateway BpmnObjectFactory factory = new BpmnObjectFactory(); TExclusiveGateway xor = factory.createTExclusiveGateway(); xor.setId(flowNode.getId() + "_implicit_join"); xor.setGatewayDirection(TGatewayDirection.CONVERGING); jfel.add(factory.createExclusiveGateway(xor)); // Retarget the incoming flows to the XOR gateway for (QName incoming : flowNode.getIncoming()) { BpmnSequenceFlow incomingFlow = (BpmnSequenceFlow) findElement(incoming); incomingFlow.setTargetRef(xor); } xor.getIncoming().addAll(flowNode.getIncoming()); flowNode.getIncoming().clear(); // Create a flow from the XOR gateway to the flow node BpmnSequenceFlow flow = factory.createTSequenceFlow(); flow.setId( flowNode.getId() + "_implicit_join_edge"); // TODO - should use IdFactory to ward against clashes flow.setSourceRef(xor); flow.setTargetRef(flowNode); jfel.add(factory.createSequenceFlow(flow)); QName flowQName = new QName(targetNamespace, flow.getId()); flowNode.getIncoming().add(flowQName); xor.getOutgoing().add(flowQName); } if (flowNode.getOutgoing().size() > 1) { // Create a diverging AND gateway BpmnObjectFactory factory = new BpmnObjectFactory(); TParallelGateway and = factory.createTParallelGateway(); and.setId(flowNode.getId() + "_implicit_split"); and.setGatewayDirection(TGatewayDirection.DIVERGING); jfel.add(factory.createParallelGateway(and)); // Change the source of the outgoing flows to be from the AND gateway for (QName outgoing : flowNode.getOutgoing()) { BpmnSequenceFlow outgoingFlow = (BpmnSequenceFlow) findElement(outgoing); outgoingFlow.setSourceRef(and); } and.getOutgoing().addAll(flowNode.getOutgoing()); flowNode.getOutgoing().clear(); // Create a flow to the AND gateway from the flow node BpmnSequenceFlow flow = factory.createTSequenceFlow(); flow.setId( flowNode.getId() + "_implicit_split_edge"); // TODO - should use IdFactory to ward against clashes flow.setSourceRef(flowNode); flow.setTargetRef(and); jfel.add(factory.createSequenceFlow(flow)); QName flowQName = new QName(targetNamespace, flow.getId()); flowNode.getOutgoing().add(flowQName); and.getIncoming().add(flowQName); } // Recursively rewrite any subprocesses if (flowNode instanceof TSubProcess) { rewriteFlowElements(((TSubProcess) flowNode).getFlowElement()); } } // Rewrite mixed gateways if (flowElement.getValue() instanceof TGateway) { TGateway gateway = (TGateway) flowElement.getValue(); if (gateway.getIncoming().size() > 1 && gateway.getOutgoing().size() > 1) { // Create a diverging XOR gateway BpmnObjectFactory factory = new BpmnObjectFactory(); TGateway newGateway; if (gateway instanceof TComplexGateway) { newGateway = factory.createTComplexGateway(); jfel.add(factory.createComplexGateway((TComplexGateway) newGateway)); } else if (gateway instanceof TEventBasedGateway) { newGateway = factory.createTEventBasedGateway(); jfel.add(factory.createEventBasedGateway((TEventBasedGateway) newGateway)); } else if (gateway instanceof TExclusiveGateway) { newGateway = factory.createTExclusiveGateway(); jfel.add(factory.createExclusiveGateway((TExclusiveGateway) newGateway)); } else if (gateway instanceof TInclusiveGateway) { newGateway = factory.createTInclusiveGateway(); jfel.add(factory.createInclusiveGateway((TInclusiveGateway) newGateway)); } else if (gateway instanceof TParallelGateway) { newGateway = factory.createTParallelGateway(); jfel.add(factory.createParallelGateway((TParallelGateway) newGateway)); } else { throw new CanoniserException( "Mixed gateway " + gateway.getId() + " of type " + gateway.getClass() + " unsupported"); } assert newGateway != null; newGateway.setId(gateway.getId() + "_mixed_split"); newGateway.setGatewayDirection(TGatewayDirection.DIVERGING); // Re-source the outgoing flows from the diverging gateway for (QName outgoing : gateway.getOutgoing()) { BpmnSequenceFlow outgoingFlow = (BpmnSequenceFlow) findElement(outgoing); outgoingFlow.setSourceRef(newGateway); } gateway.setGatewayDirection(TGatewayDirection.CONVERGING); gateway.getOutgoing().clear(); // Create a flow from the original (now converging) gateway to the new diverging gateway BpmnSequenceFlow flow = factory.createTSequenceFlow(); flow.setId(gateway.getId() + "_mixed_edge"); flow.setSourceRef(gateway); flow.setTargetRef(newGateway); jfel.add(factory.createSequenceFlow(flow)); QName flowQName = new QName(targetNamespace, flow.getId()); newGateway.getIncoming().add(flowQName); gateway.getOutgoing().add(flowQName); } } } }