| /******************************************************************************* |
| * Copyright (c) 2011, 2012 Red Hat, Inc. |
| * All rights reserved. |
| * This program is made available under the terms of the |
| * Eclipse Public License v1.0 which accompanies this distribution, |
| * and is available at http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Red Hat, Inc. - initial API and implementation |
| * |
| * @author Bob Brodt |
| ******************************************************************************/ |
| package org.eclipse.bpmn2.modeler.core.model; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.bpmn2.Assignment; |
| import org.eclipse.bpmn2.BaseElement; |
| import org.eclipse.bpmn2.Bpmn2Factory; |
| import org.eclipse.bpmn2.Bpmn2Package; |
| import org.eclipse.bpmn2.CompensateEventDefinition; |
| import org.eclipse.bpmn2.DataAssociation; |
| import org.eclipse.bpmn2.Definitions; |
| import org.eclipse.bpmn2.Documentation; |
| import org.eclipse.bpmn2.Expression; |
| import org.eclipse.bpmn2.ExtensionAttributeValue; |
| import org.eclipse.bpmn2.FormalExpression; |
| import org.eclipse.bpmn2.Import; |
| import org.eclipse.bpmn2.ItemDefinition; |
| import org.eclipse.bpmn2.Lane; |
| import org.eclipse.bpmn2.Participant; |
| import org.eclipse.bpmn2.Process; |
| import org.eclipse.bpmn2.RootElement; |
| import org.eclipse.bpmn2.SubProcess; |
| import org.eclipse.bpmn2.di.BPMNDiagram; |
| import org.eclipse.bpmn2.di.BPMNEdge; |
| import org.eclipse.bpmn2.di.BPMNLabel; |
| import org.eclipse.bpmn2.di.BPMNLabelStyle; |
| import org.eclipse.bpmn2.di.BPMNPlane; |
| import org.eclipse.bpmn2.di.BPMNShape; |
| import org.eclipse.bpmn2.di.BpmnDiPackage; |
| import org.eclipse.bpmn2.modeler.core.Activator; |
| import org.eclipse.bpmn2.modeler.core.LifecycleEvent; |
| import org.eclipse.bpmn2.modeler.core.LifecycleEvent.EventType; |
| import org.eclipse.bpmn2.modeler.core.adapters.ExtendedPropertiesAdapter; |
| import org.eclipse.bpmn2.modeler.core.adapters.IExtensionValueAdapter; |
| import org.eclipse.bpmn2.modeler.core.features.GraphitiConstants; |
| import org.eclipse.bpmn2.modeler.core.model.Bpmn2ModelerFactory.Bpmn2ModelerDocumentRootImpl; |
| import org.eclipse.bpmn2.modeler.core.model.Bpmn2ModelerFactory.KeyValue; |
| import org.eclipse.bpmn2.modeler.core.preferences.Bpmn2Preferences; |
| import org.eclipse.bpmn2.modeler.core.runtime.TargetRuntime; |
| import org.eclipse.bpmn2.modeler.core.runtime.TargetRuntimeAdapter; |
| import org.eclipse.bpmn2.modeler.core.runtime.TypeLanguageDescriptor; |
| import org.eclipse.bpmn2.modeler.core.utils.FeatureSupport; |
| import org.eclipse.bpmn2.modeler.core.utils.ImportUtil; |
| import org.eclipse.bpmn2.modeler.core.utils.ModelUtil; |
| import org.eclipse.bpmn2.modeler.core.utils.NamespaceUtil; |
| import org.eclipse.bpmn2.modeler.core.validation.SyntaxCheckerUtils; |
| import org.eclipse.bpmn2.util.Bpmn2ResourceImpl; |
| import org.eclipse.bpmn2.util.ImportHelper; |
| import org.eclipse.bpmn2.util.OnlyContainmentTypeInfo; |
| import org.eclipse.bpmn2.util.QNameURIHandler; |
| import org.eclipse.bpmn2.util.XmlExtendedMetadata; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.dd.dc.Bounds; |
| import org.eclipse.dd.dc.DcFactory; |
| import org.eclipse.dd.dc.DcPackage; |
| import org.eclipse.dd.dc.Point; |
| import org.eclipse.dd.di.DiPackage; |
| import org.eclipse.dd.di.DiagramElement; |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.ECollections; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.EMap; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EFactory; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.util.BasicFeatureMap; |
| import org.eclipse.emf.ecore.util.EObjectWithInverseEList; |
| import org.eclipse.emf.ecore.util.ExtendedMetaData; |
| import org.eclipse.emf.ecore.util.FeatureMap; |
| import org.eclipse.emf.ecore.util.FeatureMapUtil; |
| import org.eclipse.emf.ecore.xmi.XMLHelper; |
| import org.eclipse.emf.ecore.xmi.XMLLoad; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| import org.eclipse.emf.ecore.xmi.XMLSave; |
| import org.eclipse.emf.ecore.xmi.impl.ElementHandlerImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLLoadImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLString; |
| import org.eclipse.emf.ecore.xml.type.XMLTypePackage; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.wst.wsdl.Definition; |
| import org.eclipse.wst.wsdl.PortType; |
| import org.eclipse.wst.wsdl.util.WSDLResourceImpl; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| /** |
| * <!-- begin-user-doc --> The <b>Resource </b> associated with the package. |
| * |
| * @implements Bpmn2Resource <!-- end-user-doc --> |
| * @see org.eclipse.bpmn2.util.Bpmn2ResourceFactoryImpl |
| */ |
| public class Bpmn2ModelerResourceImpl extends Bpmn2ResourceImpl { |
| |
| public static final String BPMN2_CONTENT_TYPE_ID = "org.eclipse.bpmn2.content-type.xml"; //$NON-NLS-1$ |
| protected BpmnXmlHelper xmlHelper; |
| protected QNameURIHandler uriHandler; |
| public HashMap xmlNameToFeatureMap = new HashMap(); |
| protected static HashSet<EStructuralFeature> qnameMap = new HashSet<EStructuralFeature>(); |
| static { |
| qnameMap.add(Bpmn2Package.eINSTANCE.getExtension_Definition()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getRelationship_Sources()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getRelationship_Targets()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getAssociation_SourceRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getAssociation_TargetRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getGroup_CategoryValueRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCorrelationKey_CorrelationPropertyRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCorrelationProperty_Type()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCorrelationPropertyBinding_CorrelationPropertyRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCorrelationPropertyRetrievalExpression_MessageRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCorrelationSubscription_CorrelationPropertyBinding()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getError_StructureRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getEscalation_StructureRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getFlowElement_CategoryValueRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getFlowNode_Incoming()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getFlowNode_Outgoing()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getFormalExpression_EvaluatesToTypeRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getInputOutputBinding_OperationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getItemDefinition_StructureRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMessage_ItemRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getResourceParameter_Type()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getInterface_ImplementationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getOperation_InMessageRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getOperation_OutMessageRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getOperation_ErrorRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getOperation_ImplementationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCallConversation_CalledCollaborationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getConversationAssociation_InnerConversationNodeRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getConversationAssociation_OuterConversationNodeRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getConversationLink_SourceRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getConversationLink_TargetRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getConversationNode_MessageFlowRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getConversationNode_ParticipantRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getConversationNode_CorrelationKeys()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMessageFlow_SourceRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMessageFlow_TargetRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMessageFlow_MessageRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMessageFlowAssociation_InnerMessageFlowRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMessageFlowAssociation_OuterMessageFlowRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getParticipant_InterfaceRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getParticipant_EndPointRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getParticipant_ProcessRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getParticipantAssociation_InnerParticipantRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getParticipantAssociation_OuterParticipantRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCallableElement_SupportedInterfaceRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCallActivity_CalledElementRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMultiInstanceLoopCharacteristics_LoopDataInputRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMultiInstanceLoopCharacteristics_LoopDataOutputRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMultiInstanceLoopCharacteristics_OneBehaviorEventRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMultiInstanceLoopCharacteristics_NoneBehaviorEventRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getReceiveTask_MessageRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getReceiveTask_OperationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getResourceRole_ResourceRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getSendTask_MessageRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getSendTask_OperationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getServiceTask_OperationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getItemAwareElement_ItemSubjectRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getBoundaryEvent_AttachedToRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCatchEvent_EventDefinitionRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCompensateEventDefinition_ActivityRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getErrorEventDefinition_ErrorRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getEscalationEventDefinition_EscalationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getLinkEventDefinition_Source()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getLinkEventDefinition_Target()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMessageEventDefinition_OperationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getMessageEventDefinition_MessageRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getSignal_StructureRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getSignalEventDefinition_SignalRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getThrowEvent_EventDefinitionRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getProcess_Supports()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getProcess_DefinitionalCollaborationRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getLane_PartitionElementRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getGlobalChoreographyTask_InitiatingParticipantRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getChoreographyActivity_ParticipantRefs()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getChoreographyActivity_InitiatingParticipantRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getChoreographyTask_MessageFlowRef()); |
| qnameMap.add(Bpmn2Package.eINSTANCE.getCallChoreography_CalledChoreographyRef()); |
| qnameMap.add(BpmnDiPackage.eINSTANCE.getBPMNPlane_BpmnElement()); |
| qnameMap.add(BpmnDiPackage.eINSTANCE.getBPMNShape_BpmnElement()); |
| qnameMap.add(BpmnDiPackage.eINSTANCE.getBPMNShape_ChoreographyActivityShape()); |
| qnameMap.add(BpmnDiPackage.eINSTANCE.getBPMNEdge_BpmnElement()); |
| qnameMap.add(BpmnDiPackage.eINSTANCE.getBPMNEdge_SourceElement()); |
| qnameMap.add(BpmnDiPackage.eINSTANCE.getBPMNEdge_TargetElement()); |
| qnameMap.add(BpmnDiPackage.eINSTANCE.getBPMNLabel_LabelStyle()); |
| } |
| |
| public class OnlyNamedContainmentTypeInfo extends OnlyContainmentTypeInfo { |
| |
| public boolean shouldSaveType(EClass objectType, EClassifier featureType, EStructuralFeature feature) { |
| String name = ExtendedMetaData.INSTANCE.getName(objectType); |
| if (name==null || name.isEmpty()) |
| return false; |
| return super.shouldSaveType(objectType, featureType, feature); |
| } |
| |
| public boolean shouldSaveType(EClass objectType, EClass featureType, EStructuralFeature feature) { |
| String name = ExtendedMetaData.INSTANCE.getName(objectType); |
| if (name==null || name.isEmpty()) |
| return false; |
| return super.shouldSaveType(objectType, featureType, feature); |
| } |
| } |
| |
| /** |
| * Creates an instance of the resource. |
| * |
| * @param uri |
| * the URI of the new resource. |
| */ |
| public Bpmn2ModelerResourceImpl(URI uri) { |
| super(uri); |
| |
| // override helper and uri handler in options map |
| this.xmlHelper = (BpmnXmlHelper)createXMLHelper(); |
| this.uriHandler = new FragmentQNameURIHandler(xmlHelper); |
| uriHandler.setBaseURI(uri); |
| |
| this.getDefaultLoadOptions().put(XMLResource.OPTION_URI_HANDLER, uriHandler); |
| this.getDefaultLoadOptions().put(XMLResource.OPTION_DEFER_IDREF_RESOLUTION, true); |
| this.getDefaultLoadOptions().put(XMLResource.OPTION_DISABLE_NOTIFY, true); |
| this.getDefaultSaveOptions().put(XMLResource.OPTION_URI_HANDLER, uriHandler); |
| |
| ExtendedMetaData extendedMetadata = new XmlExtendedMetadata(); |
| this.getDefaultSaveOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetadata); |
| this.getDefaultLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetadata); |
| this.getDefaultSaveOptions().put(XMLResource.OPTION_SAVE_TYPE_INFORMATION, new OnlyNamedContainmentTypeInfo()); |
| this.getDefaultSaveOptions().put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); |
| this.getDefaultLoadOptions().put(XMLResource.OPTION_USE_LEXICAL_HANDLER, Boolean.TRUE); |
| this.getDefaultSaveOptions().put(XMLResource.OPTION_ELEMENT_HANDLER, new ElementHandlerImpl(true)); |
| this.getDefaultSaveOptions().put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$ |
| this.getDefaultSaveOptions().put(XMLResource.OPTION_USE_CACHED_LOOKUP_TABLE, new ArrayList<Object>()); |
| |
| // some interesting things to play with: |
| // this.getDefaultLoadOptions().put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, true); |
| // this.getDefaultLoadOptions().put(XMLResource.OPTION_LAX_WILDCARD_PROCESSING, true); |
| // this.getDefaultLoadOptions().put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, true); |
| // this.getDefaultLoadOptions().put(XMLResource.OPTION_ANY_TYPE, BpmnDiPackage.eINSTANCE.getBPMNPlane()); |
| this.getDefaultLoadOptions().put(XMLResource.OPTION_USE_XML_NAME_TO_FEATURE_MAP, xmlNameToFeatureMap); |
| |
| // only necessary if this resource will not be added to a ResourceSet instantly |
| this.eAdapters().add(oppositeReferenceAdapter); |
| } |
| |
| @Override |
| public void load(Map<?, ?> options) throws IOException { |
| try { |
| Bpmn2ModelerFactory.lock(); |
| Bpmn2ModelerFactory.setEnableModelExtensions(false); |
| super.load(options); |
| } |
| finally { |
| Bpmn2ModelerFactory.setEnableModelExtensions(true); |
| Bpmn2ModelerFactory.setResource(null); |
| Bpmn2ModelerFactory.unlock(); |
| } |
| } |
| |
| public void save(Map<?, ?> options) throws IOException { |
| uriHandler.setBaseURI(getURI()); |
| xmlHelper.setResource(this); |
| super.save(options); |
| } |
| |
| @Override |
| protected XMLHelper createXMLHelper() { |
| if (xmlHelper!=null) |
| return xmlHelper; |
| return new Bpmn2ModelerXmlHelper(this); |
| } |
| |
| /** |
| * Override this method to hook in our own XmlHandler |
| */ |
| @Override |
| protected XMLLoad createXMLLoad() { |
| XMLLoad xmlLoad = new XMLLoadImpl(createXMLHelper()) { |
| Bpmn2ModelerXmlHandler handler; |
| |
| @Override |
| protected DefaultHandler makeDefaultHandler() { |
| handler = new Bpmn2ModelerXmlHandler(resource, helper, options); |
| return handler; |
| } |
| |
| @Override |
| public void load(XMLResource resource, InputStream inputStream, Map<?, ?> options) throws IOException { |
| try { |
| super.load(resource, inputStream, options); |
| } |
| catch (Exception e) { |
| e.printStackTrace(); |
| BPMNDiagnostic error = new BPMNDiagnostic(e.getMessage()); |
| error.setLine(handler.getLineNumber()); |
| error.setColumn(handler.getColumnNumber()); |
| error.setLocation(handler.getLocation()); |
| if (!resource.getErrors().contains(error)) |
| resource.getErrors().add(error); |
| throw new IOException(e); |
| } |
| } |
| }; |
| return xmlLoad; |
| } |
| |
| static class BPMNDiagnostic implements Resource.Diagnostic { |
| |
| private String message; |
| private String location; |
| private int column; |
| private int line; |
| |
| public BPMNDiagnostic(String message) { |
| this.message = message; |
| } |
| |
| public void setLocation(String location) { |
| this.location = location; |
| } |
| |
| public String getLocation() { |
| return location; |
| } |
| |
| public void setColumn(int column) { |
| this.column = column;; |
| } |
| |
| public int getColumn() { |
| return column; |
| } |
| |
| public void setLine(int line) { |
| this.line = line; |
| } |
| |
| public int getLine() { |
| return line; |
| } |
| |
| public String getMessage() { |
| return message; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof BPMNDiagnostic) { |
| BPMNDiagnostic that = (BPMNDiagnostic)obj; |
| return |
| (this.message!=null && this.message.equals(that.message)) && |
| this.line==that.line && |
| this.column==that.column; |
| } |
| else if (obj instanceof Exception) { |
| String message = ((Exception)obj).getMessage(); |
| return message.equals(this.message); |
| } |
| return super.equals(obj); |
| } |
| } |
| |
| @Override |
| protected XMLSave createXMLSave() { |
| prepareSave(); |
| return new Bpmn2ModelerXMLSave(createXMLHelper()) { |
| }; |
| } |
| |
| @Override |
| protected void prepareSave() { |
| EObject cur; |
| // Definitions definitions = ImportHelper.getDefinitions(this); |
| for (Iterator<EObject> iter = getAllContents(); iter.hasNext();) { |
| cur = iter.next(); |
| |
| setDefaultId(cur); |
| |
| // for (EObject referenced : cur.eCrossReferences()) { |
| // setDefaultId(referenced); |
| // if (definitions != null) { |
| // Resource refResource = referenced.eResource(); |
| // if (refResource != null && refResource != this) { |
| // createImportIfNecessary(definitions, refResource); |
| // } |
| // } |
| // } |
| } |
| } |
| |
| /** |
| * Generate an ID attribute for the given BPMN2 element if not already set. |
| * |
| * @param obj |
| * The object whose ID should be set. |
| */ |
| private void setDefaultId(EObject obj) { |
| if (obj.eClass() != null) { |
| EStructuralFeature idAttr = obj.eClass().getEIDAttribute(); |
| if (idAttr != null && !obj.eIsSet(idAttr)) { |
| obj.eSetDeliver(false); |
| ModelUtil.setID(obj); |
| obj.eSetDeliver(true); |
| } |
| } |
| } |
| |
| @Override |
| public void setURI(URI uri) { |
| super.setURI(uri); |
| xmlHelper.setResource(this); |
| uriHandler.setBaseURI(uri); |
| } |
| |
| /** |
| * We need to extend the standard SAXXMLHandler to hook into the handling of |
| * attribute references which may be either simple ID Strings or QNames. |
| * We'll search through all of the objects' IDs first to find the one we're |
| * looking for. If not, we'll try a QName search. |
| */ |
| protected static class Bpmn2ModelerXmlHandler extends BpmnXmlHandler { |
| |
| protected Bpmn2Preferences preferences = null; |
| protected ImportUtil importHandler = new ImportUtil(); |
| protected String targetNamespace = null; |
| |
| public Bpmn2ModelerXmlHandler(XMLResource xmiResource, XMLHelper helper, Map<?, ?> options) { |
| super(xmiResource, helper, options); |
| } |
| |
| /** |
| * Subclasses should override this to provide their own namespace URI. |
| * Default is to use that "targetNamespace" attribute in the <definitions> element. |
| * @param defs |
| * @return |
| */ |
| protected String getTargetNamespace(Definitions defs) { |
| return defs.getTargetNamespace(); |
| } |
| |
| @Override |
| public void startDocument() { |
| Bpmn2ModelerFactory.setResource(xmlResource); |
| preferences = Bpmn2Preferences.getInstance(xmlResource); |
| super.startDocument(); |
| } |
| |
| @Override |
| public void endDocument() { |
| super.endDocument(); |
| // Make sure there's a namespace prefix definition for typeLanguage. |
| // We'll need that prefix to qualify data types defined in the type language. |
| Definitions definitions = ModelUtil.getDefinitions(xmlResource); |
| String typeLanguage = definitions.getTypeLanguage(); |
| if (typeLanguage!=null) { |
| String prefix = NamespaceUtil.getPrefixForNamespace(helper.getResource(), typeLanguage); |
| if (prefix==null) { |
| TargetRuntime rt = TargetRuntime.getRuntime(xmlResource); |
| TypeLanguageDescriptor tld = rt.getTypeLanguageDescriptor(typeLanguage); |
| if (tld!=null) |
| prefix = tld.getPrefix(); |
| NamespaceUtil.addNamespace(helper.getResource(), prefix, typeLanguage); |
| } |
| } |
| // Load all of the Imports and generate Interfaces, Operations, Messages, Faults and ItemDefinitions |
| for (Import imp : definitions.getImports()) { |
| try { |
| Object importObject = importHandler.loadImport(imp); |
| if (importObject!=null) { |
| importHandler.addImportObjects(imp, importObject); |
| } |
| } |
| catch (Exception e) { |
| BPMNDiagnostic error = new BPMNDiagnostic(e.getMessage()); |
| error.setLine(getLineNumber()); |
| error.setColumn(getColumnNumber()); |
| error.setLocation(getLocation()); |
| xmlResource.getErrors().add(error); |
| } |
| } |
| |
| // Fix up the descriptions for BPMNDiagrams |
| for (BPMNDiagram d : definitions.getDiagrams()) { |
| // Set the diagram's description AFTER it has been completely populated |
| ExtendedPropertiesAdapter epa = ExtendedPropertiesAdapter.adapt(d); |
| if (epa!=null) { |
| epa.setProperty(ExtendedPropertiesAdapter.LONG_DESCRIPTION, epa.getDescription(d)); |
| } |
| } |
| } |
| |
| @Override |
| protected void handleForwardReferences(boolean isEndDocument) { |
| if (isEndDocument) { |
| List<SingleReference> resolved = new ArrayList<SingleReference>(); |
| for (SingleReference ref : forwardSingleReferences) { |
| EObject referencedObject = null; |
| try { |
| referencedObject = xmlResource.getEObject((String) ref.getValue()); |
| } catch (RuntimeException exception) {} |
| if (referencedObject==null) { |
| // The forward reference may be in an external document. |
| // Check the reference type and its owner, then search |
| // external documents contained in the same project. |
| EObject referencingObject = ref.getObject(); |
| EStructuralFeature referencingFeature = ref.getFeature(); |
| String id = (String) ref.getValue(); |
| referencedObject = importHandler.resolveExternalReference(referencingObject, referencingFeature, id); |
| if (referencedObject != null) { |
| resolved.add(ref); |
| if (shouldResolveExternals(referencingObject, referencedObject, id)) { |
| importHandler.addImport(xmlResource, ModelUtil.getDefinitions(referencedObject)); |
| xmlResource.getResourceSet().getResources().add(referencedObject.eResource()); |
| setFeatureValue(referencingObject, referencingFeature, referencedObject, ref.getPosition()); |
| } |
| } |
| } |
| } |
| if (!resolved.isEmpty()) |
| forwardSingleReferences.removeAll(resolved); |
| } |
| super.handleForwardReferences(isEndDocument); |
| } |
| |
| /** |
| * Check if the loader should allow external references to other files |
| * in the project. This is controlled by a User Preference setting. |
| * |
| * @param referencingObject the object referencing an external object. |
| * @param referencedObject the referenced object contained in another |
| * file in the project. |
| * @param id the ID string of the referenced object. |
| * @return true if externals should be resolved, false to cause an error |
| * for missing references. |
| */ |
| private boolean shouldResolveExternals(EObject referencingObject, EObject referencedObject, String id) { |
| if (preferences.getResolveExternals()==0) |
| return false; |
| if (preferences.getResolveExternals()==1) |
| return true; |
| try { |
| Resource resource = referencedObject.eResource(); |
| IPath path = new Path(resource.getURI().toPlatformString(true)); |
| boolean doit = MessageDialog.openQuestion(new Shell(), |
| Messages.Bpmn2ModelerResourceSetImpl_External_Reference_Found_Title, |
| NLS.bind( |
| Messages.Bpmn2ModelerResourceSetImpl_External_Reference_Found_Message, |
| new Object[] { |
| referencedObject.eClass().getName(), |
| id, |
| ModelUtil.getLabel(referencingObject)+" \""+ModelUtil.getName((BaseElement)referencingObject)+"\"", //$NON-NLS-1$ //$NON-NLS-2$ |
| path.toString()} |
| ) |
| ); |
| return doit; |
| } |
| catch (Exception e) {} |
| return true; |
| } |
| |
| @Override |
| protected EStructuralFeature getFeature(EObject object, String prefix, String name, boolean isElement) { |
| EStructuralFeature feature = null; |
| String nsURI = (prefix==null ? targetNamespace : helper.getURI(prefix)); |
| ModelDecorator md = ModelDecorator.getModelDecorator(nsURI); |
| if (md!=null) { |
| feature = md.getEStructuralFeature(object, name); |
| if (feature!=null) { |
| // System.out.println("found feature "+object.eClass().getName()+"."+name+" in pkg "+pkg.getName()); |
| return feature; |
| } |
| } |
| feature = super.getFeature(object, prefix, name, isElement); |
| // if (feature!=null) |
| // System.out.println("found feature "+object.eClass().getName()+"."+name); |
| // else |
| // System.out.println("feature "+prefix+":"+name+" not found!!!"); |
| return feature; |
| } |
| |
| @Override |
| protected EObject createObjectFromFeatureType(EObject peekObject, EStructuralFeature feature) { |
| int lineNumber = getLineNumber(); |
| EObject newObject = null; |
| String nsURI = ExtendedMetaData.INSTANCE.getNamespace(feature); |
| EPackage pkg = ModelDecorator.getEPackage(nsURI); |
| if (pkg!=null) { |
| EClassifier eType = feature.getEType(); |
| |
| newObject = pkg.getEFactoryInstance().create((EClass)eType); |
| |
| // ModelDecoratorAdapter mda = AdapterUtil.adapt(pkg, ModelDecoratorAdapter.class); |
| // feature = mda.getEStructuralFeature(peekObject, feature); |
| if (feature!=null) { |
| ExtendedPropertiesAdapter epa = ExtendedPropertiesAdapter.adapt(peekObject); |
| if (epa!=null) { |
| epa.getFeatureDescriptor(feature).setValue(newObject); |
| processObject(newObject); |
| handleObjectAttribs(newObject); |
| } |
| } |
| } |
| else { |
| newObject = super.createObjectFromFeatureType(peekObject, feature); |
| } |
| |
| if (newObject!=null) { |
| ExtendedPropertiesAdapter epa = ExtendedPropertiesAdapter.adapt(newObject); |
| if (epa!=null) { |
| epa.setProperty(ExtendedPropertiesAdapter.LINE_NUMBER, lineNumber); |
| } |
| } |
| |
| return newObject; |
| } |
| |
| protected EObject validateCreateObjectFromFactory(EFactory factory, String typeName, EObject newObject, EStructuralFeature feature) { |
| if (newObject != null) { |
| TargetRuntime rt = TargetRuntime.getRuntime(xmlResource); |
| String id = rt.getCustomTaskId(newObject); |
| if (id!=null) { |
| // if this is a CustomElement we need to discard this object and construct it |
| // properly such that all extension attributes and elements are created and |
| // initialized. |
| newObject = Bpmn2ModelerFactory.create(xmlResource, newObject.eClass(), |
| new KeyValue(GraphitiConstants.CUSTOM_ELEMENT_ID, id)); |
| handleObjectAttribs(newObject); |
| } |
| } |
| return super.validateCreateObjectFromFactory(factory, typeName, newObject, feature); |
| } |
| |
| @Override |
| protected void setFeatureValue(EObject object, EStructuralFeature feature, Object value, int position) { |
| ModelDecorator md = ModelDecorator.getModelDecorator(feature); |
| if (md!=null) { |
| EStructuralFeature f = md.getEStructuralFeature(object, feature.getName()); |
| if (f!=null) { |
| ExtendedPropertiesAdapter epa = ExtendedPropertiesAdapter.adapt(object); |
| epa.getFeatureDescriptor(f).setValue(value, position); |
| return; |
| } |
| |
| // ExtendedPropertiesAdapter epa = ExtendedPropertiesAdapter.adapt(object); |
| // epa.getFeatureDescriptor(feature).setValue(value, position); |
| } |
| super.setFeatureValue(object, feature, value, position); |
| } |
| |
| @Override |
| protected void handleObjectAttribs(EObject obj) { |
| if (obj instanceof BPMNShape) { |
| // Enable immediate ID resolution because we need to link up |
| // the BPMNShape's "bpmnElement" reference. This is required |
| // by the Bpmn2Preferences so it can determine how to handle |
| // certain DI attributes, e.g. isHorizontal, isExpanded, etc. |
| deferIDREFResolution = false; |
| } |
| |
| super.handleObjectAttribs(obj); |
| |
| String xmlns = null; |
| String tns = null; |
| if (attribs != null) { |
| for (int i = 0, size = attribs.getLength(); i < size; ++i) { |
| String name = attribs.getQName(i); |
| if (name.equals(XMLResource.XML_NS)) { |
| // create an ns prefix in the prefix map for this default namespace |
| // and qualify any qnameFeatures contained in this object... |
| xmlns = attribs.getValue(i); |
| for (EStructuralFeature f : obj.eClass().getEAllStructuralFeatures()) { |
| if (qnameMap.contains(f)) { |
| Object value = obj.eGet(f); |
| if (ModelUtil.isStringWrapper(value)) { |
| String localpart = ModelUtil.getStringWrapperValue(value); |
| if (localpart!=null && !localpart.isEmpty() && !localpart.contains(":")) { //$NON-NLS-1$ |
| String prefix = helper.getPrefix(xmlns); |
| if (prefix==null || prefix.isEmpty()) { |
| for (int index = 0; true; ++index) { |
| prefix = "ns" + index; //$NON-NLS-1$ |
| String ns = helper.getPrefixToNamespaceMap().get(prefix); |
| if (ns==null) |
| break; |
| } |
| helper.addPrefix(prefix, xmlns); |
| } |
| ModelUtil.setStringWrapperValue(value, prefix + ":" + localpart); //$NON-NLS-1$ |
| } |
| } |
| } |
| } |
| } |
| else if (name.startsWith(XMLResource.XML_NS+":")) { //$NON-NLS-1$ |
| String prefix = name.substring(name.indexOf(':')+1); |
| String namespace = attribs.getValue(i); |
| NamespaceUtil.addNamespace(xmlResource, prefix, namespace); |
| } |
| else if (name.equals("tns")) { |
| tns = attribs.getValue(i); |
| } |
| } |
| } |
| |
| if (obj instanceof BPMNShape) { |
| // Defer ID resolution until after resource is loaded. |
| // See above. |
| deferIDREFResolution = true; |
| BPMNShape bpmnShape = (BPMNShape)obj; |
| Hashtable<String,String> map = new Hashtable<String,String>(); |
| if (attribs != null) { |
| for (int i = 0, size = attribs.getLength(); i < size; ++i) { |
| String key = attribs.getQName(i); |
| String value = attribs.getValue(i); |
| map.put(key, value); |
| } |
| preferences.applyBPMNDIDefaults(bpmnShape, map); |
| } |
| } |
| else if (obj instanceof ItemDefinition) { |
| ItemDefinition itemDef = (ItemDefinition)obj; |
| |
| Definitions definitions = ModelUtil.getDefinitions(xmlResource); |
| URI referencingURI = ImportHelper.makeURICanonical(resourceURI); |
| String location = ModelUtil.getStringWrapperValue(itemDef.getStructureRef()); |
| if (location!=null) { |
| int i = location.indexOf("$"); //$NON-NLS-1$ |
| if (i>0) |
| location = location.substring(0,i); |
| URI uri = URI.createURI(location).resolve(referencingURI); |
| uri = uri.trimFragment(); |
| Import imp = ImportHelper.findImportForLocation(definitions, uri); |
| itemDef.setImport(imp); |
| } |
| } |
| /* it's already too late at this point to identify targetNamespace - see createDocumentRoot() |
| else if (obj instanceof Definitions) { |
| // Fetch the targetNamespace from Definitions object: |
| // this is where we allow the TargetRuntime extension to provide |
| // its own targetNamespace if the file doesn't define one. |
| // The targetNamespace determines the TargetRuntime and therefore |
| // how the file is handled, since the TargetRuntime may have special |
| // processing that needs to be done during loading. Therefore, |
| // it's important that we have a targetNamespace after the <definitions> |
| // element is parsed, or the remainder of the file may not be processed |
| // correctly. |
| targetNamespace = getTargetNamespace((Definitions)obj); |
| // if targetNamespace is not provided, use "tns" from file |
| if (targetNamespace==null && tns!=null && !tns.isEmpty()) |
| targetNamespace = tns; |
| // if that didn't work, try "xmlns" |
| if (targetNamespace==null && xmlns!=null && !xmlns.isEmpty()) |
| targetNamespace = xmlns; |
| // if that still didn't work use the default namespace |
| if (targetNamespace==null) |
| targetNamespace = TargetRuntime.getDefaultRuntime().getRuntimeExtension().getTargetNamespace(null); |
| ((Bpmn2ModelerXmlHelper)helper).initializeTargetRuntime(targetNamespace); |
| |
| } |
| */ |
| |
| } |
| |
| protected EObject createDocumentRoot(String prefix, String uri, String name, EFactory eFactory, boolean top) { |
| // Fetch the targetNamespace from DocumentRoot (<definitions>) object: |
| // this is where we allow the TargetRuntime extension to provide |
| // its own targetNamespace if the file doesn't define one, by overriding |
| // the Bpmn2ModelerXmlHandler#getTargetNamespace(Definitions) method. |
| // The targetNamespace determines the TargetRuntime and therefore |
| // how the file is handled, since the TargetRuntime may have special |
| // processing that needs to be done during loading. Therefore, |
| // it's important that we have a targetNamespace after the <definitions> |
| // element is parsed, or the remainder of the file may not be processed |
| // correctly. |
| // |
| // TargetNamespace identification needs to happen very early in the resource |
| // load process, sometime before the first EObject is created by Bpmn2ModelerFactory |
| Definitions definitions = Bpmn2Factory.eINSTANCE.createDefinitions(); |
| String tns = null; |
| String xmlns = null; |
| for (int i = 0, size = attribs.getLength(); i < size; ++i) { |
| String attrib = attribs.getQName(i); |
| if (attrib.equals("tns")) { |
| tns = attribs.getValue(i); |
| } |
| else if (attrib.equals("targetNamespace")) { |
| targetNamespace = attribs.getValue(i); |
| definitions.setTargetNamespace(targetNamespace); |
| } |
| else if (attrib.equals(XMLResource.XML_NS)) { |
| xmlns = attribs.getValue(i); |
| } |
| } |
| targetNamespace = getTargetNamespace(definitions); |
| // if targetNamespace is not provided, use "tns" from file |
| if (targetNamespace==null && tns!=null && !tns.isEmpty()) |
| targetNamespace = tns; |
| // if that didn't work, try "xmlns" |
| if (targetNamespace==null && xmlns!=null && !xmlns.isEmpty()) |
| targetNamespace = xmlns; |
| // if that still didn't work use the default namespace |
| if (targetNamespace==null) |
| targetNamespace = TargetRuntime.getDefaultRuntime().getRuntimeExtension().getTargetNamespace(null); |
| ((Bpmn2ModelerXmlHelper)helper).initializeTargetRuntime(targetNamespace); |
| |
| return super.createDocumentRoot(prefix, uri, name, eFactory, top); |
| } |
| |
| /** |
| * Overridden to be able to convert ID references in attributes to URIs |
| * during load. If the reference can't be found by its ID, we'll try a |
| * QName search (done in the super class) |
| * |
| * @param ids |
| * In our case the parameter will contain exactly one ID that |
| * we resolve to URI. |
| */ |
| @Override |
| protected void setValueFromId(EObject object, EReference eReference, String ids) { |
| |
| Object value = null; |
| // Handle QNames and arbitrary strings in BPMN2 element references |
| if ( qnameMap.contains(eReference) ) { |
| // This reference might be a QName (according to the BPMN2 spec!) |
| // or it might not, in the case of some jBPM Java type references. |
| int i = ids.indexOf(":"); //$NON-NLS-1$ |
| if (i>0) { |
| // if the ID string is a QName, try to resolve and load the object |
| String prefix = ids.substring(0,i); |
| String localname = ids.substring(i+1); |
| String namespace = helper.getNamespaceURI(prefix); |
| if (namespace!=null && namespace.equals(targetNamespace)) { |
| // namespace for prefix is the same as targetNamespace |
| // so remove the prefix to avoid confusing the XMLHandler |
| ids = localname; |
| } |
| else { |
| // this thing is in another namespace, possibly in an external document |
| Import imp = importHandler.findImportForNamespace(helper.getResource(), namespace); |
| if (imp!=null) { |
| value = importHandler.getObjectForId(imp, object, eReference, ids); |
| } |
| } |
| } |
| |
| if (value==null) { |
| // we can't find the object in any of our imports, |
| // so create a string wrapper EObject for this thing |
| value = ModelUtil.createStringWrapper(ids); |
| } |
| |
| if (value!=null && eReference.getEType().isInstance(value)) { |
| try { |
| if (eReference.isMany()) { |
| ((EList)object.eGet(eReference)).add(value); |
| } |
| else { |
| object.eSet(eReference, value); |
| } |
| return; |
| } catch (Exception e) { |
| String msg = NLS.bind( |
| Messages.Bpmn2ModelerResourceImpl_Invalid_Reference, |
| new Object[] {object, eReference, value}); |
| IStatus s = new Status(Status.ERROR, Activator.PLUGIN_ID, |
| msg, e); |
| Activator.getDefault().logStatus(s); |
| } |
| } |
| } |
| |
| // And yet another hack to deal with files generated by Savara: |
| // Savara creates some object references as QNames and, while the |
| // "Official" BPMN 2.0 xsd says these SHOULD be QNames, the bpmn2 EMF |
| // model has these defined as "resolveProxies=false" which means they |
| // will NOT get resolved. |
| if (/*!eReference.isResolveProxies() && */ids.contains(":")) { //$NON-NLS-1$ |
| // Resolve QNames here: if they are internal objects, |
| // simply replace the ID string with the URI fragment. |
| // If they are not internal objects, then there's a |
| // problem with the file! |
| String resolvedId = ((QNameURIHandler) uriHandler).convertQNameToUri(ids); |
| URI resolvedURI = URI.createURI(resolvedId); |
| URI resourceURI = xmlResource.getURI(); |
| if (resolvedURI.trimFragment().equals(resourceURI)) |
| ids = resolvedURI.fragment(); |
| } |
| super.setValueFromId(object, eReference, ids); |
| } |
| |
| public int getLineNumber() { |
| return super.getLineNumber(); |
| } |
| |
| public int getColumnNumber() { |
| return super.getColumnNumber(); |
| } |
| |
| public String getLocation() { |
| return super.getLocation(); |
| } |
| |
| @Override |
| public void startElement(String uri, String localName, String name) { |
| super.startElement(uri, localName, name); |
| EObject peekObject = objects.peekEObject(); |
| // if (peekObject instanceof Definitions) { |
| // // create all model extensions for this target runtime so that all |
| // // extension attributes and elements are available during loading. |
| // TargetRuntime rt = TargetRuntime.getCurrentRuntime(); |
| // rt.createModelExtensions(peekObject.eResource()); |
| // } |
| if (peekObject!=null && peekObject.getClass()==Expression.class) { |
| // If the element is an Expression (not a FormalExpression) then use the CDATA |
| // as the body of a Formal Expression (because Expression does not have a body) |
| text = new StringBuffer(); |
| } |
| } |
| |
| @Override |
| public void endElement(String uri, String localName, String name) { |
| EObject peekObject = objects.peek(); |
| if (peekObject!=null && peekObject.getClass()==Expression.class) { |
| // if the element is an Expression, replace it with a FormalExpression and set |
| // its body using the CDATA of the Expression element. |
| FormalExpression fe = Bpmn2Factory.eINSTANCE.createFormalExpression(); |
| EObject owner = peekObject.eContainer(); |
| if (owner!=null) { |
| for (EStructuralFeature f : owner.eClass().getEAllStructuralFeatures()) { |
| if (owner.eGet(f) == peekObject) { |
| owner.eSet(f, fe); |
| break; |
| } |
| } |
| objects.pop(); |
| objects.push(fe); |
| types.pop(); |
| types.push(Bpmn2Package.eINSTANCE.getFormalExpression_Body()); |
| |
| EStructuralFeature mixedFeature = extendedMetaData.getMixedFeature(fe.eClass()); |
| if (mixedFeature != null) |
| { |
| mixedTargets.push((FeatureMap)fe.eGet(mixedFeature)); |
| } |
| else |
| { |
| mixedTargets.push(null); |
| } |
| } |
| } |
| super.endElement(uri, localName, name); |
| TargetRuntime rt = TargetRuntime.getRuntime(xmlResource); |
| LifecycleEvent.notify(new LifecycleEvent(EventType.BUSINESSOBJECT_LOADED, peekObject, rt)); |
| } |
| } |
| |
| public class Bpmn2ModelerXMLSave extends XMLSaveImpl { |
| protected float minX = Float.MAX_VALUE; |
| protected float minY = Float.MAX_VALUE; |
| protected int lineNum = 1; |
| protected int lineOffset = 0; |
| protected Bpmn2Preferences preferences; |
| |
| @SuppressWarnings("serial") |
| protected class Bpmn2ModelerXMLString extends XMLString { |
| public Bpmn2ModelerXMLString(String publicId, String systemId) { |
| super(Integer.MAX_VALUE, publicId, systemId, null); |
| } |
| @Override |
| public void addAttribute(String name, String value) { |
| // This special little hack removes namespace declarations |
| // and schemaLocation attributes for the XSI namespace if the prefix |
| // is anything other than "xsi". The EMF serializers rely on the fact |
| // that the XSI namespace prefix is ALWAYS "xsi" and they WILL create |
| // a duplicate namespace declaration if one already existed under a |
| // different prefix. This would result a nasty warning from the parser. |
| if (XSI_URI.equals(value) && name.startsWith("xmlns:")) { //$NON-NLS-1$ |
| int i = name.indexOf(":"); //$NON-NLS-1$ |
| String prefix = name.substring(i+1); |
| if (!ExtendedMetaData.XSI_PREFIX.equals(prefix)) |
| return; |
| } |
| if (name.contains(":schemaLocation")) { //$NON-NLS-1$ |
| if (!XSI_SCHEMA_LOCATION.equals(name)) |
| return; |
| } |
| super.addAttribute(name, value); |
| } |
| |
| @Override |
| public void addAttributeNS(String prefix, String localName, String value) { |
| // Same hack as above - see comments. |
| if (XSI_URI.equals(value) && !ExtendedMetaData.XSI_PREFIX.equals(localName)) |
| return; |
| super.addAttributeNS(prefix, localName, value); |
| } |
| |
| @Override |
| public void addLine() { |
| ++lineNum; |
| super.addLine(); |
| lineOffset = getLength(); |
| } |
| |
| public int getLineNum() { |
| return lineNum; |
| } |
| |
| @Override |
| public void addAttributeContent(String content) { |
| // convert to XML string with entities |
| super.addAttributeContent(SyntaxCheckerUtils.toXMLString(content)); |
| } |
| |
| public int getColumnNum() { |
| return getLength() - lineOffset + 1; |
| } |
| }; |
| |
| public Bpmn2ModelerXMLSave(XMLHelper helper) { |
| super(helper); |
| helper.getPrefixToNamespaceMap().clear(); |
| preferences = Bpmn2Preferences.getInstance(helper.getResource()); |
| } |
| |
| @Override |
| protected void addNamespaceDeclarations() { |
| EMap<String,String> map = helper.getPrefixToNamespaceMap(); |
| Definitions definitions = ModelUtil.getDefinitions(helper.getResource()); |
| String typeLanguage = definitions.getTypeLanguage(); |
| if (!map.containsValue(typeLanguage)) { |
| String prefix = "tl"; //$NON-NLS-1$ |
| TargetRuntime rt = TargetRuntime.getRuntime(xmlResource); |
| TypeLanguageDescriptor tld = rt.getTypeLanguageDescriptor(typeLanguage); |
| if (tld!=null) |
| prefix = tld.getPrefix(); |
| doc.addAttributeNS(XMLResource.XML_NS, prefix, typeLanguage); |
| } |
| super.addNamespaceDeclarations(); |
| } |
| |
| @Override |
| protected void init(XMLResource resource, Map<?, ?> options) { |
| super.init(resource, options); |
| featureTable = new Bpmn2ModelerXMLSave.Bpmn2Lookup(map, extendedMetaData, elementHandler); |
| |
| final List<BPMNDiagram> diagrams = getAll(BPMNDiagram.class, resource); |
| for (BPMNDiagram bpmnDiagram : diagrams) { |
| findMinXY(bpmnDiagram); |
| } |
| |
| doc = createXMLString(); |
| |
| if (contents.size()>0 && contents.get(0) instanceof Bpmn2ModelerDocumentRootImpl) { |
| Bpmn2ModelerDocumentRootImpl documentRoot = (Bpmn2ModelerDocumentRootImpl)contents.get(0); |
| Definitions definitions = ModelUtil.getDefinitions(helper.getResource()); |
| try { |
| documentRoot.setDeliver(false); |
| documentRoot.eSetDeliver(false); |
| FeatureMap featureMap = documentRoot.getMixed(); |
| if (featureMap.size()>0) { |
| // insert a comment before the Definitions node |
| String comment = " origin at X="+(minX<0 ? minX : 0)+ //$NON-NLS-1$ |
| " Y="+(minY<0 ? minY : 0)+" "; //$NON-NLS-1$ //$NON-NLS-2$ |
| if (featureMap.get(0).getEStructuralFeature() != XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__COMMENT) { |
| featureMap.add(0,XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__COMMENT, comment); |
| } |
| else { |
| FeatureMap.Entry e = FeatureMapUtil.createEntry(XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__COMMENT, comment); |
| featureMap.set(0, e); |
| } |
| } |
| definitions.eSetDeliver(false); |
| definitions.setExporter(Activator.PLUGIN_ID); |
| String version = Platform.getBundle(Activator.PLUGIN_ID).getHeaders().get("Bundle-Version"); //$NON-NLS-1$ |
| version = version.replaceAll(".qualifier", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| definitions.setExporterVersion(version); |
| } |
| finally { |
| documentRoot.setDeliver(true); |
| documentRoot.eSetDeliver(true); |
| definitions.eSetDeliver(true); |
| } |
| } |
| } |
| |
| protected XMLString createXMLString() { |
| return new Bpmn2ModelerXMLString(publicId, systemId); |
| } |
| |
| protected Bpmn2ModelerXMLString getXMLString() { |
| if (doc==null) { |
| createXMLString(); |
| } |
| return (Bpmn2ModelerXMLString)doc; |
| } |
| |
| @Override |
| protected void endSave(List<? extends EObject> contents) throws IOException |
| { |
| Bpmn2ModelerDocumentRootImpl documentRoot = null; |
| if (contents.size()>0 && contents.get(0) instanceof Bpmn2ModelerDocumentRootImpl) { |
| documentRoot = (Bpmn2ModelerDocumentRootImpl)contents.get(0); |
| documentRoot.setDeliver(false); |
| documentRoot.eSetDeliver(false); |
| } |
| |
| try { |
| super.endSave(contents); |
| } |
| finally { |
| if (documentRoot!=null) { |
| documentRoot.setDeliver(true); |
| documentRoot.eSetDeliver(true); |
| } |
| } |
| } |
| |
| @Override |
| protected boolean shouldSaveFeature(EObject o, EStructuralFeature f) { |
| if (o instanceof BPMNShape) { |
| BPMNShape s = (BPMNShape)o; |
| if (f==BpmnDiPackage.eINSTANCE.getBPMNShape_IsExpanded()) { |
| if (FeatureSupport.isExpandableElement(s.getBpmnElement())) |
| return true; |
| } |
| if (f==BpmnDiPackage.eINSTANCE.getBPMNShape_IsHorizontal()) { |
| if (s.getBpmnElement() instanceof Lane || s.getBpmnElement() instanceof Participant) |
| return true; |
| } |
| } |
| |
| // we also want to store x and y with value zero, would be skipped because of default value otherwise |
| if (o instanceof Bounds || o instanceof Point) { |
| return true; |
| } |
| |
| if (o instanceof Process && f==Bpmn2Package.eINSTANCE.getProcess_IsExecutable()) |
| return true; |
| if (o instanceof ItemDefinition && f==Bpmn2Package.eINSTANCE.getItemDefinition_IsCollection()) |
| return true; |
| if (o instanceof CompensateEventDefinition && f==Bpmn2Package.eINSTANCE.getCompensateEventDefinition_WaitForCompletion()) |
| return true; |
| |
| // empty Expressions should not be saved |
| if (f!=null && (f.getEType() == Bpmn2Package.eINSTANCE.getExpression() || |
| f.getEType() == Bpmn2Package.eINSTANCE.getFormalExpression())) { |
| Expression expression = (Expression)o.eGet(f); |
| if (expression==null) |
| return false; |
| if (expression instanceof FormalExpression) { |
| FormalExpression formalExpression = (FormalExpression)expression; |
| String body = ModelUtil.getExpressionBody(formalExpression); |
| if (body==null) { |
| return false; |
| } |
| } |
| } |
| |
| if (o!=null && o instanceof Documentation) { |
| Documentation doc = (Documentation)o; |
| if (doc.getText()==null || doc.getText().isEmpty()) |
| return false; |
| } |
| |
| if (f!=null && f.getEType() == Bpmn2Package.eINSTANCE.getDocumentation()) { |
| EList<Documentation> docList = (EList<Documentation>)o.eGet(f); |
| if (docList.isEmpty()) |
| return false; |
| int empty = 0; |
| for (Documentation doc : docList) { |
| if (doc.getText()==null || doc.getText().isEmpty()) |
| ++empty; |
| } |
| if (empty==docList.size()) |
| return false; |
| } |
| |
| // don't serialize the "body" attribute of FormalExpressions because the expression text |
| // is already in the CDATA section of the <bpmn2:expression> element. This would cause |
| // the expression text to be duplicated on deserialization. |
| // Same goes for Documentation.text |
| if (Bpmn2Package.eINSTANCE.getFormalExpression_Body().equals(f) || |
| Bpmn2Package.eINSTANCE.getDocumentation_Text().equals(f)) |
| return false; |
| |
| // don't save Assignments if they are invalid: Assignments must have |
| // both a "from" and "to" expression and they may not be empty strings. |
| if (o instanceof DataAssociation && "assignment".equals(f.getName())) { //$NON-NLS-1$ |
| DataAssociation da = (DataAssociation)o; |
| for (Assignment a : da.getAssignment()) { |
| Expression from = a.getFrom(); |
| if (from instanceof FormalExpression) { |
| String body = ModelUtil.getExpressionBody(((FormalExpression)from)); |
| if (body==null || body.isEmpty()) |
| return false; |
| } |
| Expression to = a.getTo(); |
| if (to instanceof FormalExpression) { |
| String body = ModelUtil.getExpressionBody(((FormalExpression)to)); |
| if (body==null || body.isEmpty()) |
| return false; |
| } |
| } |
| } |
| |
| if (f == Bpmn2Package.eINSTANCE.getBaseElement_ExtensionValues()) { |
| // check if this element is (or should be) empty |
| int entryCount = 0; |
| for (ExtensionAttributeValue ev : (EList<ExtensionAttributeValue>)o.eGet(f)) { |
| BasicFeatureMap map = (BasicFeatureMap) ev.getValue(); |
| Iterator<FeatureMap.Entry> mi = map.iterator(); |
| while (mi.hasNext()) { |
| FeatureMap.Entry entry = mi.next(); |
| Object v = entry.getValue(); |
| boolean entryCounted = false; |
| if (v instanceof EObject) { |
| Iterator<Adapter> ai = ((EObject)v).eAdapters().iterator(); |
| while (ai.hasNext()) { |
| Adapter a = ai.next(); |
| if (a instanceof IExtensionValueAdapter) { |
| if (((IExtensionValueAdapter)a).shouldSaveElement((EObject)v)) { |
| ++entryCount; |
| } |
| entryCounted = true; |
| } |
| } |
| } |
| if (!entryCounted) |
| ++entryCount; |
| } |
| } |
| return entryCount>0; |
| } |
| |
| Iterator<Adapter> ai = o.eAdapters().iterator(); |
| while (ai.hasNext()) { |
| Adapter a = ai.next(); |
| if (a instanceof IExtensionValueAdapter) { |
| if (!((IExtensionValueAdapter)a).shouldSaveFeature(o,f)) |
| return false; |
| } |
| } |
| |
| return super.shouldSaveFeature(o, f); |
| } |
| |
| protected <T> List<T> getAll(Class<T> class1, Resource resource) { |
| ArrayList<T> l = new ArrayList<T>(); |
| TreeIterator<EObject> contents = resource.getAllContents(); |
| for (; contents.hasNext();) { |
| Object t = contents.next(); |
| if (class1.isInstance(t)) { |
| l.add((T) t); |
| } |
| } |
| return l; |
| } |
| |
| protected void findMinXY(BPMNDiagram bpmnDiagram) { |
| EList<DiagramElement> elements = (EList<DiagramElement>) bpmnDiagram.getPlane().getPlaneElement(); |
| for (DiagramElement e : elements) { |
| if (e instanceof BPMNShape) { |
| Bounds b = ((BPMNShape)e).getBounds(); |
| minX = Math.min(minX, b.getX()); |
| minY = Math.min(minY, b.getY()); |
| } |
| else if (e instanceof BPMNEdge) { |
| List<Point> points = ((BPMNEdge)e).getWaypoint(); |
| for (Point p : points) { |
| minX = Math.min(minX, p.getX()); |
| minY = Math.min(minY, p.getY()); |
| } |
| |
| } |
| else if (e instanceof BPMNLabel) { |
| Bounds b = ((BPMNLabel)e).getBounds(); |
| minX = Math.min(minX, b.getX()); |
| minY = Math.min(minY, b.getY()); |
| } |
| } |
| } |
| |
| @Override |
| protected void saveContainedMany(EObject o, EStructuralFeature f) { |
| if (o instanceof BPMNPlane && f==DiPackage.eINSTANCE.getPlane_PlaneElement()) { |
| // Sort the Diagram Elements in ascending Z-order |
| BPMNPlane plane = (BPMNPlane) o; |
| EList<DiagramElement> originalList = new BasicEList<DiagramElement>(); |
| originalList.addAll(plane.getPlaneElement()); |
| |
| plane.eSetDeliver(false); |
| ECollections.sort((EList<DiagramElement>) plane.getPlaneElement(), new DIZorderComparator()); |
| super.saveContainedMany(o, f); |
| ECollections.setEList((EList)plane.getPlaneElement(),originalList); |
| plane.eSetDeliver(true); |
| } |
| else if (o instanceof Definitions && f==Bpmn2Package.eINSTANCE.getDefinitions_RootElements()) { |
| // Sort the Definitions Root Elements to avoid forward references |
| Definitions definitions = (Definitions) o; |
| EList<RootElement> originalList = new BasicEList<RootElement>(); |
| originalList.addAll(definitions.getRootElements()); |
| |
| definitions.eSetDeliver(false); |
| ECollections.sort((EList<RootElement>)definitions.getRootElements(), new RootElementComparator()); |
| super.saveContainedMany(o, f); |
| ECollections.setEList((EList)definitions.getRootElements(),originalList); |
| definitions.eSetDeliver(true); |
| } |
| else { |
| super.saveContainedMany(o, f); |
| } |
| } |
| |
| @Override |
| protected void saveElement(EObject o, EStructuralFeature f) { |
| |
| Iterator<Adapter> ai = o.eAdapters().iterator(); |
| while (ai.hasNext()) { |
| Adapter a = ai.next(); |
| if (a instanceof IExtensionValueAdapter) { |
| if (!((IExtensionValueAdapter)a).shouldSaveElement(o)) |
| return; |
| } |
| } |
| |
| if (o instanceof BPMNLabel) { |
| if (!preferences.getSaveBPMNLabels()) |
| return; |
| } |
| |
| if (o instanceof BPMNLabelStyle) { |
| // is anyone still using this BPMNLabelStyle? |
| // if not, get rid of it. |
| boolean save = false; |
| if (preferences.getSaveBPMNLabels()) { |
| Definitions definitions = ModelUtil.getDefinitions(o); |
| TreeIterator<EObject> iter = definitions.eAllContents(); |
| while (iter.hasNext()) { |
| EObject eo = iter.next(); |
| if (eo instanceof BPMNLabel) { |
| if (((BPMNLabel)eo).getLabelStyle() == o) |
| save = true; |
| } |
| } |
| } |
| if (!save) |
| return; |
| } |
| |
| float oldX = 0, oldY = 0; |
| List<Point> oldPoints = null; |
| |
| if (minX<0 || minY<0) { |
| if (o instanceof BPMNShape) { |
| Bounds b = ((BPMNShape)o).getBounds(); |
| b.eSetDeliver(false); |
| if (minX<0) { |
| oldX = b.getX(); |
| b.setX(oldX - minX); |
| } |
| if (minY<0) { |
| oldY = b.getY(); |
| b.setY(oldY - minY); |
| } |
| } |
| else if (o instanceof BPMNEdge) { |
| List<Point> points = ((BPMNEdge)o).getWaypoint(); |
| oldPoints = new ArrayList<Point>(); |
| for (Point p : points) { |
| p.eSetDeliver(false); |
| Point oldPoint = DcFactory.eINSTANCE.createPoint(); |
| oldPoint.setX(p.getX()); |
| oldPoint.setY(p.getY()); |
| oldPoints.add(oldPoint); |
| if (minX<0) |
| p.setX( p.getX() - minX); |
| if (minY<0) |
| p.setY( p.getY() - minY); |
| } |
| } |
| else if (o instanceof BPMNLabel) { |
| Bounds b = ((BPMNLabel)o).getBounds(); |
| if (b!=null) { |
| b.eSetDeliver(false); |
| if (minX<0) { |
| oldX = b.getX(); |
| b.setX(oldX - minX); |
| } |
| if (minY<0) { |
| oldY = b.getY(); |
| b.setY(oldY - minY); |
| } |
| } |
| } |
| } |
| |
| super.saveElement(o, f); |
| |
| if (minX<0 || minY<0) { |
| if (o instanceof BPMNShape) { |
| Bounds b = ((BPMNShape)o).getBounds(); |
| if (minX<0) { |
| b.setX(oldX); |
| } |
| if (minY<0) { |
| b.setY(oldY); |
| } |
| b.eSetDeliver(true); |
| } |
| else if (o instanceof BPMNEdge) { |
| List<Point> points = ((BPMNEdge)o).getWaypoint(); |
| int index = 0; |
| for (Point p : points) { |
| if (minX<0) |
| p.setX(oldPoints.get(index).getX()); |
| if (minY<0) |
| p.setY(oldPoints.get(index).getY()); |
| p.eSetDeliver(true); |
| ++index; |
| } |
| } |
| else if (o instanceof BPMNLabel) { |
| Bounds b = ((BPMNLabel)o).getBounds(); |
| if (b!=null) { |
| if (minX<0) { |
| b.setX(oldX); |
| } |
| if (minY<0) { |
| b.setY(oldY); |
| } |
| b.eSetDeliver(true); |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected String convertURI(String s) { |
| URI uri = helper.deresolve( URI.createURI(s) ); |
| return uri.toString(); |
| } |
| |
| @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((RootElement) p); |
| } |
| } |
| } |
| super.traverse(contents); |
| } |
| |
| public 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); |
| EStructuralFeature[] newFeatureList = featureList; |
| if (c == null) { |
| newFeatureList = reorderFeatureList(cls, featureList); |
| classes[index] = cls; |
| features[index] = newFeatureList; |
| featureKinds[index] = listKinds(newFeatureList); |
| } |
| return newFeatureList; |
| } |
| |
| /** |
| * Specifies the serialization order of features for a given ECLass. |
| * Subclasses should override this behavior. |
| * The default implementation simply returns the original list. |
| * |
| * @param cls - EClass whose features need to be reordered |
| * @param featureList - the original feature list as provided by the Bpmn2Package |
| * @return a feature list that specifies the new ordering |
| */ |
| protected EStructuralFeature[] reorderFeatureList(EClass cls, EStructuralFeature[] featureList) { |
| return featureList; |
| } |
| |
| /** |
| * Change the serialization order of features for a given EClass. The string array "featureNames" |
| * specifies a new ordering for some or all of the features in the feature list; these names must |
| * be contiguous in the original list. For example, given the following original feature list: |
| * |
| * "w" |
| * "x" |
| * "a" |
| * "b" |
| * "c" |
| * "d" |
| * "e" |
| * "y" |
| * "z" |
| * |
| * The featureNames list may not contain this: |
| * |
| * "b" |
| * "a" |
| * "e" |
| * "d" |
| * |
| * because the two sets "b", "a" and "e", "d" are not contiguous. The correct way of specifying this is: |
| * |
| * "b" |
| * "a" |
| * "c" |
| * "e" |
| * "d" |
| * |
| * Alternatively, the client could call this method twice, the first time with the first set ("b" and "a") |
| * and a second time with the second set ("e" and "d). |
| * |
| * @param cls |
| * @param featureList |
| * @param featureNames |
| * @return |
| */ |
| protected EStructuralFeature[] reorderFeatureList(EClass cls, EStructuralFeature[] featureList, String[] featureNames) { |
| // the reordered list of features |
| EStructuralFeature[] newFeatureList = new EStructuralFeature[featureList.length]; |
| // map of old to new array indexes |
| int[] indexMap = new int[featureList.length]; |
| for (int i=0; i<indexMap.length; ++i) |
| indexMap[i] = -1; |
| |
| int startIndex = Integer.MAX_VALUE; |
| for (int i=0; i<featureList.length; ++i) { |
| for (int j=0; j<featureNames.length; ++j) { |
| if (featureList[i].getName().equals(featureNames[j])) { |
| if (i<startIndex) { |
| startIndex = i; |
| break; |
| } |
| } |
| } |
| } |
| |
| for (int newIndex=0; newIndex<featureNames.length; ++newIndex) { |
| String fn = featureNames[newIndex]; |
| for (int oldIndex=0; oldIndex<featureList.length; ++oldIndex) { |
| EStructuralFeature f = featureList[oldIndex]; |
| if (f.getName().equalsIgnoreCase(fn)) { |
| indexMap[oldIndex] = newIndex + startIndex; |
| break; |
| } |
| } |
| } |
| |
| for (int oldIndex=0; oldIndex<featureList.length; ++oldIndex) { |
| EStructuralFeature f = featureList[oldIndex]; |
| int newIndex = indexMap[oldIndex]; |
| if (newIndex>=0) { |
| newFeatureList[newIndex] = featureList[oldIndex]; |
| } |
| else |
| newFeatureList[oldIndex] = featureList[oldIndex]; |
| } |
| return newFeatureList; |
| } |
| } |
| } |
| |
| // TODO check this, is this the correct way to deal with this ID prefixes |
| /** |
| * QName handler to make create URIs out of the fragment, which is the local part of the QName |
| * |
| * Most other tools dont understand QNames in referencing attributes |
| * |
| * @author drobisch |
| * |
| */ |
| public static class FragmentQNameURIHandler extends QNameURIHandler { |
| |
| protected BpmnXmlHelper xmlHelper; |
| |
| public FragmentQNameURIHandler(BpmnXmlHelper xmlHelper) { |
| super(xmlHelper); |
| this.xmlHelper = xmlHelper; |
| } |
| |
| @Override |
| public URI resolve(URI uri) { |
| URI resolvedUri = super.resolve(uri); |
| if (resolvedUri.isRelative()) |
| resolvedUri = resolvedUri.resolve(baseURI); |
| return resolvedUri; |
| } |
| |
| @Override |
| public URI deresolve(URI uri) { |
| String fragment = uri.fragment(); |
| if (fragment != null && !fragment.startsWith("/")) { //$NON-NLS-1$ |
| // return just fragment (i.e. without the '#') but only if local reference |
| URI otherURI = uri.trimFragment(); |
| if (baseURI.equals(otherURI)) |
| return URI.createURI(fragment); |
| } |
| |
| if ( |
| (uri.isPlatformResource() && baseURI.isPlatformResource()) || |
| (uri.isFile() && baseURI.isFile())) { |
| uri = uri.deresolve(baseURI, false, true, true); |
| return uri; |
| } |
| return super.deresolve(uri); |
| } |
| |
| @Override |
| public String convertQNameToUri(String qName) { |
| if (qName.contains("#") || qName.contains("/")) { //$NON-NLS-1$ //$NON-NLS-2$ |
| // We already have an URI and not QName, e.g. URL |
| return qName; |
| } |
| |
| // Split into prefix and local part (fragment) |
| String[] parts = qName.split(":"); //$NON-NLS-1$ |
| String prefix, fragment; |
| if (parts.length == 1) { |
| prefix = null; |
| fragment = qName; |
| } else if (parts.length == 2) { |
| prefix = parts[0]; |
| fragment = parts[1]; |
| } else |
| throw new IllegalArgumentException(Messages.Bpmn2ModelerResourceImpl_Illegal_QName + qName); |
| |
| if (fragment.contains(".")) { //$NON-NLS-1$ |
| // HACK: officially IDs can contain ".", but unfortunately |
| // XmlHandler calls resolve also for xsi:schemaLocation stuff |
| // and similar, that are |
| // NO URIs. We must not process them. |
| return qName; |
| } |
| |
| boolean isTargetNamespacePrefix = false; |
| try { |
| isTargetNamespacePrefix = xmlHelper.isTargetNamespace(prefix); |
| } catch (Exception e) { |
| } |
| |
| if (!isTargetNamespacePrefix) { |
| String uriString = xmlHelper.getPathForPrefix(prefix).appendFragment(fragment).toString(); |
| URI uri = URI.createURI(uriString); |
| ResourceSet rs = ModelUtil.slightlyHackedResourceSet(xmlHelper.getResource().getResourceSet()); |
| Resource r = ((Bpmn2ModelerResourceSetImpl)rs).getResource(uri, true, "wsdl"); // the only problem here... //$NON-NLS-1$ |
| if (r instanceof WSDLResourceImpl) { |
| EObject o = r.getContents().get(0); |
| Definition def = (Definition)o; |
| // if eReference -- operation.implementationref |
| // search all of these: |
| for (PortType pt : (List<PortType>)def.getEPortTypes()) { |
| for (org.eclipse.wst.wsdl.Operation op : (List<org.eclipse.wst.wsdl.Operation>)pt.getEOperations()) { |
| |
| } |
| } |
| // and so on for other eReference bpmn2 types |
| } |
| return xmlHelper.getPathForPrefix(prefix).appendFragment(fragment).toString(); |
| } |
| else { |
| return URI.createURI("").appendFragment(fragment).toString(); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| public static class Bpmn2ModelerXmlHelper extends BpmnXmlHelper { |
| |
| // List of all EReferences that are defined as type="xsd:QName" in the BPMN 2.0 Schema |
| // This information is not represented in the MDT BPMN2 project metamodel. |
| boolean isQNameFeature = false; |
| ImportUtil importHandler = new ImportUtil(); |
| |
| /** associated target runtime, only used in "load" scenario */ |
| protected TargetRuntime runtime = null; |
| |
| public Bpmn2ModelerXmlHelper(Bpmn2ResourceImpl resource) { |
| super(resource); |
| } |
| |
| /** |
| * initialize the target runtime according to the parsed namespace |
| * |
| * @param targetNamespace |
| */ |
| protected void initializeTargetRuntime(String targetNamespace) { |
| runtime = TargetRuntime.getRuntimeByNamespace(targetNamespace); |
| if (runtime == null) { |
| runtime = TargetRuntime.getDefaultRuntime(); |
| } |
| TargetRuntimeAdapter.adapt(resource, runtime); |
| } |
| |
| @Override |
| public Object getValue(EObject eObject, EStructuralFeature eStructuralFeature) { |
| Object o = super.getValue(eObject, eStructuralFeature); |
| if (qnameMap.contains(eStructuralFeature)) { |
| List<String> prefixes = urisToPrefixes.get(getTargetNamespace()); |
| if (prefixes!=null && prefixes.contains("")) //$NON-NLS-1$ |
| isQNameFeature = false; |
| else |
| isQNameFeature = true; |
| } |
| else |
| isQNameFeature = false; |
| return o; |
| } |
| |
| @Override |
| public String getHREF(EObject obj) { |
| // convert the attribute ID references to a QName |
| String s = null; |
| if (ModelUtil.isStringWrapper(obj)) { |
| s = ModelUtil.getStringWrapperValue(obj); |
| } |
| else |
| s = super.getHREF(obj); |
| if (isQNameFeature) { |
| if (s != null && s.contains("#")) { //$NON-NLS-1$ |
| // object is a reference possibly to another document |
| Import imp = importHandler.findImportForObject(resource, obj); |
| if (imp != null) { |
| return importHandler.getQNameForObject(resource, obj); |
| } |
| } |
| } |
| |
| return s; |
| } |
| |
| public String getIDREF(EObject obj) { |
| // convert the element ID references to a QName |
| String s = null; |
| if (ModelUtil.isStringWrapper(obj)) { |
| s = ModelUtil.getStringWrapperValue(obj); |
| } |
| else { |
| s = super.getIDREF(obj); |
| if (isQNameFeature) { |
| // Don't use targetNamespace prefixes for BPMN2 object ID references |
| // See https://bugzilla.redhat.com/show_bug.cgi?id=1150060 |
| EPackage ePackage = obj.eClass().getEPackage(); |
| if (!Bpmn2Package.class.isInstance(ePackage) && |
| !DiPackage.class.isInstance(ePackage) && |
| !DcPackage.class.isInstance(ePackage)) |
| s = convertToQName(s); |
| } |
| } |
| return s; |
| } |
| |
| /** |
| * Returns the targetNamespace defined in the <definitions> root element. |
| * |
| * @return a namespace URI or null if targetNamespace is not defined. |
| */ |
| private String getTargetNamespace() { |
| Definitions definitions = ModelUtil.getDefinitions(getResource()); |
| if (definitions==null) |
| return null; |
| return definitions.getTargetNamespace(); |
| } |
| |
| /** |
| * Get the namespace prefix for the targetNamespace. |
| * |
| * @return null if the document does not define a targetNamespace, |
| * an empty string if there is a targetNamespace, but no prefix has been |
| * defined for it, or the prefix for the targetNamespace |
| * |
| * Examples: |
| * |
| * <bpmn2:definitions tns="http://eclipse.org/example" targetNamespace="http://eclipse.org/example"/> |
| * return "tns" |
| * |
| * <bpmn2:definitions targetNamespace="http://eclipse.org/example"/> |
| * returns "" |
| * |
| * <bpmn2:definitions tns="http://eclipse.org/example"/> |
| * returns null |
| */ |
| private String getTargetNamespacePrefix() { |
| String targetNamespace = getTargetNamespace(); |
| if (targetNamespace!=null && !targetNamespace.isEmpty()) { |
| String prefix = getPrefix(targetNamespace); |
| if (prefix==null || prefix.isEmpty()) { |
| for (Entry<String, String> e : this.getPrefixToNamespaceMap().entrySet()) { |
| if (targetNamespace.equals(e.getValue()) && !e.getKey().isEmpty()) { |
| return e.getKey(); |
| } |
| } |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| return null; |
| } |
| |
| /** |
| * Converts the NCName "s" to a QName that maps to the targetNamespace |
| * |
| * @param s - a non-colonized name string |
| * @return the string "s" prefixed with the NS prefix for the targetNamespace. |
| */ |
| private String convertToQName(String s) { |
| if (s!=null && !s.contains(":")) { //$NON-NLS-1$ |
| String prefix = getTargetNamespacePrefix(); |
| if (prefix!=null && !prefix.isEmpty()) { |
| s = prefix + ":" + s; //$NON-NLS-1$ |
| } |
| } |
| return s; |
| } |
| |
| public void setValue(EObject object, EStructuralFeature feature, Object value, int position) { |
| // fix some kind of bug which causes duplicate entries in objects that have |
| // mutual reference lists. |
| if ( object!=null |
| && feature!=null |
| && object.eClass()!=null |
| && feature == object.eClass().getEStructuralFeature(feature.getFeatureID()) |
| ) { |
| Object v = object.eGet(feature); |
| if (v instanceof EObjectWithInverseEList) { |
| EObjectWithInverseEList list = (EObjectWithInverseEList)v; |
| if (list.contains(value)) { |
| // it's already in there! |
| return; |
| } |
| } |
| } |
| |
| // // check if we need to change the attribute's data type: |
| // if (feature instanceof EAttribute) { |
| // // and only if the attribute's data type is "Object" |
| // EClassifier t = feature.getEType(); |
| // if (t!=null && t.getInstanceClass() == Object.class) { |
| // // search for the attribute in the target runtime's Custom Task and |
| // // Model Extension definitions by name |
| // List<Property>properties = new ArrayList<Property>(); |
| // TargetRuntime rt = TargetRuntime.getCurrentRuntime(); |
| // String className = object.eClass().getName(); |
| // String featureName = feature.getName(); |
| // for (CustomTaskDescriptor ctd : rt.getCustomTasks()) { |
| // if (className.equals(ctd.getType())) { |
| // properties.addAll(ctd.getProperties()); |
| // } |
| // } |
| // for (ModelExtensionDescriptor med : rt.getModelExtensions()) { |
| // if (className.equals(med.getType())) { |
| // properties.addAll(med.getProperties()); |
| // } |
| // } |
| // for (Property p : properties) { |
| // if (p.name.equals(featureName)) { |
| // String type = p.type; |
| // if (type==null) |
| // type = "EString"; //$NON-NLS-1$ |
| // EClassifier eClassifier = ModelDecorator.findEClassifier( |
| // rt.getModelDescriptor().getEPackage(),type); |
| // if (eClassifier instanceof EDataType) { |
| // feature.setEType(eClassifier); |
| // } |
| // break; |
| // } |
| // } |
| // } |
| // } |
| |
| super.setValue(object, feature, value, position); |
| } |
| |
| @Override |
| public EStructuralFeature getFeature(EClass eClass, String nsURI, String name, boolean isElement) { |
| // This fixes https://bugs.eclipse.org/bugs/show_bug.cgi?id=378296 |
| // I'm still not convinced that getFeature() shouldn't simply return the feature |
| // from the given EClass instead of searching the EPackage of the Resource being |
| // loaded (if the EClass has a feature with that name of course). |
| EStructuralFeature feature = null; |
| EPackage pkg = eClass.getEPackage(); |
| if (pkg != Bpmn2Package.eINSTANCE && |
| pkg != BpmnDiPackage.eINSTANCE && |
| pkg != DcPackage.eINSTANCE && |
| pkg != DiPackage.eINSTANCE && |
| pkg != TargetRuntime.getRuntime(resource).getModelDescriptor().getEPackage()) { |
| feature = eClass.getEStructuralFeature(name); |
| } |
| if (feature==null) |
| feature = super.getFeature(eClass, nsURI, name, isElement); |
| return feature; |
| } |
| } |
| } |