/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.core.resource.xmi; import java.lang.reflect.Method; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EFactory; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.xmi.ClassNotFoundException; import org.eclipse.emf.ecore.xmi.IllegalValueException; import org.eclipse.emf.ecore.xmi.XMIResource; import org.eclipse.emf.ecore.xmi.XMLHelper; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.ecore.xmi.impl.SAXXMIHandler; import org.eclipse.xsd.XSDPackage; import org.teiid.core.designer.id.IDGenerator; import org.teiid.core.designer.id.InvalidIDException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.ReflectionHelper; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.container.Container; import org.teiid.designer.core.container.ResourceFinder; import org.teiid.designer.core.metamodel.MetamodelDescriptor; import org.teiid.designer.core.metamodel.MetamodelRegistry; import org.teiid.designer.core.util.DateUtil; import org.teiid.designer.metamodels.core.CorePackage; import org.teiid.designer.metamodels.core.Identifiable; import org.teiid.designer.metamodels.core.ModelImport; import org.xml.sax.Attributes; /** * @since 8.0 */ public class MtkXmiHandler extends SAXXMIHandler { private static final String XSD_URI = XSDPackage.eNS_URI; private static final String TARGET_NS_ATTRIBUTE_NAME = "targetNamespace"; //$NON-NLS-1$ private static final String SDT_DOMAIN_INSTANCE_CLASS_NAME = "org.teiid.designer.metamodels.sdt.Domain"; //$NON-NLS-1$ private static final DateFormat[] DATE_FORMATS = {new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"), //$NON-NLS-1$ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSSZ"), //$NON-NLS-1$ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSS"), //$NON-NLS-1$ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"), //$NON-NLS-1$ new SimpleDateFormat("yyyy-MM-dd'T'HH:mm"), //$NON-NLS-1$ new SimpleDateFormat("yyyy-MM-dd")}; //$NON-NLS-1$ private final MetamodelRegistry registry; private final IDGenerator idGenerator; private final Container container; private final Resource resource; private final Collection roots; private boolean isXsdResource; private final List xmlSchemaProxies; private final List targetNamespaces; private final Collection proxyResourceURIs; private final Collection modelImportsToConvert; /** * Constructor for EmfXMIHandler. * * @param xmiResource * @param helper * @param options */ public MtkXmiHandler( final XMIResource xmiResource, final XMLHelper helper, final Container container, final Map options ) { super(xmiResource, helper, options); if (xmiResource == null) { final String msg = ModelerCore.Util.getString("MtkXmiHandler.The_XMIResource_reference_may_not_be_null_1"); //$NON-NLS-1$ throw new IllegalArgumentException(msg); } if (!(xmiResource instanceof MtkXmiResourceImpl)) { final String msg = ModelerCore.Util.getString("MtkXmiHandler.The_XMIResource_must_be_an_instance_of_MtkXMIResourceImpl_2"); //$NON-NLS-1$ throw new IllegalArgumentException(msg); } final MtkXmiResourceImpl mtkResource = (MtkXmiResourceImpl)xmiResource; this.resource = mtkResource; this.registry = mtkResource.getMetamodelRegistry(); this.idGenerator = IDGenerator.getInstance(); this.container = container; this.xmlSchemaProxies = new LinkedList(); this.targetNamespaces = new LinkedList(); this.roots = new ArrayList(); this.proxyResourceURIs = new HashSet(); this.modelImportsToConvert = new HashSet(); } private void addNamespaceConversions() { final Resource resource = this.xmlResource; final ResourceSet resourceSet = this.resourceSet; for (final Iterator iter = this.targetNamespaces.iterator(); iter.hasNext();) { final String targetNamespace = (String)iter.next(); final URI logicalURI = URI.createURI(targetNamespace); final URI physicalURI = resource.getURI(); resourceSet.getURIConverter().getURIMap().put(logicalURI, physicalURI); // System.out.println("Added URI conversion from "+logicalURI+" to "+physicalURI); } } private String convertDateFormat( final String value ) { Date valueAsDate = null; for (int i = 0; i < DATE_FORMATS.length; ++i) { try { valueAsDate = DATE_FORMATS[i].parse(value); // MyDefect : 18060 Added break to break for the right date formatter. no break was there before. break; } catch (final ParseException parseException) { // do nothing } } if (valueAsDate == null) { final String msg = ModelerCore.Util.getString("MtkXmiHandler.Error_parsing_date_String", value); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.ERROR, msg); return value; } return DateUtil.getDateAsString(valueAsDate); } /* (non-Javadoc) * @see org.eclipse.emf.ecore.xmi.impl.XMLHandler#createObjectFromFactory(org.eclipse.emf.ecore.EFactory, java.lang.String) */ @Override protected EObject createObjectFromFactory( final EFactory factory, final String typeName ) { EObject newObject = null; if (factory != null) { newObject = helper.createObject(factory, helper.getType(factory, typeName)); if (newObject != null) { if (disableNotify) newObject.eSetDeliver(false); handleObjectAttribs(newObject); // Fix for defect 12764. Ensure that any EObject instances from the // "http://www.eclipse.org/emf/2002/Ecore" metamodel are resolved immediately newObject = handleEcoreProxy(newObject, attribs); } else { super.error(new ClassNotFoundException(typeName, factory, getLocation(), getLineNumber(), getColumnNumber())); } } return newObject; } /** * Create a top object based on the prefix and name. Overrides same method in super-class, but wraps resulting object in a java * proxy */ @Override protected void createTopObject( final String prefix, final String name ) { if (isXsdPrefix(prefix)) { isXsdResource = true; } final EFactory eFactory = getFactoryForPrefix(prefix); EObject newObject = null; try { newObject = createObjectFromFactory(eFactory, name); } catch (final Throwable t) { final Object[] params = new Object[] {prefix, name}; ModelerCore.Util.log(IStatus.ERROR, t, ModelerCore.Util.getString("MtkXmiHandler.Error_in_MtkXmiHandler.createTopObject()_1", params)); //$NON-NLS-1$ } if (ModelerCore.DEBUG || ModelerCore.DEBUG_METAMODEL) { final Object[] params = new Object[] {newObject, prefix, name, eFactory}; ModelerCore.Util.log(IStatus.INFO, ModelerCore.Util.getString("MtkXmiHandler.DEBUG.Created_new_EObject_from_prefix,_name,_and_EFactory_1", params)); //$NON-NLS-1$ } final URI uri = this.xmlResource.getURI(); // If this URI represents a metamodel that has been registered and is // now being loaded then set its namespace URI and namespace URI prefix if (newObject instanceof EPackage && this.registry != null && this.registry.containsURI(uri)) { try { final MetamodelDescriptor descriptor = this.registry.getMetamodelDescriptor(uri); if (descriptor == null) { final String msg = ModelerCore.Util.getString("MtkXmiHandler.No_metamodel_descriptor_was_found"); //$NON-NLS-1$ throw new AssertionError(msg); } final EPackage ePackage = (EPackage)newObject; ePackage.setNsPrefix(descriptor.getNamespacePrefix()); ePackage.setNsURI(uri.toString()); } catch (final Throwable t) { final Object[] params = new Object[] {prefix, name}; ModelerCore.Util.log(IStatus.ERROR, t, ModelerCore.Util.getString("MtkXmiHandler.Error_in_MtkXmiHandler.createTopObject()_1", params)); //$NON-NLS-1$ } } try { processTopObject(newObject); } catch (final Throwable t) { final Object[] params = new Object[] {prefix, name}; ModelerCore.Util.log(IStatus.ERROR, t, ModelerCore.Util.getString("MtkXmiHandler.Error_in_MtkXmiHandler.createTopObject()_1", params)); //$NON-NLS-1$ } } /** * @see org.eclipse.emf.ecore.xmi.impl.XMLHandler#endDocument() */ @Override public void endDocument() { addNamespaceConversions(); // Execute XSDSchema.update() on any XSDSchema instances // found as top level objects if (isXsdResource) { final List topObjects = this.xmlResource.getContents(); for (final Iterator iter = topObjects.iterator(); iter.hasNext();) { updateSchema((EObject)iter.next()); } } // resolveXmlSchemaProxies(); this.resource.getContents().addAll(roots); // This second patch reconciles the "modelLocation" value that was simply transfered from // / the "path" value in the first patch to its correct relative URI path patchB_modelImport(); super.endDocument(); } /** * Ensure that the metamodel with the specified URI is loaded */ private void ensureMetamodelIsLoaded( final URI metamodelURI ) { if (metamodelURI == null) { final String msg = ModelerCore.Util.getString("MtkXmiHandler.The_URI_reference_may_not_be_null_3"); //$NON-NLS-1$ throw new IllegalArgumentException(msg); } // Load the metamodel if it is not yet loaded final Resource resource = registry.getResource(metamodelURI); CoreArgCheck.isTrue(resource.isLoaded(), "Resource " + resource.getURI() + " must be loaded"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Attempt to get the namespace for the given prefix, then return ERegister.getPackage() or null. */ @Override protected EPackage getPackageForURI( final String uriString ) { if (uriString == null) { return null; } // Ensure that any metamodel for this URI is loaded if (registry != null && registry.containsURI(uriString)) { ensureMetamodelIsLoaded(registry.getURI(uriString)); } return super.getPackageForURI(uriString); } /** * For a newly created EObject along with its associated attributes, check if that EObject has an "href" attribte to a * "http://www.eclipse.org/emf/2002/Ecore" instance and resolve it immediately, otherwise return the original object. Fix for * defect 12764. */ private EObject handleEcoreProxy( final EObject obj, final Attributes atts ) { if (atts != null) { final InternalEObject internalEObject = (InternalEObject)obj; for (int i = 0, size = atts.getLength(); i < size; ++i) { final String name = atts.getQName(i); final String value = atts.getValue(i); // If the xmi:href attribute is encountered ... if (name.equals(XMLResource.HREF)) { // System.out.println("handleEcoreProxy for "+value); final URI uri = URI.createURI(value); if (EcorePackage.eNS_URI.equals(uri.trimFragment().toString())) { if (this.container != null) { return EcoreUtil.resolve(internalEObject, this.container.getMetamodelRegistry().getResource(uri)); } } } } } return obj; } /** * {@inheritDoc} * * @see org.eclipse.emf.ecore.xmi.impl.XMLHandler#handleFeature(java.lang.String, java.lang.String) */ @Override protected void handleFeature( final String prefix, String name ) { if ("".equals(prefix) && ("containers".equals(name) || "elements".equals(name)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ && objects.peekEObject().getClass().getName().startsWith("org.teiid.designer.metamodels.xml.impl.")) name = "entities"; //$NON-NLS-1$ //$NON-NLS-2$ super.handleFeature(prefix, name); } /** * Process the XMI attributes for the newly created object. Overrides same method in super-class, but handles UUID instead of * explicitly ignoring it as the super class does. */ @Override protected void handleObjectAttribs( final EObject obj ) { if (attribs != null) { final InternalEObject internalEObject = (InternalEObject)obj; for (int i = 0, size = attribs.getLength(); i < size; ++i) { final String name = attribs.getQName(i); // If the xmi:uuid attribute is encountered ... if (name.equals(UUID_ATTRIB) && this.idGenerator != null) { try { final String uuidStr = attribs.getValue(i); this.idGenerator.stringToObject(uuidStr); // ------------------------------------------------------------------------------- // Fix to defect 14449, where Core::ModelImport objects were created with the same // UUID as the model that they reference. This fix only addresses the side effect // of the defect in existing models; see a little lower in this method // for the fix so that we don't reset it upon reading in (the original cause of the // problem) if (obj instanceof ModelImport) { final ModelImport modelImport = (ModelImport)obj; // Get the UUID of the referenced model (first on the object instance) ... String uuidOfRefedModel = modelImport.getUuid(); if (uuidOfRefedModel == null) { // That attribute hasn't yet been read in, so look in attributes that haven't yet been processed // ... final String uuidAttributeName = CorePackage.eINSTANCE.getModelImport_Uuid().getName(); for (int k = (i + 1); k < size; ++k) { // start at the next unread attribute!!! final String attributeName = attribs.getQName(k); if (uuidAttributeName.equals(attributeName)) { uuidOfRefedModel = attribs.getValue(k); } } } // Check if the uuuid of the ModelImport is the same as the UUID of the referenced model ... // Note that both values use the "mmuuid:" form, so okay to compare the value strings if (uuidStr.equals(uuidOfRefedModel)) { this.idGenerator.create(); } } // End of fix to defect 14449 // ------------------------------------------------------------------------------- xmlResource.setID(internalEObject, uuidStr); } catch (final InvalidIDException e) { ModelerCore.Util.log(IStatus.ERROR, ModelerCore.Util.getString("MtkXmiHandler.Error_handling_Object_attributes_for_-_5", new Object[] {obj, e.getMessage()})); //$NON-NLS-1$ } } // If the xmi:href attribute is encountered ... else if (name.equals(XMLResource.HREF)) { String uri = attribs.getValue(i); if (uri.startsWith("#")) { //$NON-NLS-1$ uri = this.resourceURI.toString() + uri; } handleProxy(internalEObject, uri); } // For all other attributes ... else if (!name.startsWith(XMLResource.XML_NS) && !notFeatures.contains(name)) { final EStructuralFeature feature = obj.eClass().getEStructuralFeature(name); if (feature != null && feature.isChangeable()) { setAttribValue(obj, name, attribs.getValue(i)); } else { if (ModelerCore.DEBUG) { ModelerCore.Util.log(IStatus.WARNING, ModelerCore.Util.getString("MtkXmiHandler.DEBUG.Unable_to_set_the_value_on_EAttribute_since_it_is_unchangeable._1", name)); //$NON-NLS-1$ } } // If we are setting a namespace URI on a new EPackage instance then register it if (obj instanceof EPackage && EcorePackage.eINSTANCE.getEPackage_NsURI().equals(feature)) { EPackage.Registry.INSTANCE.put(attribs.getValue(i), obj); } // setAttribValue(obj, name, attribs.getValue(i)); } // If the uuid feature name is encountered ... if (name.equalsIgnoreCase("uuid") && this.idGenerator != null) { //$NON-NLS-1$ // ------------------------------------------------------------------------------- // Fix to defect 14449, where we don't want to reset the ObjectID on // a ModelImport, since the "uuid" feature on a ModelImport represents // the UUID of the referenced model. boolean treatAsObjectId = true; if (obj instanceof ModelImport) { // also Manifest::ModelReference, which extends ModelImport treatAsObjectId = false; } else if (!obj.eClass().getEPackage().getNsURI().equals("http://www.metamatrix.com/metamodels/VirtualDatabase") //$NON-NLS-1$ && !(obj instanceof Identifiable)) { // Don't know what metaclass this is, so do not treat as an ObjectID ... treatAsObjectId = false; // And log ... final Object[] params = new Object[] {obj.eClass().getEPackage(), obj.eClass()}; final String msg = ModelerCore.Util.getString("MtkXmiHandler.UnexpectedUuidFeature", params); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.ERROR, msg); } // End of fix to defect 14449 // ------------------------------------------------------------------------------- if (treatAsObjectId) { xmlResource.setID(internalEObject, attribs.getValue(i)); } } // If the targetNamespace attribute in a org.teiid.designer.metamodels.sdt.Domain instance is encountered ... if (name.equals(TARGET_NS_ATTRIBUTE_NAME) && SDT_DOMAIN_INSTANCE_CLASS_NAME.equals(obj.eClass().getInstanceClassName())) { final String targetNamespace = attribs.getValue(i); if (targetNamespace != null && targetNamespace.length() > 0) { this.targetNamespaces.add(attribs.getValue(i)); } } } } // First of two patches to convert the Core::ModelImport "path" feature value found in models // created prior to 4.4 to their new "modelLocation" value patchA_modelImport(obj, attribs); } /** * @see org.eclipse.emf.ecore.xmi.impl.XMLHandler#handleProxy(org.eclipse.emf.ecore.InternalEObject, java.lang.String) * @since 4.3 */ @Override protected void handleProxy( final InternalEObject proxy, final String uriLiteral ) { super.handleProxy(proxy, uriLiteral); // Save the URI of the proxy's resource this.proxyResourceURIs.add(proxy.eProxyURI().trimFragment()); } private boolean isXsdPrefix( final String prefix ) { // MetamodelDescriptor descriptor = ModelerCore.getMetamodels().getMetamodelDescriptor(SDT_URI); // if (descriptor != null && descriptor.getNamespacePrefix().equalsIgnoreCase(prefix)) { // return true; // } final URI nsUri = ModelerCore.getMetamodelRegistry().getURI(XSD_URI); if (nsUri != null) { final MetamodelDescriptor descriptor = ModelerCore.getMetamodelRegistry().getMetamodelDescriptor(nsUri); if (descriptor != null && descriptor.getNamespacePrefix().equalsIgnoreCase(prefix)) { return true; } } return false; } /** * First of two patches to convert the Core::ModelImport "path" feature value found in models created prior to 4.4 to their new * "modelLocation" value. In 4.4, the "path" feature on Core::ModelImport was changed to be transient and volatile to be * replaced by a new feature, "modelLocation". The new feature stores the relative URI path of the referenced resource instead * of the "path" relative to the workspace root which assumed an Eclipse runtime workspace. This first patch simply transfers * the "path" value to the new "modelLocation" feature. */ protected EObject patchA_modelImport( final EObject obj, final Attributes attribs ) { if (obj instanceof ModelImport && attribs != null) { for (int i = 0, size = attribs.getLength(); i < size; ++i) { final String qName = attribs.getQName(i); final String value = attribs.getValue(i); if (qName.equals("path")) { //$NON-NLS-1$ ((ModelImport)obj).setModelLocation(value); this.modelImportsToConvert.add(obj); } } } return obj; } /** * Second of two patches to convert the Core::ModelImport "path" feature value found in models created prior to 4.4 to their new * "modelLocation" value. In 4.4, the "path" feature on Core::ModelImport was changed to be transient and volatile to be * replaced by a new feature, "modelLocation". The new feature stores the relative URI path of the referenced resource instead * of the "path" relative to the workspace root which assumed an Eclipse runtime workspace. This second patch reconciles the * "modelLocation" value that was simply transfered from the "path" value in the first patch to its correct relative URI path */ protected void patchB_modelImport() { // If no ModelImport conversion work is required, return if (this.modelImportsToConvert.isEmpty()) { return; } final URI eResourceURI = this.resource.getURI(); // Preprocess the collection of proxy resource URIs ... removeBadProxyResourceUris(this.proxyResourceURIs); // Reconcile the workspace relative paths, stored in the "modelLocation" feature, // against the resource URIs of the proxies final Collection unconvertedImports = new HashSet(this.modelImportsToConvert); for (final Iterator i = this.modelImportsToConvert.iterator(); i.hasNext();) { final ModelImport modelImport = (ModelImport)i.next(); final String modelLocation = modelImport.getModelLocation().toLowerCase(); // If the modelLocation value represents a logical location of a built-in resource then ignore it if (modelLocation.startsWith("http") || //$NON-NLS-1$ modelLocation.startsWith(ResourceFinder.METAMODEL_PREFIX) || modelLocation.startsWith(ResourceFinder.UML2_METAMODELS_PREFIX)) { unconvertedImports.remove(modelImport); continue; } for (final Iterator j = this.proxyResourceURIs.iterator(); j.hasNext();) { URI importURI = (URI)j.next(); final String uriString = URI.decode(importURI.toString()).toLowerCase(); // If the URI of the proxy resource is a logical URI of the form "http://..." then ignore it if (uriString.startsWith("http") && !uriString.endsWith("xmi")) { //$NON-NLS-1$ //$NON-NLS-2$ continue; } // Match the modelLocation, currently of the form "/project/.../model.xmi" to // a resource URI of the form "file:/C:/.../project/.../model.xmi" if (uriString.endsWith(modelLocation)) { final boolean deresolve = (eResourceURI != null && !eResourceURI.isRelative() && eResourceURI.isHierarchical()); if (deresolve && !importURI.isRelative()) { final URI deresolvedURI = importURI.deresolve(eResourceURI, true, true, false); if (deresolvedURI.hasRelativePath()) { importURI = deresolvedURI; } } modelImport.setModelLocation(URI.decode(importURI.toString())); unconvertedImports.remove(modelImport); break; } } } // Reconcile the workspace relative paths, stored in the "modelLocation" feature, // against the model names found in the resource URIs of the proxies for (final Iterator i = unconvertedImports.iterator(); i.hasNext();) { final ModelImport modelImport = (ModelImport)i.next(); final String modelLocation = removeProjectNameFromLocation(modelImport.getModelLocation()).toLowerCase(); for (final Iterator j = this.proxyResourceURIs.iterator(); j.hasNext();) { URI importURI = (URI)j.next(); final String uriString = URI.decode(importURI.toString()).toLowerCase(); // If the URI of the proxy resource is a logical URI of the form "http://..." then ignore it if (uriString.startsWith("http") && !uriString.endsWith("xmi")) { //$NON-NLS-1$ //$NON-NLS-2$ continue; } // Match the modelLocation, currently a project relative path, to a resource URI if (uriString.endsWith(modelLocation)) { final boolean deresolve = (eResourceURI != null && !eResourceURI.isRelative() && eResourceURI.isHierarchical()); if (deresolve && !importURI.isRelative()) { final URI deresolvedURI = importURI.deresolve(eResourceURI, true, true, false); if (deresolvedURI.hasRelativePath()) { importURI = deresolvedURI; } } modelImport.setModelLocation(URI.decode(importURI.toString())); i.remove(); break; } } } // Remove any model imports that could not be matched to a proxy resource for (final Iterator i = unconvertedImports.iterator(); i.hasNext();) { final ModelImport modelImport = (ModelImport)i.next(); modelImport.setModel(null); } } /* (non-Javadoc) * @see org.eclipse.emf.ecore.xmi.impl.XMLHandler#processTopObject(org.eclipse.emf.ecore.EObject) */ @Override protected void processTopObject( final EObject object ) { super.processObject(object); roots.add(object); } /** * If any of the resource URIs begin with '/' then it may represent a bad href (Eclipse workspace relative path of the form * "/project/.../model.xmi") which are sometimes found in old model files. Check if the collection contains the correct file URI * so that the bad one can be removed */ protected void removeBadProxyResourceUris( final Collection proxyResourceUris ) { if (proxyResourceUris == null || proxyResourceUris.isEmpty()) { return; } // Collect all the URIs that are identified as being bad and // remove them from the collection of proxy resource URIs final List badUris = new ArrayList(proxyResourceUris.size()); for (final Iterator i = proxyResourceUris.iterator(); i.hasNext();) { final URI uri = (URI)i.next(); final String uriString = uri.toString(); if (uriString.charAt(0) == '/') { badUris.add(uri); i.remove(); } } if (badUris.isEmpty()) { return; } // Check the collection of remaining proxy resource URIs attempting to // match the bad Eclipse workspace relative path to a good file URI path. // If a match is not found then re-add the bad path for (final Iterator i = proxyResourceUris.iterator(); i.hasNext();) { final URI uri = (URI)i.next(); final String uriString = URI.decode(uri.toString()).toLowerCase(); for (final Iterator j = badUris.iterator(); j.hasNext();) { final URI badUri = (URI)j.next(); final String badUriString = URI.decode(badUri.toString()).toLowerCase(); if (uriString.endsWith(badUriString)) { j.remove(); } } } if (!badUris.isEmpty()) { proxyResourceUris.addAll(badUris); } } protected String removeProjectNameFromLocation( final String location ) { String newLocation = location; final URI uri = URI.createURI(location); if (uri.segmentCount() > 1) { final StringBuffer sb = new StringBuffer(location.length()); final String[] segments = uri.segments(); for (int i = 1; i != segments.length; ++i) { sb.append("/"); //$NON-NLS-1$ sb.append(segments[i]); } newLocation = sb.toString(); } return newLocation; } /** * Set the given feature of the given object to the given value. */ @Override protected void setFeatureValue( final EObject object, final EStructuralFeature feature, Object value, final int position ) { try { // If there is a reference to an XMLSchema entity ... if (value instanceof EObject && ((EObject)value).eIsProxy()) { final URI proxyURI = ((InternalEObject)value).eProxyURI(); if (proxyURI != null && proxyURI.toString().startsWith(MtkXmiSaveImpl.XML_SCHEMA_ECLIPSE_PLATFORM_URI_PREFIX)) { // System.out.println("setFeatureValue - creating ProxyReferenceHolder for "+value+" and feature "+feature.getName()); final ProxyReferenceHolder refHolder = new ProxyReferenceHolder(object, feature, (EObject)value, position); this.xmlSchemaProxies.add(refHolder); } } // If the object for which the value is being set in XMLSchema model ... if (isXsdResource || isXsdPrefix(object.eClass().getEPackage().getNsPrefix())) { this.setValue(object, feature, value, position); return; } // If the feature has a datatype of java.util.Date then we need to ensure // that the format of the value adheres to one of the accepted formats // in EFactoryImpl.EDATE_FORMATS. if (feature instanceof EAttribute && value instanceof String) { if (Date.class.equals(((EAttribute)feature).getEAttributeType().getInstanceClass())) { value = convertDateFormat((String)value); } } // Process as a normal feature value super.setFeatureValue(object, feature, value, position); } catch (final RuntimeException e) { error(new IllegalValueException(object, feature, value, e, getLocation(), getLineNumber(), getColumnNumber())); } } public void setValue( final EObject object, final EStructuralFeature feature, final Object value, final int position ) { final int kind = helper.getFeatureKind(feature); switch (kind) { case XMLHelper.DATATYPE_SINGLE: case XMLHelper.DATATYPE_IS_MANY: final EClassifier eMetaObject = feature.getEType(); final EDataType eDataType = (EDataType)eMetaObject; final EFactory eFactory = eDataType.getEPackage().getEFactoryInstance(); if (kind == XMLHelper.DATATYPE_IS_MANY) { final BasicEList list = (BasicEList)object.eGet(feature); if (position == -2) { for (final StringTokenizer stringTokenizer = new StringTokenizer((String)value, " "); //$NON-NLS-1$ stringTokenizer.hasMoreTokens();) { final String token = stringTokenizer.nextToken(); list.addUnique(eFactory.createFromString(eDataType, token)); } // Make sure that the list will appear to be set to be empty. // if (list.isEmpty()) { list.clear(); } } else if (value == null) { list.addUnique(null); } else { list.addUnique(eFactory.createFromString(eDataType, (String)value)); } } else if (value == null) { object.eSet(feature, null); } else { object.eSet(feature, eFactory.createFromString(eDataType, (String)value)); } break; case XMLHelper.IS_MANY_ADD: case XMLHelper.IS_MANY_MOVE: final BasicEList list = (BasicEList)object.eGet(feature); if (position == -1) { list.addUnique(value); } else if (position == -2) { list.clear(); } else if (kind == XMLHelper.IS_MANY_ADD) { list.addUnique(position, value); } else { list.move(position, value); } break; default: object.eSet(feature, value); } } /** * @see org.eclipse.emf.ecore.xmi.impl.XMLHandler#startElement(java.lang.String, java.lang.String, java.lang.String) */ @Override public void startElement( final String uri, final String localName, final String name ) { // System.out.println("startElement "+uri+ ", "+localName+", "+name); super.startElement(uri, localName, name); } /** * Update any XMLSchema entity found in the model file. By calling update() on a XMLSchema entity we are forcing a datatype * analysis and validation of the whole schema. This is necessary to ensure that datatypes defined within the schema are * properly constraned. * * @param topObject */ private void updateSchema( final EObject topObject ) { // Create the arguments to the method ... final Object[] args = new Object[] {}; final Class xmlSchemaClass = topObject.getClass(); final ReflectionHelper helper = new ReflectionHelper(xmlSchemaClass); Method updateSchemaMethod = null; try { updateSchemaMethod = helper.findBestMethodOnTarget("update", args); //$NON-NLS-1$ } catch (final SecurityException e) { ModelerCore.Util.log(IStatus.ERROR, e, ModelerCore.Util.getString("MtkXmiHandler.Error_execute_the_XSDSchema.update()_method_for_1", topObject)); //$NON-NLS-1$ } catch (final NoSuchMethodException e) { // do nothing } // Execute the XSDSchema.update() method if (updateSchemaMethod != null) { // System.out.println("Executing update() on "+topObject); try { updateSchemaMethod.invoke(topObject, args); } catch (final Throwable t) { ModelerCore.Util.log(IStatus.ERROR, ModelerCore.Util.getString("MtkXmiHandler.Error_execute_the_XSDSchema.update()_method_for_2", topObject)); //$NON-NLS-1$ } } } } class ProxyReferenceHolder { private final EObject owner; private final EStructuralFeature sf; private final EObject proxy; private final int position; public ProxyReferenceHolder( final EObject owner, final EStructuralFeature sf, final EObject proxy, final int position ) { this.owner = owner; this.sf = sf; this.proxy = proxy; this.position = position; } public EObject getOwner() { return owner; } public int getPosition() { return position; } public EObject getProxy() { return proxy; } public EStructuralFeature getSf() { return sf; } }