Community
Participate
Working Groups
At least for elements of type Process, EMF's XML serialization stores children elements not in the order prescribed by the XML schema. In our Ecore file (modeled after XMI), Process inherits from CallableElement, FlowElementsContainer (in this order). Thus, EMF stores contained elements of super types in order of the super type collection first (1. CallableElement, 2. FlowElementsContainer), then the contained elements defined for the type itself. Instead of multi inheritance, which is not possible in XML Schema, the XML type Process only inherits from CallableElement, whose children elements therefore go before children of Process itself. The elements defined by FlowElementsContainer have been pulled down to the type definition of Process. Sadly, Semantic.xsd defines a different order as EMF and inserts the children defined by FlowElementsContainer in between the children defined by Process itself. Therefore, the default order of EMF's XML serialization does not match the XML schema and needs to be adapted. See http://www.eclipse.org/forums/index.php/mv/msg/236798/719960/#msg_719960 for a possible solution, involving OPTION_USE_CACHED_LOOKUP_TABLE and a custom XMLSaveImpl.Lookup implementation. The same might occur in other cases with multi inheritance.
Hi Henning, here is description of a fix. I can create a diff for it so it can be merged, just let me know if I am supposed to create a diff off of the github repo or some other repository. Thanks: 1) Update org.eclipse.bpmn2.util.Bpmn2ResourceFactoryImpl: add: result.getDefaultSaveOptions().put(XMLResource.OPTION_USE_CACHED_LOOKUP_TABLE, new ArrayList<Object>()); to the createResource method 2) Update org.eclipse.bpmn2.util.Bpmn2ResourceImpl: change: return new XMLSaveImpl(createXMLHelper()) { ... to return new Bpmn2XMLSaveImpl(createXMLHelper()) { ... 3) Create new class Bpmn2XMLSaveImpl: You can use this implementation if you wish: public class Bpmn2XMLSaveImpl extends XMLSaveImpl { public Bpmn2XMLSaveImpl(XMLHelper helper) { super(helper); } @Override protected void init(XMLResource resource, Map<?, ?> options) { super.init(resource, options); featureTable = new Bpmn2XMLSaveImpl.Bpmn2Lookup(map, extendedMetaData, elementHandler); } @Override public void traverse(List<? extends EObject> contents) { for(EObject e : contents) { if(e instanceof Definitions) { List<RootElement> roots = ((Definitions) e).getRootElements(); Process p = null; for(RootElement root : roots) { if(root instanceof Process) { p = (Process) root; } } if(p != null) { ((Definitions) e).getRootElements().remove(p); ((Definitions) e).getRootElements().add(p); } } } super.traverse(contents); } public static class Bpmn2Lookup extends XMLSaveImpl.Lookup { public Bpmn2Lookup(XMLMap map, ExtendedMetaData extendedMetaData, ElementHandler elementHandler) { super(map, extendedMetaData, elementHandler); } @Override public EStructuralFeature[] getFeatures(EClass cls) { int index = getIndex(cls); EClass c = classes[index]; if (c == cls) { return features[index]; } EStructuralFeature[] featureList = listFeatures(cls); if (c == null) { classes[index] = cls; features[index] = featureList; featureKinds[index] = listKinds(featureList); } if(cls.getName().equalsIgnoreCase("Process")) { EStructuralFeature[] modifiedFeatureList = getModifiedProcessFeatureSet(featureList); if (c == null) { classes[index] = cls; features[index] = modifiedFeatureList; featureKinds[index] = listKinds(modifiedFeatureList); } return modifiedFeatureList; } return featureList; } } private static EStructuralFeature[] getModifiedProcessFeatureSet(EStructuralFeature[] processFeatureList) { /** Feature list for Process provided by eclipse.bpmn2: - extensionDefinitions (0) - id (1) - anyAttribute (2) - name (3) - definitionalCollaborationRef (4) - isClosed (5) - isExecutable (6) - processType (7) - extensionValues (8) - documentation (9) - supportedInterfaceRefs (10) - ioSpecification (11) - ioBinding (12) - laneSets (13) - flowElements (14) - auditing (15) - monitoring (16) - properties (17) - artifacts (18) - resources (19) - correlationSubscriptions (20) - supports (21) Semantic.xsd sequence definition for Process: <xsd:sequence> <xsd:element ref="auditing" minOccurs="0" maxOccurs="1"/> <xsd:element ref="monitoring" minOccurs="0" maxOccurs="1"/> <xsd:element ref="property" minOccurs="0" maxOccurs="unbounded"/> <xsd:element ref="laneSet" minOccurs="0" maxOccurs="unbounded"/> <xsd:element ref="flowElement" minOccurs="0" maxOccurs="unbounded"/> <xsd:element ref="artifact" minOccurs="0" maxOccurs="unbounded"/> <xsd:element ref="resourceRole" minOccurs="0" maxOccurs="unbounded"/> <xsd:element ref="correlationSubscription" minOccurs="0" maxOccurs="unbounded"/> <xsd:element name="supports" type="xsd:QName" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> Moving auditing, monitoring, property above flowElements... */ EStructuralFeature[] retArray = new EStructuralFeature[processFeatureList.length]; for(int i=0; i<13; i++) { retArray[i] = processFeatureList[i]; } retArray[13] = processFeatureList[15]; // auditing retArray[14] = processFeatureList[16]; // monitoring retArray[15] = processFeatureList[17]; // properties retArray[16] = processFeatureList[13]; // lanesets retArray[17] = processFeatureList[14]; // flow elements retArray[18] = processFeatureList[18]; // artifacts retArray[19] = processFeatureList[19]; // resources retArray[20] = processFeatureList[20]; // correlationSubscriptions retArray[21] = processFeatureList[21]; // supports return retArray; } } Hope this helps. Thanks.
Thanks. I'm aware of the problem, and the use of strict sequences in BPMN 2.0 XSD is really a problem. Not only for the EMF metamodel, but also for the XSLT transforms between XML and XMI. The XSLTs also simulate the multiple inheritance aspect of the CMOF metamodel and thus can produce invalid XMLs in the sense of the sequence of features. About your proposal: It looks right, but I would prefer a more generic approach. I think we could store the order information in EMF annotations and let the serializer consider it from there. Ideally we generate the annotations from the original BPMN 2.0 XSD. This is possible, as I anyway used a merge tool to generate the Ecore. Unfortunately this will take some time - and my time for BPMN2 is currently very limmited. Reiner.
Some addition: I have checked my merge tool (in http://git.eclipse.org/c/bpmn2/tree/org.eclipse.bpmn2.tools.ecoremerger/src/org/eclipse/bpmn2/tools/ecoremerger/Processor.java ). I do consider feature sorting of the XSD, but not in cases of Multi Inheritance. I now plan to extend the merge tool that i writes an annotation to each class with the original XSD feature order. The XmlSave.traverse then can easily take this information and walk accordingly.