Sfoglia il codice sorgente

更新工作流模型导入带监听配置!

zdd 3 anni fa
parent
commit
93185f1c03

+ 5 - 0
pom.xml

@@ -176,6 +176,11 @@
             <artifactId>batik-svggen</artifactId>
             <version>${apache.xmlgraphics.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20210307</version>
+        </dependency>
 
     </dependencies>
 

+ 92 - 6
src/main/java/com/activiti6/controller/ModelerController.java

@@ -2,11 +2,17 @@ package com.activiti6.controller;
 
 import com.activiti6.controller.editor.ModelSaveRestResource;
 import com.activiti6.entity.AjaxEntityVo;
+import com.activiti6.entity.editor.ExecutionListeners;
 import com.activiti6.service.ModelService;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.sun.deploy.util.ArrayUtil;
 import org.activiti.bpmn.converter.BpmnXMLConverter;
+import org.activiti.bpmn.converter.MyBpmnXMLConverter;
 import org.activiti.bpmn.model.BpmnModel;
 import org.activiti.bpmn.model.Process;
 import org.activiti.editor.constants.ModelDataJsonConstants;
@@ -18,6 +24,8 @@ import org.activiti.engine.repository.Deployment;
 import org.activiti.engine.repository.Model;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.json.JSONObject;
+import org.json.XML;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -33,6 +41,8 @@ import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 import java.io.*;
 import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -276,21 +286,97 @@ public class ModelerController extends BaseController {
     @Autowired
     private ModelSaveRestResource modelSaveRestResource;
 
-    protected BpmnXMLConverter bpmnXmlConverter = new BpmnXMLConverter();
-
-    protected BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
-
     @ResponseBody
     @PostMapping("upload")
     public AjaxEntityVo importProcessModel(HttpServletRequest request, @RequestParam("file") MultipartFile file) {
         try {
             convertInputStreamToModel(file.getInputStream());
+            //convertInputStreamToModelNew(file);
         } catch (Exception e) {
             return error(e.getMessage());
         }
         return success();
     }
 
+    public void convertInputStreamToModelNew(MultipartFile file) throws Exception {
+        byte[] bytes = file.getBytes();
+        String xml = new String(bytes, StandardCharsets.UTF_8);
+        //创建转换对象
+        MyBpmnXMLConverter converter = new MyBpmnXMLConverter();
+
+        JSONObject jsonObject = XML.toJSONObject(xml);
+        String s = jsonObject.toString();
+
+        XMLInputFactory factory = XMLInputFactory.newInstance();
+        // 字节方式
+        //XMLStreamReader reader = factory.createXMLStreamReader(new ByteArrayInputStream(xml.getBytes()));
+        // 流方式
+        XMLStreamReader reader = factory.createXMLStreamReader(file.getInputStream());
+
+        //将xml文件转换成BpmnModel
+        BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
+        // 处理异常
+        if (bpmnModel.getMainProcess() == null
+                || bpmnModel.getMainProcess().getId() == null) {
+            throw new Exception("模板文件可能存在问题,请检查后重试!");
+        }
+        ObjectNode modelNode = new BpmnJsonConverter().convertToJson(bpmnModel);
+
+        Model modelData = repositoryService.newModel();
+        org.activiti.bpmn.model.Process process = bpmnModel.getMainProcess();
+        String key = process.getId();
+        checkName(process);
+        String name = process.getName();
+        String description = process.getDocumentation();
+        modelData.setKey(key);
+        modelData.setName(name);
+
+        ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
+        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
+        modelData.setMetaInfo(modelObjectNode.toString());
+        repositoryService.saveModel(modelData);
+        //对activiti 模型json 新增监听配置
+        String jsonModel = modelAddLese(modelNode);
+        repositoryService.addModelEditorSource(modelData.getId(), jsonModel.getBytes("utf-8"));
+    }
+
+    /**
+     * 对activiti 模型json 新增监听配置
+     *
+     * @param modelNode
+     * @return
+     * @throws JsonProcessingException
+     */
+    private static String modelAddLese(ObjectNode modelNode) throws JsonProcessingException {
+        ObjectMapper mapper = new ObjectMapper();
+        String json = mapper.writeValueAsString(modelNode);
+        com.alibaba.fastjson.JSONObject jsonObjectRe = JSON.parseObject(json);
+        JSONArray childShapes = jsonObjectRe.getJSONArray("childShapes");
+        for (Object childShape : childShapes) {
+            com.alibaba.fastjson.JSONObject childShapeRe = (com.alibaba.fastjson.JSONObject) com.alibaba.fastjson.JSONObject.toJSON(childShape);
+            com.alibaba.fastjson.JSONObject properties = childShapeRe.getJSONObject("properties");
+            if (null != properties) {
+                String overrideid = properties.getString("overrideid");
+                boolean equals = "reject".equals(overrideid);
+                if (equals) {
+                    Map<String, Object> data = new HashMap();
+                    ExecutionListeners executionListeners = new ExecutionListeners();
+                    executionListeners.setEvent("end");
+                    executionListeners.setImplementation("cn.modules.workflow.activiti.event.listener.task.RejectListener");
+                    executionListeners.setClassName("cn.modules.workflow.activiti.event.listener.task.RejectListener");
+                    List<ExecutionListeners> list = Arrays.asList(executionListeners);
+                    data.put("executionListeners", list);
+                    properties.put("executionlisteners", data);
+                }
+
+            }
+        }
+
+        return jsonObjectRe.toString();
+    }
+
     public void convertInputStreamToModel(InputStream is) throws Exception {
         String modelId = null;
 
@@ -323,8 +409,8 @@ public class ModelerController extends BaseController {
             modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
             modelData.setMetaInfo(modelObjectNode.toString());
             repositoryService.saveModel(modelData);
-            repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
-
+            String jsonModel = modelAddLese(modelNode);
+            repositoryService.addModelEditorSource(modelData.getId(), jsonModel.getBytes("utf-8"));
             modelId = modelData.getId();
         } catch (Exception e) {
             e.printStackTrace();

+ 50 - 0
src/main/java/com/activiti6/entity/editor/ExecutionListeners.java

@@ -0,0 +1,50 @@
+package com.activiti6.entity.editor;
+
+public class ExecutionListeners {
+
+    private String event;
+    private String implementation;
+    private String className;
+    private String expression;
+    private String delegateExpression;
+
+    public String getEvent() {
+        return event;
+    }
+
+    public void setEvent(String event) {
+        this.event = event;
+    }
+
+    public String getImplementation() {
+        return implementation;
+    }
+
+    public void setImplementation(String implementation) {
+        this.implementation = implementation;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getExpression() {
+        return expression;
+    }
+
+    public void setExpression(String expression) {
+        this.expression = expression;
+    }
+
+    public String getDelegateExpression() {
+        return delegateExpression;
+    }
+
+    public void setDelegateExpression(String delegateExpression) {
+        this.delegateExpression = delegateExpression;
+    }
+}

+ 617 - 0
src/main/java/org/activiti/bpmn/converter/MyBpmnXMLConverter.java

@@ -0,0 +1,617 @@
+package org.activiti.bpmn.converter;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.XMLConstants;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+import org.activiti.bpmn.constants.BpmnXMLConstants;
+import org.activiti.bpmn.converter.alfresco.AlfrescoStartEventXMLConverter;
+import org.activiti.bpmn.converter.alfresco.AlfrescoUserTaskXMLConverter;
+import org.activiti.bpmn.converter.child.DocumentationParser;
+import org.activiti.bpmn.converter.child.IOSpecificationParser;
+import org.activiti.bpmn.converter.child.MultiInstanceParser;
+import org.activiti.bpmn.converter.export.ActivitiListenerExport;
+import org.activiti.bpmn.converter.export.BPMNDIExport;
+import org.activiti.bpmn.converter.export.CollaborationExport;
+import org.activiti.bpmn.converter.export.DataStoreExport;
+import org.activiti.bpmn.converter.export.DefinitionsRootExport;
+import org.activiti.bpmn.converter.export.MultiInstanceExport;
+import org.activiti.bpmn.converter.export.ProcessExport;
+import org.activiti.bpmn.converter.export.SignalAndMessageDefinitionExport;
+import org.activiti.bpmn.converter.parser.BpmnEdgeParser;
+import org.activiti.bpmn.converter.parser.BpmnShapeParser;
+import org.activiti.bpmn.converter.parser.DataStoreParser;
+import org.activiti.bpmn.converter.parser.DefinitionsParser;
+import org.activiti.bpmn.converter.parser.ExtensionElementsParser;
+import org.activiti.bpmn.converter.parser.ImportParser;
+import org.activiti.bpmn.converter.parser.InterfaceParser;
+import org.activiti.bpmn.converter.parser.ItemDefinitionParser;
+import org.activiti.bpmn.converter.parser.LaneParser;
+import org.activiti.bpmn.converter.parser.MessageFlowParser;
+import org.activiti.bpmn.converter.parser.MessageParser;
+import org.activiti.bpmn.converter.parser.ParticipantParser;
+import org.activiti.bpmn.converter.parser.PotentialStarterParser;
+import org.activiti.bpmn.converter.parser.ProcessParser;
+import org.activiti.bpmn.converter.parser.ResourceParser;
+import org.activiti.bpmn.converter.parser.SignalParser;
+import org.activiti.bpmn.converter.parser.SubProcessParser;
+import org.activiti.bpmn.converter.util.BpmnXMLUtil;
+import org.activiti.bpmn.converter.util.InputStreamProvider;
+import org.activiti.bpmn.exceptions.XMLException;
+import org.activiti.bpmn.model.Activity;
+import org.activiti.bpmn.model.Artifact;
+import org.activiti.bpmn.model.Association;
+import org.activiti.bpmn.model.BaseElement;
+import org.activiti.bpmn.model.BooleanDataObject;
+import org.activiti.bpmn.model.BoundaryEvent;
+import org.activiti.bpmn.model.BpmnModel;
+import org.activiti.bpmn.model.DateDataObject;
+import org.activiti.bpmn.model.DoubleDataObject;
+import org.activiti.bpmn.model.EventSubProcess;
+import org.activiti.bpmn.model.FlowElement;
+import org.activiti.bpmn.model.FlowNode;
+import org.activiti.bpmn.model.IntegerDataObject;
+import org.activiti.bpmn.model.LongDataObject;
+import org.activiti.bpmn.model.Pool;
+import org.activiti.bpmn.model.Process;
+import org.activiti.bpmn.model.SequenceFlow;
+import org.activiti.bpmn.model.StringDataObject;
+import org.activiti.bpmn.model.SubProcess;
+import org.activiti.bpmn.model.TextAnnotation;
+import org.activiti.bpmn.model.Transaction;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+
+/**
+ * @author Tijs Rademakers
+ * @author Joram Barrez
+ */
+public class MyBpmnXMLConverter implements BpmnXMLConstants {
+
+    protected static final Logger LOGGER = LoggerFactory.getLogger(BpmnXMLConverter.class);
+
+    protected static final String BPMN_XSD = "org/activiti/impl/bpmn/parser/BPMN20.xsd";
+    protected static final String DEFAULT_ENCODING = "UTF-8";
+
+    protected static Map<String, BaseBpmnXMLConverter> convertersToBpmnMap = new HashMap<String, BaseBpmnXMLConverter>();
+    protected static Map<Class<? extends BaseElement>, BaseBpmnXMLConverter> convertersToXMLMap =
+            new HashMap<Class<? extends BaseElement>, BaseBpmnXMLConverter>();
+
+    protected ClassLoader classloader;
+    protected List<String> userTaskFormTypes;
+    protected List<String> startEventFormTypes;
+
+    protected BpmnEdgeParser bpmnEdgeParser = new BpmnEdgeParser();
+    protected BpmnShapeParser bpmnShapeParser = new BpmnShapeParser();
+    protected DefinitionsParser definitionsParser = new DefinitionsParser();
+    protected DocumentationParser documentationParser = new DocumentationParser();
+    protected ExtensionElementsParser extensionElementsParser = new ExtensionElementsParser();
+    protected ImportParser importParser = new ImportParser();
+    protected InterfaceParser interfaceParser = new InterfaceParser();
+    protected ItemDefinitionParser itemDefinitionParser = new ItemDefinitionParser();
+    protected IOSpecificationParser ioSpecificationParser = new IOSpecificationParser();
+    protected DataStoreParser dataStoreParser = new DataStoreParser();
+    protected LaneParser laneParser = new LaneParser();
+    protected MessageParser messageParser = new MessageParser();
+    protected MessageFlowParser messageFlowParser = new MessageFlowParser();
+    protected MultiInstanceParser multiInstanceParser = new MultiInstanceParser();
+    protected ParticipantParser participantParser = new ParticipantParser();
+    protected PotentialStarterParser potentialStarterParser = new PotentialStarterParser();
+    protected ProcessParser processParser = new ProcessParser();
+    protected ResourceParser resourceParser = new ResourceParser();
+    protected SignalParser signalParser = new SignalParser();
+    protected SubProcessParser subProcessParser = new SubProcessParser();
+
+    static {
+        // events
+        addConverter(new EndEventXMLConverter());
+        addConverter(new StartEventXMLConverter());
+
+        // tasks
+        addConverter(new BusinessRuleTaskXMLConverter());
+        addConverter(new ManualTaskXMLConverter());
+        addConverter(new ReceiveTaskXMLConverter());
+        addConverter(new ScriptTaskXMLConverter());
+        addConverter(new ServiceTaskXMLConverter());
+        addConverter(new SendTaskXMLConverter());
+        addConverter(new UserTaskXMLConverter());
+        addConverter(new TaskXMLConverter());
+        addConverter(new CallActivityXMLConverter());
+
+        // gateways
+        addConverter(new EventGatewayXMLConverter());
+        addConverter(new ExclusiveGatewayXMLConverter());
+        addConverter(new InclusiveGatewayXMLConverter());
+        addConverter(new ParallelGatewayXMLConverter());
+        addConverter(new ComplexGatewayXMLConverter());
+
+        // connectors
+        addConverter(new SequenceFlowXMLConverter());
+
+        // catch, throw and boundary event
+        addConverter(new CatchEventXMLConverter());
+        addConverter(new ThrowEventXMLConverter());
+        addConverter(new BoundaryEventXMLConverter());
+
+        // artifacts
+        addConverter(new TextAnnotationXMLConverter());
+        addConverter(new AssociationXMLConverter());
+
+        // data store reference
+        addConverter(new DataStoreReferenceXMLConverter());
+
+        // data objects
+        addConverter(new ValuedDataObjectXMLConverter(), StringDataObject.class);
+        addConverter(new ValuedDataObjectXMLConverter(), BooleanDataObject.class);
+        addConverter(new ValuedDataObjectXMLConverter(), IntegerDataObject.class);
+        addConverter(new ValuedDataObjectXMLConverter(), LongDataObject.class);
+        addConverter(new ValuedDataObjectXMLConverter(), DoubleDataObject.class);
+        addConverter(new ValuedDataObjectXMLConverter(), DateDataObject.class);
+
+        // Alfresco types
+        addConverter(new AlfrescoStartEventXMLConverter());
+        addConverter(new AlfrescoUserTaskXMLConverter());
+    }
+
+    public static void addConverter(BaseBpmnXMLConverter converter) {
+        addConverter(converter, converter.getBpmnElementType());
+    }
+
+    public static void addConverter(BaseBpmnXMLConverter converter, Class<? extends BaseElement> elementType) {
+        convertersToBpmnMap.put(converter.getXMLElementName(), converter);
+        convertersToXMLMap.put(elementType, converter);
+    }
+
+    public void setClassloader(ClassLoader classloader) {
+        this.classloader = classloader;
+    }
+
+    public void setUserTaskFormTypes(List<String> userTaskFormTypes) {
+        this.userTaskFormTypes = userTaskFormTypes;
+    }
+
+    public void setStartEventFormTypes(List<String> startEventFormTypes) {
+        this.startEventFormTypes = startEventFormTypes;
+    }
+
+    public void validateModel(InputStreamProvider inputStreamProvider) throws Exception {
+        Schema schema = createSchema();
+
+        Validator validator = schema.newValidator();
+        validator.validate(new StreamSource(inputStreamProvider.getInputStream()));
+    }
+
+    public void validateModel(XMLStreamReader xmlStreamReader) throws Exception {
+        Schema schema = createSchema();
+
+        Validator validator = schema.newValidator();
+        validator.validate(new StAXSource(xmlStreamReader));
+    }
+
+    protected Schema createSchema() throws SAXException {
+        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        Schema schema = null;
+        if (classloader != null) {
+            schema = factory.newSchema(classloader.getResource(BPMN_XSD));
+        }
+
+        if (schema == null) {
+            schema = factory.newSchema(BpmnXMLConverter.class.getClassLoader().getResource(BPMN_XSD));
+        }
+
+        if (schema == null) {
+            throw new XMLException("BPMN XSD could not be found");
+        }
+        return schema;
+    }
+
+    public BpmnModel convertToBpmnModel(InputStreamProvider inputStreamProvider, boolean validateSchema, boolean enableSafeBpmnXml) {
+        return convertToBpmnModel(inputStreamProvider, validateSchema, enableSafeBpmnXml, DEFAULT_ENCODING);
+    }
+
+    public BpmnModel convertToBpmnModel(InputStreamProvider inputStreamProvider, boolean validateSchema, boolean enableSafeBpmnXml, String encoding) {
+        XMLInputFactory xif = XMLInputFactory.newInstance();
+
+        if (xif.isPropertySupported(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES)) {
+            xif.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+        }
+
+        if (xif.isPropertySupported(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES)) {
+            xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+        }
+
+        if (xif.isPropertySupported(XMLInputFactory.SUPPORT_DTD)) {
+            xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
+        }
+
+        InputStreamReader in = null;
+        try {
+            in = new InputStreamReader(inputStreamProvider.getInputStream(), encoding);
+            XMLStreamReader xtr = xif.createXMLStreamReader(in);
+
+            try {
+                if (validateSchema) {
+
+                    if (!enableSafeBpmnXml) {
+                        validateModel(inputStreamProvider);
+                    } else {
+                        validateModel(xtr);
+                    }
+
+                    // The input stream is closed after schema validation
+                    in = new InputStreamReader(inputStreamProvider.getInputStream(), encoding);
+                    xtr = xif.createXMLStreamReader(in);
+                }
+
+            } catch (Exception e) {
+                throw new XMLException(e.getMessage(), e);
+            }
+
+            // XML conversion
+            return convertToBpmnModel(xtr);
+        } catch (UnsupportedEncodingException e) {
+            throw new XMLException("The bpmn 2.0 xml is not UTF8 encoded", e);
+        } catch (XMLStreamException e) {
+            throw new XMLException("Error while reading the BPMN 2.0 XML", e);
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    LOGGER.debug("Problem closing BPMN input stream", e);
+                }
+            }
+        }
+    }
+
+    public BpmnModel convertToBpmnModel(XMLStreamReader xtr) {
+        BpmnModel model = new BpmnModel();
+        model.setStartEventFormTypes(startEventFormTypes);
+        model.setUserTaskFormTypes(userTaskFormTypes);
+        try {
+            Process activeProcess = null;
+            List<SubProcess> activeSubProcessList = new ArrayList<SubProcess>();
+            while (xtr.hasNext()) {
+                try {
+                    xtr.next();
+                } catch (Exception e) {
+                    LOGGER.debug("Error reading XML document", e);
+                    throw new XMLException("Error reading XML", e);
+                }
+
+                if (xtr.isEndElement() && ELEMENT_SUBPROCESS.equals(xtr.getLocalName())) {
+                    activeSubProcessList.remove(activeSubProcessList.size() - 1);
+                }
+
+                if (xtr.isEndElement() && ELEMENT_TRANSACTION.equals(xtr.getLocalName())) {
+                    activeSubProcessList.remove(activeSubProcessList.size() - 1);
+                }
+
+                if (xtr.isStartElement() == false) {
+                    continue;
+                }
+
+                if (ELEMENT_DEFINITIONS.equals(xtr.getLocalName())) {
+                    definitionsParser.parse(xtr, model);
+
+                } else if (ELEMENT_RESOURCE.equals(xtr.getLocalName())) {
+                    resourceParser.parse(xtr, model);
+
+                } else if (ELEMENT_SIGNAL.equals(xtr.getLocalName())) {
+                    signalParser.parse(xtr, model);
+
+                } else if (ELEMENT_MESSAGE.equals(xtr.getLocalName())) {
+                    messageParser.parse(xtr, model);
+
+                } else if (ELEMENT_ERROR.equals(xtr.getLocalName())) {
+
+                    if (StringUtils.isNotEmpty(xtr.getAttributeValue(null, ATTRIBUTE_ID))) {
+                        model.addError(xtr.getAttributeValue(null, ATTRIBUTE_ID),
+                                xtr.getAttributeValue(null, ATTRIBUTE_ERROR_CODE));
+                    }
+
+                } else if (ELEMENT_IMPORT.equals(xtr.getLocalName())) {
+                    importParser.parse(xtr, model);
+
+                } else if (ELEMENT_ITEM_DEFINITION.equals(xtr.getLocalName())) {
+                    itemDefinitionParser.parse(xtr, model);
+
+                } else if (ELEMENT_DATA_STORE.equals(xtr.getLocalName())) {
+                    dataStoreParser.parse(xtr, model);
+
+                } else if (ELEMENT_INTERFACE.equals(xtr.getLocalName())) {
+                    interfaceParser.parse(xtr, model);
+
+                } else if (ELEMENT_IOSPECIFICATION.equals(xtr.getLocalName())) {
+                    ioSpecificationParser.parseChildElement(xtr, activeProcess, model);
+
+                } else if (ELEMENT_PARTICIPANT.equals(xtr.getLocalName())) {
+                    participantParser.parse(xtr, model);
+
+                } else if (ELEMENT_MESSAGE_FLOW.equals(xtr.getLocalName())) {
+                    messageFlowParser.parse(xtr, model);
+
+                } else if (ELEMENT_PROCESS.equals(xtr.getLocalName())) {
+
+                    Process process = processParser.parse(xtr, model);
+                    if (process != null) {
+                        activeProcess = process;
+                    }
+
+                } else if (ELEMENT_POTENTIAL_STARTER.equals(xtr.getLocalName())) {
+                    potentialStarterParser.parse(xtr, activeProcess);
+
+                } else if (ELEMENT_LANE.equals(xtr.getLocalName())) {
+                    laneParser.parse(xtr, activeProcess, model);
+
+                } else if (ELEMENT_DOCUMENTATION.equals(xtr.getLocalName())) {
+
+                    BaseElement parentElement = null;
+                    if (!activeSubProcessList.isEmpty()) {
+                        parentElement = activeSubProcessList.get(activeSubProcessList.size() - 1);
+                    } else if (activeProcess != null) {
+                        parentElement = activeProcess;
+                    }
+                    documentationParser.parseChildElement(xtr, parentElement, model);
+
+                } else if (activeProcess == null && ELEMENT_TEXT_ANNOTATION.equals(xtr.getLocalName())) {
+                    String elementId = xtr.getAttributeValue(null, ATTRIBUTE_ID);
+                    TextAnnotation textAnnotation = (TextAnnotation) new TextAnnotationXMLConverter().convertXMLToElement(xtr, model);
+                    textAnnotation.setId(elementId);
+                    model.getGlobalArtifacts().add(textAnnotation);
+
+                } else if (activeProcess == null && ELEMENT_ASSOCIATION.equals(xtr.getLocalName())) {
+                    String elementId = xtr.getAttributeValue(null, ATTRIBUTE_ID);
+                    Association association = (Association) new AssociationXMLConverter().convertXMLToElement(xtr, model);
+                    association.setId(elementId);
+                    model.getGlobalArtifacts().add(association);
+                } else if (ELEMENT_EXTENSIONS.equals(xtr.getLocalName())) {
+                    extensionElementsParser.parse(xtr, activeSubProcessList, activeProcess, model);
+
+                } else if (ELEMENT_SUBPROCESS.equals(xtr.getLocalName())) {
+                    subProcessParser.parse(xtr, activeSubProcessList, activeProcess);
+
+                } else if (ELEMENT_TRANSACTION.equals(xtr.getLocalName())) {
+                    subProcessParser.parse(xtr, activeSubProcessList, activeProcess);
+
+                } else if (ELEMENT_DI_SHAPE.equals(xtr.getLocalName())) {
+                    bpmnShapeParser.parse(xtr, model);
+
+                } else if (ELEMENT_DI_EDGE.equals(xtr.getLocalName())) {
+                    bpmnEdgeParser.parse(xtr, model);
+
+                } else {
+
+                    if (!activeSubProcessList.isEmpty() && ELEMENT_MULTIINSTANCE.equalsIgnoreCase(xtr.getLocalName())) {
+
+                        multiInstanceParser.parseChildElement(xtr, activeSubProcessList.get(activeSubProcessList.size() - 1), model);
+
+                    } else if (convertersToBpmnMap.containsKey(xtr.getLocalName())) {
+                        if (activeProcess != null) {
+                            BaseBpmnXMLConverter converter = convertersToBpmnMap.get(xtr.getLocalName());
+                            converter.convertToBpmnModel(xtr, model, activeProcess, activeSubProcessList);
+                        }
+                    }
+                }
+            }
+
+            for (Process process : model.getProcesses()) {
+                for (Pool pool : model.getPools()) {
+                    if (process.getId().equals(pool.getProcessRef())) {
+                        pool.setExecutable(process.isExecutable());
+                    }
+                }
+                processFlowElements(process.getFlowElements(), process);
+            }
+
+        } catch (XMLException e) {
+            throw e;
+
+        } catch (Exception e) {
+            LOGGER.error("Error processing BPMN document", e);
+            throw new XMLException("Error processing BPMN document", e);
+        }
+        return model;
+    }
+
+    private void processFlowElements(Collection<FlowElement> flowElementList, BaseElement parentScope) {
+        for (FlowElement flowElement : flowElementList) {
+            if (flowElement instanceof SequenceFlow) {
+                SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
+                FlowNode sourceNode = getFlowNodeFromScope(sequenceFlow.getSourceRef(), parentScope);
+                if (sourceNode != null) {
+                    sourceNode.getOutgoingFlows().add(sequenceFlow);
+                }
+                FlowNode targetNode = getFlowNodeFromScope(sequenceFlow.getTargetRef(), parentScope);
+                if (targetNode != null) {
+                    targetNode.getIncomingFlows().add(sequenceFlow);
+                }
+            } else if (flowElement instanceof BoundaryEvent) {
+                BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement;
+                FlowElement attachedToElement = getFlowNodeFromScope(boundaryEvent.getAttachedToRefId(), parentScope);
+                if (attachedToElement != null) {
+                    boundaryEvent.setAttachedToRef((Activity) attachedToElement);
+                    ((Activity) attachedToElement).getBoundaryEvents().add(boundaryEvent);
+                }
+            } else if (flowElement instanceof SubProcess) {
+                SubProcess subProcess = (SubProcess) flowElement;
+                processFlowElements(subProcess.getFlowElements(), subProcess);
+            }
+        }
+    }
+
+    private FlowNode getFlowNodeFromScope(String elementId, BaseElement scope) {
+        FlowNode flowNode = null;
+        if (StringUtils.isNotEmpty(elementId)) {
+            if (scope instanceof Process) {
+                flowNode = (FlowNode) ((Process) scope).getFlowElement(elementId);
+            } else if (scope instanceof SubProcess) {
+                flowNode = (FlowNode) ((SubProcess) scope).getFlowElement(elementId);
+            }
+        }
+        return flowNode;
+    }
+
+    public byte[] convertToXML(BpmnModel model) {
+        return convertToXML(model, DEFAULT_ENCODING);
+    }
+
+    public byte[] convertToXML(BpmnModel model, String encoding) {
+        try {
+
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+            XMLOutputFactory xof = XMLOutputFactory.newInstance();
+            OutputStreamWriter out = new OutputStreamWriter(outputStream, encoding);
+
+            XMLStreamWriter writer = xof.createXMLStreamWriter(out);
+            XMLStreamWriter xtw = new IndentingXMLStreamWriter(writer);
+
+            DefinitionsRootExport.writeRootElement(model, xtw, encoding);
+            CollaborationExport.writePools(model, xtw);
+            DataStoreExport.writeDataStores(model, xtw);
+            SignalAndMessageDefinitionExport.writeSignalsAndMessages(model, xtw);
+
+            for (Process process : model.getProcesses()) {
+
+                if (process.getFlowElements().isEmpty() && process.getLanes().isEmpty()) {
+                    // empty process, ignore it
+                    continue;
+                }
+
+                ProcessExport.writeProcess(process, xtw);
+
+                for (FlowElement flowElement : process.getFlowElements()) {
+                    createXML(flowElement, model, xtw);
+                }
+
+                for (Artifact artifact : process.getArtifacts()) {
+                    createXML(artifact, model, xtw);
+                }
+
+                // end process element
+                xtw.writeEndElement();
+            }
+
+            BPMNDIExport.writeBPMNDI(model, xtw);
+
+            // end definitions root element
+            xtw.writeEndElement();
+            xtw.writeEndDocument();
+
+            xtw.flush();
+
+            outputStream.close();
+
+            xtw.close();
+
+            return outputStream.toByteArray();
+
+        } catch (Exception e) {
+            LOGGER.error("Error writing BPMN XML", e);
+            throw new XMLException("Error writing BPMN XML", e);
+        }
+    }
+
+    private void createXML(FlowElement flowElement, BpmnModel model, XMLStreamWriter xtw) throws Exception {
+
+        if (flowElement instanceof SubProcess) {
+
+            SubProcess subProcess = (SubProcess) flowElement;
+            if (flowElement instanceof Transaction) {
+                xtw.writeStartElement(ELEMENT_TRANSACTION);
+            } else {
+                xtw.writeStartElement(ELEMENT_SUBPROCESS);
+            }
+
+            xtw.writeAttribute(ATTRIBUTE_ID, subProcess.getId());
+            if (StringUtils.isNotEmpty(subProcess.getName())) {
+                xtw.writeAttribute(ATTRIBUTE_NAME, subProcess.getName());
+            } else {
+                xtw.writeAttribute(ATTRIBUTE_NAME, "subProcess");
+            }
+
+            if (subProcess instanceof EventSubProcess) {
+                xtw.writeAttribute(ATTRIBUTE_TRIGGERED_BY, ATTRIBUTE_VALUE_TRUE);
+
+            } else if (subProcess instanceof Transaction == false) {
+                if (subProcess.isAsynchronous()) {
+                    BpmnXMLUtil.writeQualifiedAttribute(ATTRIBUTE_ACTIVITY_ASYNCHRONOUS, ATTRIBUTE_VALUE_TRUE, xtw);
+                    if (subProcess.isNotExclusive()) {
+                        BpmnXMLUtil.writeQualifiedAttribute(ATTRIBUTE_ACTIVITY_EXCLUSIVE, ATTRIBUTE_VALUE_FALSE, xtw);
+                    }
+                }
+            }
+
+            if (StringUtils.isNotEmpty(subProcess.getDocumentation())) {
+
+                xtw.writeStartElement(ELEMENT_DOCUMENTATION);
+                xtw.writeCharacters(subProcess.getDocumentation());
+                xtw.writeEndElement();
+            }
+
+            boolean didWriteExtensionStartElement = ActivitiListenerExport.writeListeners(subProcess, false, xtw);
+
+            didWriteExtensionStartElement = BpmnXMLUtil.writeExtensionElements(subProcess, didWriteExtensionStartElement, model.getNamespaces(), xtw);
+            if (didWriteExtensionStartElement) {
+                // closing extensions element
+                xtw.writeEndElement();
+            }
+
+            MultiInstanceExport.writeMultiInstance(subProcess, xtw);
+
+            for (FlowElement subElement : subProcess.getFlowElements()) {
+                createXML(subElement, model, xtw);
+            }
+
+            for (Artifact artifact : subProcess.getArtifacts()) {
+                createXML(artifact, model, xtw);
+            }
+
+            xtw.writeEndElement();
+
+        } else {
+
+            BaseBpmnXMLConverter converter = convertersToXMLMap.get(flowElement.getClass());
+
+            if (converter == null) {
+                throw new XMLException("No converter for " + flowElement.getClass() + " found");
+            }
+
+            converter.convertToXML(xtw, flowElement, model);
+        }
+    }
+
+    private void createXML(Artifact artifact, BpmnModel model, XMLStreamWriter xtw) throws Exception {
+
+        BaseBpmnXMLConverter converter = convertersToXMLMap.get(artifact.getClass());
+
+        if (converter == null) {
+            throw new XMLException("No converter for " + artifact.getClass() + " found");
+        }
+
+        converter.convertToXML(xtw, artifact, model);
+    }
+}