MyBpmnXMLConverter.java 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. package org.activiti.bpmn.converter;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.OutputStreamWriter;
  6. import java.io.UnsupportedEncodingException;
  7. import java.util.ArrayList;
  8. import java.util.Collection;
  9. import java.util.HashMap;
  10. import java.util.List;
  11. import java.util.Map;
  12. import javax.xml.XMLConstants;
  13. import javax.xml.stream.XMLInputFactory;
  14. import javax.xml.stream.XMLOutputFactory;
  15. import javax.xml.stream.XMLStreamException;
  16. import javax.xml.stream.XMLStreamReader;
  17. import javax.xml.stream.XMLStreamWriter;
  18. import javax.xml.transform.stax.StAXSource;
  19. import javax.xml.transform.stream.StreamSource;
  20. import javax.xml.validation.Schema;
  21. import javax.xml.validation.SchemaFactory;
  22. import javax.xml.validation.Validator;
  23. import org.activiti.bpmn.constants.BpmnXMLConstants;
  24. import org.activiti.bpmn.converter.alfresco.AlfrescoStartEventXMLConverter;
  25. import org.activiti.bpmn.converter.alfresco.AlfrescoUserTaskXMLConverter;
  26. import org.activiti.bpmn.converter.child.DocumentationParser;
  27. import org.activiti.bpmn.converter.child.IOSpecificationParser;
  28. import org.activiti.bpmn.converter.child.MultiInstanceParser;
  29. import org.activiti.bpmn.converter.export.ActivitiListenerExport;
  30. import org.activiti.bpmn.converter.export.BPMNDIExport;
  31. import org.activiti.bpmn.converter.export.CollaborationExport;
  32. import org.activiti.bpmn.converter.export.DataStoreExport;
  33. import org.activiti.bpmn.converter.export.DefinitionsRootExport;
  34. import org.activiti.bpmn.converter.export.MultiInstanceExport;
  35. import org.activiti.bpmn.converter.export.ProcessExport;
  36. import org.activiti.bpmn.converter.export.SignalAndMessageDefinitionExport;
  37. import org.activiti.bpmn.converter.parser.BpmnEdgeParser;
  38. import org.activiti.bpmn.converter.parser.BpmnShapeParser;
  39. import org.activiti.bpmn.converter.parser.DataStoreParser;
  40. import org.activiti.bpmn.converter.parser.DefinitionsParser;
  41. import org.activiti.bpmn.converter.parser.ExtensionElementsParser;
  42. import org.activiti.bpmn.converter.parser.ImportParser;
  43. import org.activiti.bpmn.converter.parser.InterfaceParser;
  44. import org.activiti.bpmn.converter.parser.ItemDefinitionParser;
  45. import org.activiti.bpmn.converter.parser.LaneParser;
  46. import org.activiti.bpmn.converter.parser.MessageFlowParser;
  47. import org.activiti.bpmn.converter.parser.MessageParser;
  48. import org.activiti.bpmn.converter.parser.ParticipantParser;
  49. import org.activiti.bpmn.converter.parser.PotentialStarterParser;
  50. import org.activiti.bpmn.converter.parser.ProcessParser;
  51. import org.activiti.bpmn.converter.parser.ResourceParser;
  52. import org.activiti.bpmn.converter.parser.SignalParser;
  53. import org.activiti.bpmn.converter.parser.SubProcessParser;
  54. import org.activiti.bpmn.converter.util.BpmnXMLUtil;
  55. import org.activiti.bpmn.converter.util.InputStreamProvider;
  56. import org.activiti.bpmn.exceptions.XMLException;
  57. import org.activiti.bpmn.model.Activity;
  58. import org.activiti.bpmn.model.Artifact;
  59. import org.activiti.bpmn.model.Association;
  60. import org.activiti.bpmn.model.BaseElement;
  61. import org.activiti.bpmn.model.BooleanDataObject;
  62. import org.activiti.bpmn.model.BoundaryEvent;
  63. import org.activiti.bpmn.model.BpmnModel;
  64. import org.activiti.bpmn.model.DateDataObject;
  65. import org.activiti.bpmn.model.DoubleDataObject;
  66. import org.activiti.bpmn.model.EventSubProcess;
  67. import org.activiti.bpmn.model.FlowElement;
  68. import org.activiti.bpmn.model.FlowNode;
  69. import org.activiti.bpmn.model.IntegerDataObject;
  70. import org.activiti.bpmn.model.LongDataObject;
  71. import org.activiti.bpmn.model.Pool;
  72. import org.activiti.bpmn.model.Process;
  73. import org.activiti.bpmn.model.SequenceFlow;
  74. import org.activiti.bpmn.model.StringDataObject;
  75. import org.activiti.bpmn.model.SubProcess;
  76. import org.activiti.bpmn.model.TextAnnotation;
  77. import org.activiti.bpmn.model.Transaction;
  78. import org.apache.commons.lang3.StringUtils;
  79. import org.slf4j.Logger;
  80. import org.slf4j.LoggerFactory;
  81. import org.xml.sax.SAXException;
  82. /**
  83. * @author Tijs Rademakers
  84. * @author Joram Barrez
  85. */
  86. public class MyBpmnXMLConverter implements BpmnXMLConstants {
  87. protected static final Logger LOGGER = LoggerFactory.getLogger(BpmnXMLConverter.class);
  88. protected static final String BPMN_XSD = "org/activiti/impl/bpmn/parser/BPMN20.xsd";
  89. protected static final String DEFAULT_ENCODING = "UTF-8";
  90. protected static Map<String, BaseBpmnXMLConverter> convertersToBpmnMap = new HashMap<String, BaseBpmnXMLConverter>();
  91. protected static Map<Class<? extends BaseElement>, BaseBpmnXMLConverter> convertersToXMLMap =
  92. new HashMap<Class<? extends BaseElement>, BaseBpmnXMLConverter>();
  93. protected ClassLoader classloader;
  94. protected List<String> userTaskFormTypes;
  95. protected List<String> startEventFormTypes;
  96. protected BpmnEdgeParser bpmnEdgeParser = new BpmnEdgeParser();
  97. protected BpmnShapeParser bpmnShapeParser = new BpmnShapeParser();
  98. protected DefinitionsParser definitionsParser = new DefinitionsParser();
  99. protected DocumentationParser documentationParser = new DocumentationParser();
  100. protected ExtensionElementsParser extensionElementsParser = new ExtensionElementsParser();
  101. protected ImportParser importParser = new ImportParser();
  102. protected InterfaceParser interfaceParser = new InterfaceParser();
  103. protected ItemDefinitionParser itemDefinitionParser = new ItemDefinitionParser();
  104. protected IOSpecificationParser ioSpecificationParser = new IOSpecificationParser();
  105. protected DataStoreParser dataStoreParser = new DataStoreParser();
  106. protected LaneParser laneParser = new LaneParser();
  107. protected MessageParser messageParser = new MessageParser();
  108. protected MessageFlowParser messageFlowParser = new MessageFlowParser();
  109. protected MultiInstanceParser multiInstanceParser = new MultiInstanceParser();
  110. protected ParticipantParser participantParser = new ParticipantParser();
  111. protected PotentialStarterParser potentialStarterParser = new PotentialStarterParser();
  112. protected ProcessParser processParser = new ProcessParser();
  113. protected ResourceParser resourceParser = new ResourceParser();
  114. protected SignalParser signalParser = new SignalParser();
  115. protected SubProcessParser subProcessParser = new SubProcessParser();
  116. static {
  117. // events
  118. addConverter(new EndEventXMLConverter());
  119. addConverter(new StartEventXMLConverter());
  120. // tasks
  121. addConverter(new BusinessRuleTaskXMLConverter());
  122. addConverter(new ManualTaskXMLConverter());
  123. addConverter(new ReceiveTaskXMLConverter());
  124. addConverter(new ScriptTaskXMLConverter());
  125. addConverter(new ServiceTaskXMLConverter());
  126. addConverter(new SendTaskXMLConverter());
  127. addConverter(new UserTaskXMLConverter());
  128. addConverter(new TaskXMLConverter());
  129. addConverter(new CallActivityXMLConverter());
  130. // gateways
  131. addConverter(new EventGatewayXMLConverter());
  132. addConverter(new ExclusiveGatewayXMLConverter());
  133. addConverter(new InclusiveGatewayXMLConverter());
  134. addConverter(new ParallelGatewayXMLConverter());
  135. addConverter(new ComplexGatewayXMLConverter());
  136. // connectors
  137. addConverter(new SequenceFlowXMLConverter());
  138. // catch, throw and boundary event
  139. addConverter(new CatchEventXMLConverter());
  140. addConverter(new ThrowEventXMLConverter());
  141. addConverter(new BoundaryEventXMLConverter());
  142. // artifacts
  143. addConverter(new TextAnnotationXMLConverter());
  144. addConverter(new AssociationXMLConverter());
  145. // data store reference
  146. addConverter(new DataStoreReferenceXMLConverter());
  147. // data objects
  148. addConverter(new ValuedDataObjectXMLConverter(), StringDataObject.class);
  149. addConverter(new ValuedDataObjectXMLConverter(), BooleanDataObject.class);
  150. addConverter(new ValuedDataObjectXMLConverter(), IntegerDataObject.class);
  151. addConverter(new ValuedDataObjectXMLConverter(), LongDataObject.class);
  152. addConverter(new ValuedDataObjectXMLConverter(), DoubleDataObject.class);
  153. addConverter(new ValuedDataObjectXMLConverter(), DateDataObject.class);
  154. // Alfresco types
  155. addConverter(new AlfrescoStartEventXMLConverter());
  156. addConverter(new AlfrescoUserTaskXMLConverter());
  157. }
  158. public static void addConverter(BaseBpmnXMLConverter converter) {
  159. addConverter(converter, converter.getBpmnElementType());
  160. }
  161. public static void addConverter(BaseBpmnXMLConverter converter, Class<? extends BaseElement> elementType) {
  162. convertersToBpmnMap.put(converter.getXMLElementName(), converter);
  163. convertersToXMLMap.put(elementType, converter);
  164. }
  165. public void setClassloader(ClassLoader classloader) {
  166. this.classloader = classloader;
  167. }
  168. public void setUserTaskFormTypes(List<String> userTaskFormTypes) {
  169. this.userTaskFormTypes = userTaskFormTypes;
  170. }
  171. public void setStartEventFormTypes(List<String> startEventFormTypes) {
  172. this.startEventFormTypes = startEventFormTypes;
  173. }
  174. public void validateModel(InputStreamProvider inputStreamProvider) throws Exception {
  175. Schema schema = createSchema();
  176. Validator validator = schema.newValidator();
  177. validator.validate(new StreamSource(inputStreamProvider.getInputStream()));
  178. }
  179. public void validateModel(XMLStreamReader xmlStreamReader) throws Exception {
  180. Schema schema = createSchema();
  181. Validator validator = schema.newValidator();
  182. validator.validate(new StAXSource(xmlStreamReader));
  183. }
  184. protected Schema createSchema() throws SAXException {
  185. SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
  186. Schema schema = null;
  187. if (classloader != null) {
  188. schema = factory.newSchema(classloader.getResource(BPMN_XSD));
  189. }
  190. if (schema == null) {
  191. schema = factory.newSchema(BpmnXMLConverter.class.getClassLoader().getResource(BPMN_XSD));
  192. }
  193. if (schema == null) {
  194. throw new XMLException("BPMN XSD could not be found");
  195. }
  196. return schema;
  197. }
  198. public BpmnModel convertToBpmnModel(InputStreamProvider inputStreamProvider, boolean validateSchema, boolean enableSafeBpmnXml) {
  199. return convertToBpmnModel(inputStreamProvider, validateSchema, enableSafeBpmnXml, DEFAULT_ENCODING);
  200. }
  201. public BpmnModel convertToBpmnModel(InputStreamProvider inputStreamProvider, boolean validateSchema, boolean enableSafeBpmnXml, String encoding) {
  202. XMLInputFactory xif = XMLInputFactory.newInstance();
  203. if (xif.isPropertySupported(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES)) {
  204. xif.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
  205. }
  206. if (xif.isPropertySupported(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES)) {
  207. xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
  208. }
  209. if (xif.isPropertySupported(XMLInputFactory.SUPPORT_DTD)) {
  210. xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
  211. }
  212. InputStreamReader in = null;
  213. try {
  214. in = new InputStreamReader(inputStreamProvider.getInputStream(), encoding);
  215. XMLStreamReader xtr = xif.createXMLStreamReader(in);
  216. try {
  217. if (validateSchema) {
  218. if (!enableSafeBpmnXml) {
  219. validateModel(inputStreamProvider);
  220. } else {
  221. validateModel(xtr);
  222. }
  223. // The input stream is closed after schema validation
  224. in = new InputStreamReader(inputStreamProvider.getInputStream(), encoding);
  225. xtr = xif.createXMLStreamReader(in);
  226. }
  227. } catch (Exception e) {
  228. throw new XMLException(e.getMessage(), e);
  229. }
  230. // XML conversion
  231. return convertToBpmnModel(xtr);
  232. } catch (UnsupportedEncodingException e) {
  233. throw new XMLException("The bpmn 2.0 xml is not UTF8 encoded", e);
  234. } catch (XMLStreamException e) {
  235. throw new XMLException("Error while reading the BPMN 2.0 XML", e);
  236. } finally {
  237. if (in != null) {
  238. try {
  239. in.close();
  240. } catch (IOException e) {
  241. LOGGER.debug("Problem closing BPMN input stream", e);
  242. }
  243. }
  244. }
  245. }
  246. public BpmnModel convertToBpmnModel(XMLStreamReader xtr) {
  247. BpmnModel model = new BpmnModel();
  248. model.setStartEventFormTypes(startEventFormTypes);
  249. model.setUserTaskFormTypes(userTaskFormTypes);
  250. try {
  251. Process activeProcess = null;
  252. List<SubProcess> activeSubProcessList = new ArrayList<SubProcess>();
  253. while (xtr.hasNext()) {
  254. try {
  255. xtr.next();
  256. } catch (Exception e) {
  257. LOGGER.debug("Error reading XML document", e);
  258. throw new XMLException("Error reading XML", e);
  259. }
  260. if (xtr.isEndElement() && ELEMENT_SUBPROCESS.equals(xtr.getLocalName())) {
  261. activeSubProcessList.remove(activeSubProcessList.size() - 1);
  262. }
  263. if (xtr.isEndElement() && ELEMENT_TRANSACTION.equals(xtr.getLocalName())) {
  264. activeSubProcessList.remove(activeSubProcessList.size() - 1);
  265. }
  266. if (xtr.isStartElement() == false) {
  267. continue;
  268. }
  269. if (ELEMENT_DEFINITIONS.equals(xtr.getLocalName())) {
  270. definitionsParser.parse(xtr, model);
  271. } else if (ELEMENT_RESOURCE.equals(xtr.getLocalName())) {
  272. resourceParser.parse(xtr, model);
  273. } else if (ELEMENT_SIGNAL.equals(xtr.getLocalName())) {
  274. signalParser.parse(xtr, model);
  275. } else if (ELEMENT_MESSAGE.equals(xtr.getLocalName())) {
  276. messageParser.parse(xtr, model);
  277. } else if (ELEMENT_ERROR.equals(xtr.getLocalName())) {
  278. if (StringUtils.isNotEmpty(xtr.getAttributeValue(null, ATTRIBUTE_ID))) {
  279. model.addError(xtr.getAttributeValue(null, ATTRIBUTE_ID),
  280. xtr.getAttributeValue(null, ATTRIBUTE_ERROR_CODE));
  281. }
  282. } else if (ELEMENT_IMPORT.equals(xtr.getLocalName())) {
  283. importParser.parse(xtr, model);
  284. } else if (ELEMENT_ITEM_DEFINITION.equals(xtr.getLocalName())) {
  285. itemDefinitionParser.parse(xtr, model);
  286. } else if (ELEMENT_DATA_STORE.equals(xtr.getLocalName())) {
  287. dataStoreParser.parse(xtr, model);
  288. } else if (ELEMENT_INTERFACE.equals(xtr.getLocalName())) {
  289. interfaceParser.parse(xtr, model);
  290. } else if (ELEMENT_IOSPECIFICATION.equals(xtr.getLocalName())) {
  291. ioSpecificationParser.parseChildElement(xtr, activeProcess, model);
  292. } else if (ELEMENT_PARTICIPANT.equals(xtr.getLocalName())) {
  293. participantParser.parse(xtr, model);
  294. } else if (ELEMENT_MESSAGE_FLOW.equals(xtr.getLocalName())) {
  295. messageFlowParser.parse(xtr, model);
  296. } else if (ELEMENT_PROCESS.equals(xtr.getLocalName())) {
  297. Process process = processParser.parse(xtr, model);
  298. if (process != null) {
  299. activeProcess = process;
  300. }
  301. } else if (ELEMENT_POTENTIAL_STARTER.equals(xtr.getLocalName())) {
  302. potentialStarterParser.parse(xtr, activeProcess);
  303. } else if (ELEMENT_LANE.equals(xtr.getLocalName())) {
  304. laneParser.parse(xtr, activeProcess, model);
  305. } else if (ELEMENT_DOCUMENTATION.equals(xtr.getLocalName())) {
  306. BaseElement parentElement = null;
  307. if (!activeSubProcessList.isEmpty()) {
  308. parentElement = activeSubProcessList.get(activeSubProcessList.size() - 1);
  309. } else if (activeProcess != null) {
  310. parentElement = activeProcess;
  311. }
  312. documentationParser.parseChildElement(xtr, parentElement, model);
  313. } else if (activeProcess == null && ELEMENT_TEXT_ANNOTATION.equals(xtr.getLocalName())) {
  314. String elementId = xtr.getAttributeValue(null, ATTRIBUTE_ID);
  315. TextAnnotation textAnnotation = (TextAnnotation) new TextAnnotationXMLConverter().convertXMLToElement(xtr, model);
  316. textAnnotation.setId(elementId);
  317. model.getGlobalArtifacts().add(textAnnotation);
  318. } else if (activeProcess == null && ELEMENT_ASSOCIATION.equals(xtr.getLocalName())) {
  319. String elementId = xtr.getAttributeValue(null, ATTRIBUTE_ID);
  320. Association association = (Association) new AssociationXMLConverter().convertXMLToElement(xtr, model);
  321. association.setId(elementId);
  322. model.getGlobalArtifacts().add(association);
  323. } else if (ELEMENT_EXTENSIONS.equals(xtr.getLocalName())) {
  324. extensionElementsParser.parse(xtr, activeSubProcessList, activeProcess, model);
  325. } else if (ELEMENT_SUBPROCESS.equals(xtr.getLocalName())) {
  326. subProcessParser.parse(xtr, activeSubProcessList, activeProcess);
  327. } else if (ELEMENT_TRANSACTION.equals(xtr.getLocalName())) {
  328. subProcessParser.parse(xtr, activeSubProcessList, activeProcess);
  329. } else if (ELEMENT_DI_SHAPE.equals(xtr.getLocalName())) {
  330. bpmnShapeParser.parse(xtr, model);
  331. } else if (ELEMENT_DI_EDGE.equals(xtr.getLocalName())) {
  332. bpmnEdgeParser.parse(xtr, model);
  333. } else {
  334. if (!activeSubProcessList.isEmpty() && ELEMENT_MULTIINSTANCE.equalsIgnoreCase(xtr.getLocalName())) {
  335. multiInstanceParser.parseChildElement(xtr, activeSubProcessList.get(activeSubProcessList.size() - 1), model);
  336. } else if (convertersToBpmnMap.containsKey(xtr.getLocalName())) {
  337. if (activeProcess != null) {
  338. BaseBpmnXMLConverter converter = convertersToBpmnMap.get(xtr.getLocalName());
  339. converter.convertToBpmnModel(xtr, model, activeProcess, activeSubProcessList);
  340. }
  341. }
  342. }
  343. }
  344. for (Process process : model.getProcesses()) {
  345. for (Pool pool : model.getPools()) {
  346. if (process.getId().equals(pool.getProcessRef())) {
  347. pool.setExecutable(process.isExecutable());
  348. }
  349. }
  350. processFlowElements(process.getFlowElements(), process);
  351. }
  352. } catch (XMLException e) {
  353. throw e;
  354. } catch (Exception e) {
  355. LOGGER.error("Error processing BPMN document", e);
  356. throw new XMLException("Error processing BPMN document", e);
  357. }
  358. return model;
  359. }
  360. private void processFlowElements(Collection<FlowElement> flowElementList, BaseElement parentScope) {
  361. for (FlowElement flowElement : flowElementList) {
  362. if (flowElement instanceof SequenceFlow) {
  363. SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
  364. FlowNode sourceNode = getFlowNodeFromScope(sequenceFlow.getSourceRef(), parentScope);
  365. if (sourceNode != null) {
  366. sourceNode.getOutgoingFlows().add(sequenceFlow);
  367. }
  368. FlowNode targetNode = getFlowNodeFromScope(sequenceFlow.getTargetRef(), parentScope);
  369. if (targetNode != null) {
  370. targetNode.getIncomingFlows().add(sequenceFlow);
  371. }
  372. } else if (flowElement instanceof BoundaryEvent) {
  373. BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement;
  374. FlowElement attachedToElement = getFlowNodeFromScope(boundaryEvent.getAttachedToRefId(), parentScope);
  375. if (attachedToElement != null) {
  376. boundaryEvent.setAttachedToRef((Activity) attachedToElement);
  377. ((Activity) attachedToElement).getBoundaryEvents().add(boundaryEvent);
  378. }
  379. } else if (flowElement instanceof SubProcess) {
  380. SubProcess subProcess = (SubProcess) flowElement;
  381. processFlowElements(subProcess.getFlowElements(), subProcess);
  382. }
  383. }
  384. }
  385. private FlowNode getFlowNodeFromScope(String elementId, BaseElement scope) {
  386. FlowNode flowNode = null;
  387. if (StringUtils.isNotEmpty(elementId)) {
  388. if (scope instanceof Process) {
  389. flowNode = (FlowNode) ((Process) scope).getFlowElement(elementId);
  390. } else if (scope instanceof SubProcess) {
  391. flowNode = (FlowNode) ((SubProcess) scope).getFlowElement(elementId);
  392. }
  393. }
  394. return flowNode;
  395. }
  396. public byte[] convertToXML(BpmnModel model) {
  397. return convertToXML(model, DEFAULT_ENCODING);
  398. }
  399. public byte[] convertToXML(BpmnModel model, String encoding) {
  400. try {
  401. ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  402. XMLOutputFactory xof = XMLOutputFactory.newInstance();
  403. OutputStreamWriter out = new OutputStreamWriter(outputStream, encoding);
  404. XMLStreamWriter writer = xof.createXMLStreamWriter(out);
  405. XMLStreamWriter xtw = new IndentingXMLStreamWriter(writer);
  406. DefinitionsRootExport.writeRootElement(model, xtw, encoding);
  407. CollaborationExport.writePools(model, xtw);
  408. DataStoreExport.writeDataStores(model, xtw);
  409. SignalAndMessageDefinitionExport.writeSignalsAndMessages(model, xtw);
  410. for (Process process : model.getProcesses()) {
  411. if (process.getFlowElements().isEmpty() && process.getLanes().isEmpty()) {
  412. // empty process, ignore it
  413. continue;
  414. }
  415. ProcessExport.writeProcess(process, xtw);
  416. for (FlowElement flowElement : process.getFlowElements()) {
  417. createXML(flowElement, model, xtw);
  418. }
  419. for (Artifact artifact : process.getArtifacts()) {
  420. createXML(artifact, model, xtw);
  421. }
  422. // end process element
  423. xtw.writeEndElement();
  424. }
  425. BPMNDIExport.writeBPMNDI(model, xtw);
  426. // end definitions root element
  427. xtw.writeEndElement();
  428. xtw.writeEndDocument();
  429. xtw.flush();
  430. outputStream.close();
  431. xtw.close();
  432. return outputStream.toByteArray();
  433. } catch (Exception e) {
  434. LOGGER.error("Error writing BPMN XML", e);
  435. throw new XMLException("Error writing BPMN XML", e);
  436. }
  437. }
  438. private void createXML(FlowElement flowElement, BpmnModel model, XMLStreamWriter xtw) throws Exception {
  439. if (flowElement instanceof SubProcess) {
  440. SubProcess subProcess = (SubProcess) flowElement;
  441. if (flowElement instanceof Transaction) {
  442. xtw.writeStartElement(ELEMENT_TRANSACTION);
  443. } else {
  444. xtw.writeStartElement(ELEMENT_SUBPROCESS);
  445. }
  446. xtw.writeAttribute(ATTRIBUTE_ID, subProcess.getId());
  447. if (StringUtils.isNotEmpty(subProcess.getName())) {
  448. xtw.writeAttribute(ATTRIBUTE_NAME, subProcess.getName());
  449. } else {
  450. xtw.writeAttribute(ATTRIBUTE_NAME, "subProcess");
  451. }
  452. if (subProcess instanceof EventSubProcess) {
  453. xtw.writeAttribute(ATTRIBUTE_TRIGGERED_BY, ATTRIBUTE_VALUE_TRUE);
  454. } else if (subProcess instanceof Transaction == false) {
  455. if (subProcess.isAsynchronous()) {
  456. BpmnXMLUtil.writeQualifiedAttribute(ATTRIBUTE_ACTIVITY_ASYNCHRONOUS, ATTRIBUTE_VALUE_TRUE, xtw);
  457. if (subProcess.isNotExclusive()) {
  458. BpmnXMLUtil.writeQualifiedAttribute(ATTRIBUTE_ACTIVITY_EXCLUSIVE, ATTRIBUTE_VALUE_FALSE, xtw);
  459. }
  460. }
  461. }
  462. if (StringUtils.isNotEmpty(subProcess.getDocumentation())) {
  463. xtw.writeStartElement(ELEMENT_DOCUMENTATION);
  464. xtw.writeCharacters(subProcess.getDocumentation());
  465. xtw.writeEndElement();
  466. }
  467. boolean didWriteExtensionStartElement = ActivitiListenerExport.writeListeners(subProcess, false, xtw);
  468. didWriteExtensionStartElement = BpmnXMLUtil.writeExtensionElements(subProcess, didWriteExtensionStartElement, model.getNamespaces(), xtw);
  469. if (didWriteExtensionStartElement) {
  470. // closing extensions element
  471. xtw.writeEndElement();
  472. }
  473. MultiInstanceExport.writeMultiInstance(subProcess, xtw);
  474. for (FlowElement subElement : subProcess.getFlowElements()) {
  475. createXML(subElement, model, xtw);
  476. }
  477. for (Artifact artifact : subProcess.getArtifacts()) {
  478. createXML(artifact, model, xtw);
  479. }
  480. xtw.writeEndElement();
  481. } else {
  482. BaseBpmnXMLConverter converter = convertersToXMLMap.get(flowElement.getClass());
  483. if (converter == null) {
  484. throw new XMLException("No converter for " + flowElement.getClass() + " found");
  485. }
  486. converter.convertToXML(xtw, flowElement, model);
  487. }
  488. }
  489. private void createXML(Artifact artifact, BpmnModel model, XMLStreamWriter xtw) throws Exception {
  490. BaseBpmnXMLConverter converter = convertersToXMLMap.get(artifact.getClass());
  491. if (converter == null) {
  492. throw new XMLException("No converter for " + artifact.getClass() + " found");
  493. }
  494. converter.convertToXML(xtw, artifact, model);
  495. }
  496. }