/* * 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.container; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; 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.xsd.XSDImport; import org.eclipse.xsd.XSDInclude; import org.eclipse.xsd.XSDRedefine; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDSchemaDirective; import org.eclipse.xsd.impl.XSDImportImpl; import org.eclipse.xsd.impl.XSDSchemaImpl; import org.eclipse.xsd.util.XSDResourceImpl; import org.teiid.core.designer.id.IDGenerator; import org.teiid.core.designer.id.InvalidIDException; import org.teiid.core.designer.id.ObjectID; import org.teiid.core.designer.id.UUID; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.resource.MMXmiResource; import org.teiid.designer.core.util.ModelObjectCollector; import org.teiid.designer.core.util.UriHelper; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.core.workspace.ModelWorkspaceException; import org.teiid.designer.metamodels.core.ModelImport; /** * @since 8.0 */ public class DefaultResourceFinder implements ResourceFinder { private final Container container; // ================================================================================== // C O N S T R U C T O R S // ================================================================================== /** * @param container * @since 4.3 */ public DefaultResourceFinder( final Container container ) { super(); this.container = container; } // ================================================================================== // I N T E R F A C E M E T H O D S // ================================================================================== /** * @see org.teiid.designer.core.container#findByUUID(org.teiid.core.designer.id.ObjectID, boolean) * @since 4.3 */ @Override public Resource findByUUID( final ObjectID uuid, final boolean searchExternal ) { Resource result = findResourceByUUID(uuid, new ArrayList(getContainer().getResources())); if (result == null && searchExternal) { ResourceSet[] externalSets = getContainer().getExternalResourceSets(); for (int i = 0; i != externalSets.length; ++i) { result = findResourceByUUID(uuid, new ArrayList(externalSets[i].getResources())); if (result != null) { break; } } } return result; } /** * @see org.teiid.designer.core.container#findByUUID(org.teiid.core.designer.id.ObjectID, * org.eclipse.emf.ecore.resource.Resource[]) * @since 4.3 */ @Override public Resource findByUUID( final ObjectID uuid, final Resource[] scope ) { return findResourceByUUID(uuid, Arrays.asList(scope)); } /** * @see org.teiid.designer.core.container#findByImport(org.teiid.designer.metamodels.core.ModelImport, boolean) * @since 4.3 */ @Override public Resource findByImport( final ModelImport theImport, final boolean searchExternal ) { Resource result = findResourceByImport(theImport, new ArrayList(getContainer().getResources())); if (result == null && searchExternal) { ResourceSet[] externalSets = getContainer().getExternalResourceSets(); for (int i = 0; i != externalSets.length; ++i) { result = findResourceByImport(theImport, new ArrayList(externalSets[i].getResources())); if (result != null) { break; } } } return result; } /** * @see org.teiid.designer.core.container#findByImport(org.teiid.designer.metamodels.core.ModelImport, * org.eclipse.emf.ecore.resource.Resource[]) * @since 4.3 */ @Override public Resource findByImport( final ModelImport theImport, final Resource[] scope ) { return findResourceByImport(theImport, Arrays.asList(scope)); } /** * @see org.teiid.designer.core.container.ResourceFinder#findByImport(org.eclipse.xsd.XSDSchemaDirective, boolean) * @since 4.3 */ @Override public Resource findByImport( final XSDSchemaDirective theImport, final boolean searchExternal ) { Resource result = findResourceByImport(theImport, new ArrayList(getContainer().getResources())); if (result == null && searchExternal) { ResourceSet[] externalSets = getContainer().getExternalResourceSets(); for (int i = 0; i != externalSets.length; ++i) { result = findResourceByImport(theImport, new ArrayList(externalSets[i].getResources())); if (result != null) { break; } } } return result; } /** * @see org.teiid.designer.core.container.ResourceFinder#findByImport(org.eclipse.xsd.XSDSchemaDirective, * org.eclipse.emf.ecore.resource.Resource[]) * @since 4.3 */ @Override public Resource findByImport( final XSDSchemaDirective theImport, final Resource[] scope ) { return findResourceByImport(theImport, Arrays.asList(scope)); } /** * @see org.teiid.designer.core.container#findByName(java.lang.String, boolean, boolean) * @since 4.3 */ @Override public Resource[] findByName( final String theName, final boolean caseSensitive, final boolean searchExternal ) { Collection result = findResourcesByName(theName, caseSensitive, new ArrayList(getContainer().getResources())); if (searchExternal) { ResourceSet[] externalSets = getContainer().getExternalResourceSets(); for (int i = 0; i != externalSets.length; ++i) { result.addAll(findResourcesByName(theName, caseSensitive, new ArrayList(externalSets[i].getResources()))); } } return (Resource[])result.toArray(new Resource[result.size()]); } /** * @see org.teiid.designer.core.container#findByURI(org.eclipse.emf.common.util.URI, boolean) * @since 4.3 */ @Override public Resource findByURI( final URI theUri, final boolean searchExternal ) { Resource result = getContainer().getResource(theUri, false); if (result == null && searchExternal) { ResourceSet[] externalSets = getContainer().getExternalResourceSets(); for (int i = 0; i != externalSets.length; ++i) { result = externalSets[i].getResource(theUri, false); if (result != null) { break; } } } // If the result cannot be an external resource then check its resource set if (result != null && !searchExternal && ModelerCore.getContainer(result) != getContainer()) { result = null; } return result; } /** * Used to find a resource using a relative URI referenced to a known resource * * @see org.teiid.designer.core.container.ResourceFinder#findByWorkspaceUri(org.eclipse.emf.common.util.URI, * org.eclipse.emf.ecore.resource.Resource) * @since 5.0.2 */ @Override public Resource findByWorkspaceUri( final URI theRelativeUri, final Resource knownResource ) { try { // Defect 23396 - an NPE was thrown here because a relativeUri was provide (i.e. BooksDatatypes.xsd) which resulted // in a NULL model Resource or null corresponding resource. ModelResource mr = ModelerCore.getModelEditor().findModelResource(knownResource); if (mr != null && mr.getCorrespondingResource() != null) { IPath thePath = mr.getCorrespondingResource().getFullPath().removeLastSegments(1).append(theRelativeUri.toString()); IResource iResrc = ModelerCore.getWorkspace().getRoot().findMember(thePath); if (iResrc instanceof IFile) { ModelResource modelResource = ModelerCore.getModelEditor().findModelResource((IFile)iResrc); if (modelResource != null) { return modelResource.getEmfResource(); } } } } catch (ModelWorkspaceException theException) { ModelerCore.Util.log(theException); } return null; } /** * @see org.teiid.designer.core.container#isExternalResource(org.eclipse.emf.common.util.URI) * @since 4.3 */ @Override public boolean isExternalResource( final URI theUri ) { if (theUri != null) { return isExternalResource(findByURI(theUri, true)); } return true; } /** * @see org.teiid.designer.core.container#isExternalResource(org.eclipse.emf.ecore.resource.Resource) * @since 4.3 */ @Override public boolean isExternalResource( final Resource theResource ) { if (theResource != null && ModelerCore.getContainer(theResource) == getContainer()) { return false; } return true; } /** * @see org.teiid.designer.core.container#isBuiltInResource(org.eclipse.emf.ecore.resource.Resource) * @since 4.3 */ @Override public boolean isBuiltInResource( final Resource theResource ) { if (theResource != null) { return isBuiltInResource(theResource.getURI()); } return false; } /** * @see org.teiid.designer.core.container#isBuiltInResource(org.eclipse.emf.common.util.URI) * @since 4.3 */ @Override public boolean isBuiltInResource( final URI theUri ) { if (theUri == null) { return false; } // The Container for this ResourceFinder should not have a built-in resouce within its contents. // If we find a non-external resource by this URI then return false. if (findByURI(theUri, false) != null) { return false; } String uriString = URI.decode(theUri.toString()); // If the URI is to the Teiid Designer built-in datatypes model if (uriString.startsWith(BUILTIN_DATATYPES_URI) || uriString.endsWith(DATATYPES_MODEL_FILE_NAME)) { return true; } // If the URI is to the Teiid Designer built-in UML primitive types model if (uriString.startsWith(UML_PRIMITIVE_TYPES_INTERNAL_URI) || uriString.endsWith(UML_PRIMITIVE_TYPES_MODEL_FILE_NAME)) { return true; } // If the URI is to the Teiid Designer built-in relationship model if (uriString.startsWith(RELATIONSHIP_PRIMITIVE_TYPES_INTERNAL_URI) || uriString.endsWith(RELATIONSHIP_PRIMITIVE_TYPES_MODEL_FILE_NAME)) { return true; } // If the URI is to one of the XSD global resources ResourceSet globalResourceSet = XSDSchemaImpl.getGlobalResourceSet(); if (globalResourceSet != null && globalResourceSet.getResource(theUri, false) != null) { return true; } // If the URI is a logical URI to one of the XSD global resources if (uriString.endsWith(SCHEMA_FOR_SCHEMA_URI_2001_SUFFIX) || uriString.endsWith(MAGIC_SCHEMA_URI_2001_SUFFIX) || uriString.endsWith(SCHEMA_INSTANCE_URI_2001_SUFFIX)) { return true; } // If the URI is to one of the Teiid Designer metamodel resources if (uriString.startsWith(METAMODEL_PREFIX)) { return true; } // If the URI is to one of the IBM UML2 metamodel resources if (uriString.startsWith(UML2_METAMODELS_PREFIX)) { return true; } // If the URI is to the Teiid Designer built-in system models if (isBuiltInSystemResource(theUri)) { return true; } // If the URI is to one of our metamodels try { if (ModelerCore.getMetamodelRegistry().containsURI(theUri)) { return true; } } catch (Exception e) { // do nothing } return false; } /** * @see org.teiid.designer.core.container#isBuiltInSystemResource(org.eclipse.emf.common.util.URI) * @since 4.3 */ @Override public boolean isBuiltInSystemResource( final URI theUri ) { if (theUri != null) { // If the models are not found in an external resource set then // they cannot be one of the built-in shared resources if (!isExternalResource(theUri)) { return false; } // Check if the string form of the URI matches one of the expected names String uriString = URI.decode(theUri.toString()); if (uriString.startsWith(SYSTEM_VIRTUAL_INTERNAL_URI) || uriString.endsWith(SYSTEM_VIRTUAL_MODEL_FILE_NAME)) { return true; } } return false; } /** * @see org.teiid.designer.core.container#isBuiltInSystemResource(org.eclipse.emf.ecore.resource.Resource) * @since 4.3 */ @Override public boolean isBuiltInSystemResource( final Resource theResource ) { if (theResource != null) { return isBuiltInSystemResource(theResource.getURI()); } return false; } /** * @see org.teiid.designer.core.container#findSystemResources() * @since 4.3 */ public Resource[] findSystemResources() { throw new UnsupportedOperationException(); } /** * @see org.teiid.designer.core.container#findByEObject(org.eclipse.emf.ecore.EObject) * @since 4.3 */ @Override public Resource findByEObject( final EObject eObject ) { if (eObject == null) { return null; } Resource result = null; if (eObject.eIsProxy()) { URI proxyURI = ((InternalEObject)eObject).eProxyURI(); result = findByURI(proxyURI.trimFragment(), true); } else { result = eObject.eResource(); } return result; } /** * @see org.teiid.designer.core.container.ResourceFinder#findReferencesFrom(org.eclipse.emf.ecore.resource.Resource, * boolean, boolean) * @since 4.3 */ @Override public Resource[] findReferencesFrom( final Resource theResource, final boolean recurse, final boolean includeExternal ) { final List result = getExternallyReferencedResources(theResource, recurse, includeExternal); if (!includeExternal) { // Filter out Resources that are not contained within the Finder's resource set for (final Iterator iter = result.iterator(); iter.hasNext();) { final Resource eResource = (Resource)iter.next(); if (isExternalResource(eResource)) { iter.remove(); } } } return (Resource[])result.toArray(new Resource[result.size()]); } /** * @see org.teiid.designer.core.container.ResourceFinder#findReferencesTo(org.eclipse.emf.ecore.resource.Resource, * boolean) * @since 4.3 */ @Override public Resource[] findReferencesTo( final Resource theResource, final boolean recurse ) { final Collection result = new HashSet(); if (theResource != null) { // Create a copy of the resource set contents (prevent ConcurrentModificationException) final List eResources = new ArrayList(getContainer().getResources()); // Remove the resource we are finding references to from the collection eResources.remove(theResource); // For each resource in the resource set, record which of those resources // references the input resource ... for (final Iterator i = eResources.iterator(); i.hasNext();) { final Resource eResource = (Resource)i.next(); final List externalResources = getExternallyReferencedResources(eResource, recurse, true); for (final Iterator j = externalResources.iterator(); j.hasNext();) { final Resource rsrc = (Resource)j.next(); if (rsrc == theResource) { result.add(eResource); break; } } } } return (Resource[])result.toArray(new Resource[result.size()]); } /** * @see org.teiid.designer.core.container.ResourceFinder#findUnresolvedResourceLocations(org.eclipse.emf.ecore.resource.Resource) * @since 4.3 */ @Override public String[] findUnresolvedResourceLocations( final Resource theResource ) { final Collection result = new HashSet(); if (theResource != null) { List dummyList = new ArrayList(); Set unresolvedURIs = new HashSet(); // just get the unresolved URI's addExternallyReferencedResources(theResource, false, true, dummyList, unresolvedURIs); // Check each one, decode it and add to result for (Iterator iter = unresolvedURIs.iterator(); iter.hasNext();) { URI uri = (URI)iter.next(); result.add(URI.decode(uri.toString())); } } return (String[])result.toArray(new String[result.size()]); } /** * @see org.teiid.designer.core.container.ResourceFinder#findMissingImportLocations(org.eclipse.emf.ecore.resource.Resource) * @since 5.0.2 */ @Override public String[] findMissingImportLocations( final Resource theResource ) { final Collection result = new HashSet(); if (theResource != null && theResource instanceof MMXmiResource) { // just get the Resolved external resources (i.e. desired imports) Collection unresolvedResources = getResolvedExternalResources(theResource); // For each unresolved resource, create a location and check existing imports for this location. for (Iterator iter = unresolvedResources.iterator(); iter.hasNext();) { Resource nextRes = (Resource)iter.next(); String location = ModelerCore.getModelEditor().createModelLocation((MMXmiResource)theResource, nextRes); if (location != null) { ModelImport existingImport = ModelerCore.getModelEditor().getExistingModelImportForLocation((MMXmiResource)theResource, location); // If no existing import, add location to result if (existingImport == null) { result.add(location); } } } } return (String[])result.toArray(new String[result.size()]); } // ================================================================================== // P R O T E C T E D M E T H O D S // ================================================================================== protected Container getContainer() { return this.container; } protected Resource findResourceByUUID( final ObjectID uuid, final List eResources ) { Resource result = null; if (uuid != null && eResources != null) { // Iterate through each resource in the resource set for (Iterator iter = eResources.iterator(); iter.hasNext();) { Resource rsrc = (Resource)iter.next(); if (rsrc instanceof MMXmiResource) { if (uuid.equals(((MMXmiResource)rsrc).getUuid())) { result = rsrc; break; } } } } return result; } protected Resource findResourceByImport( final ModelImport theImport, final List eResources ) { Resource result = null; if (theImport != null && eResources != null) { // A ModelImport that references an EResource instance // will have the UUID of that EResource final String uuidString = theImport.getUuid(); if (!CoreStringUtil.isEmpty(uuidString)) { final ObjectID uuid = stringToObjectID(uuidString); if (uuid != null) { result = findResourceByUUID(uuid, eResources); if (result != null) { return result; } } } // A ModelImport that references a Resource instance will have // the relative path to that resource in its location final String modelLocation = theImport.getModelLocation(); if (!CoreStringUtil.isEmpty(modelLocation) && theImport.eResource() != null) { // Defect 23340 - Simplifying this check. URI modelLocationURI = URI.createURI(modelLocation); if (modelLocationURI.isRelative()) { result = findByWorkspaceUri(modelLocationURI, theImport.eResource()); } else { result = findByURI(modelLocationURI, true); } if (result != null && eResources.contains(result)) { return result; } result = null; } // A ModelImport that references an XSDResource instance // will have the name of that XSDResource in its path/location final String path = theImport.getPath(); final String modelPath = (CoreStringUtil.isEmpty(path) ? modelLocation : path); if (!CoreStringUtil.isEmpty(modelPath)) { // Check if the path represents a logic URI that can be found final URI uri = URI.createURI(modelPath); result = findByURI(uri, true); if (result != null && eResources.contains(result)) { return result; } result = null; // Check if the resource name matches any resource in the list final String name = uri.lastSegment(); final Collection results = findResourcesByName(name, true, eResources); if (results.size() == 1) { result = (Resource)results.iterator().next(); } else if (results.size() > 1) { for (Iterator iter = eResources.iterator(); iter.hasNext();) { Resource rsrc = (Resource)iter.next(); // jh Defect 23067: Changed 'toFileString()' to 'toString()' // so it will handle both files and urls correctly String uriString = rsrc.getURI().toString(); if (uriString.endsWith(modelPath)) { return rsrc; } } } } } return result; } protected Resource findResourceByImport( final XSDSchemaDirective theImport, final List eResources ) { Resource result = null; if (theImport != null && eResources != null) { // An XSDSchemaDirective referencing an XSDResource instance will have // the relative path to that resource in its location final String schemaLocation = theImport.getSchemaLocation(); if (!CoreStringUtil.isEmpty(schemaLocation) && theImport.eResource() != null) { // Check if the path represents a logic URI that can be found final URI uri = URI.createURI(schemaLocation); result = findByURI(uri, true); if (result != null && eResources.contains(result)) { return result; } result = null; XSDResourceImpl eResource = (XSDResourceImpl)theImport.eResource(); URI baseLocationURI = eResource.getURI(); // If the base resource URI was created as a file URI then it's path is encoded so before we // resolve the referenced resource we need to encode it's relative path URI schemaLocationURI = UriHelper.makeAbsoluteUri(baseLocationURI, schemaLocation); // URI schemaLocationURI = (baseLocationURI.isFile() ? URI.createURI(schemaLocation, false): // URI.createURI(schemaLocation)); // if (baseLocationURI.isHierarchical() && !baseLocationURI.isRelative() && schemaLocationURI.isRelative()) { // schemaLocationURI = schemaLocationURI.resolve(baseLocationURI); // } result = findByURI(schemaLocationURI, true); if (result != null && eResources.contains(result)) { return result; } result = null; // Check if the resource name matches any resource in the list final String name = URI.createURI(schemaLocation).lastSegment(); final Collection results = findResourcesByName(name, true, eResources); if (results.size() == 1) { result = (Resource)results.iterator().next(); } else if (results.size() > 1) { // Ensure that all referenced schemas are resolved getExternallyReferencedResources(eResource, true, false); // Match the input XSDSchemaDirective to one in the resource for (final Iterator i = eResource.getSchema().eContents().iterator(); i.hasNext();) { EObject eObj = (EObject)i.next(); if (eObj instanceof XSDSchemaDirective && theImport == eObj) { XSDSchema resolvedSchema = ((XSDSchemaDirective)eObj).getResolvedSchema(); if (resolvedSchema != null) { Resource refResource = resolvedSchema.eResource(); if (eResources.contains(refResource)) { return refResource; } } } } } } } return result; } protected Collection findResourcesByName( final String name, final boolean caseSensitive, final List eResources ) { Collection result = new HashSet(3); if (name != null && eResources != null) { // Iterate through each resource in the resource set for (Iterator iter = eResources.iterator(); iter.hasNext();) { Resource rsrc = (Resource)iter.next(); if (rsrc != null) { final String rsrcName = rsrc.getURI().lastSegment(); if (caseSensitive && name.equals(rsrcName)) { result.add(rsrc); } if (!caseSensitive && name.equalsIgnoreCase(rsrcName)) { result.add(rsrc); } } } } return result; } /** * Return the list of external resources referenced by the specified resource * * @param eResource the resource to process for references * @param recurse If true, the result will include all direct and indirect dependent resources otherwise only the direct * dependencies are returned. * @param includeExternal If true, external resource references will be included in the resulant array, otherwise they will be * excluded from the result. * @return result */ protected List getExternallyReferencedResources( final Resource eResource, final boolean recurse, final boolean includeExternal ) { List result = new ArrayList(); Set unresolvedURIs = new HashSet(); if (eResource != null) { addExternallyReferencedResources(eResource, recurse, includeExternal, result, unresolvedURIs); // Log any resource references that cannot be resolved in the resource set if (!unresolvedURIs.isEmpty()) { for (Iterator iter = unresolvedURIs.iterator(); iter.hasNext();) { URI uri = (URI)iter.next(); String msg = ModelerCore.Util.getString("DefaultResourceFinder.Unable_to_resolve_ref_to_resource_with_uri", uri); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.ERROR, msg); } } } return result; } /** * Return the list of external resources referenced by the specified resource * * @param eResource the resource to process for references * @return result */ protected Collection getResolvedExternalResources( final Resource eResource ) { List externalResources = new ArrayList(); if (eResource != null) { addExternallyReferencedResources(eResource, false, true, externalResources, new HashSet()); } return externalResources; } /** * Add external resources referenced by the specified resource to the resultant list * * @param eResource the resource to process for references * @param recurse if true, the result will include all direct and indirect dependent resources otherwise only the direct * dependencies are returned. * @param includeExternal If true, external resource references will be included in the resulant array, otherwise they will be * excluded from the result. * @param result the resultant list to add to */ protected void addExternallyReferencedResources( final Resource eResource, final boolean recurse, final boolean includeExternal, final List result, final Set unresolvedResourceURIs ) { if (eResource != null) { // The resource must be loaded to process its references if (!eResource.isLoaded()) { try { eResource.load(getContainer().getLoadOptions()); } catch (IOException err) { String msg = ModelerCore.Util.getString("DefaultResourceFinder.Error_loading_resource", eResource); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.ERROR, msg); } } // If the resource is an XSDResource instance if (eResource instanceof XSDResourceImpl) { addExternallyReferencedResourcesForXsd((XSDResourceImpl)eResource, recurse, includeExternal, result, unresolvedResourceURIs); // If the resource is an EResource instances } else if (eResource instanceof MMXmiResource) { addExternallyReferencedResourcesForXmi((MMXmiResource)eResource, recurse, includeExternal, result, unresolvedResourceURIs); } } } /** * Add external resources referenced by the specified XMI resource to the resultant list * * @param eResource the resource to process for references * @param recurse if true, the result will include all direct and indirect dependent resources otherwise only the direct * dependencies are returned. * @param includeExternal If true, external resource references will be included in the resulant array, otherwise they will be * excluded from the result. * @param result the resultant list to add to */ protected void addExternallyReferencedResourcesForXmi( final MMXmiResource eResource, final boolean recurse, final boolean includeExternal, final List result, final Set unresolvedResourceURIs ) { if (eResource != null) { // Collect all the EObject instances in this resource using the // ModelObjectCollector class to avoid a ConcurrentModificationException // that may occur when using the TreeIterator (i.e. super.getAllContents()) final ModelObjectCollector moc = new ModelObjectCollector(eResource); // Iterate through the contents of this resource collecting externally referenced resources final List partialResult = new ArrayList(); for (final Iterator i = moc.getEObjects().iterator(); i.hasNext();) { final EObject eObject = (EObject)i.next(); for (final Iterator j = eObject.eClass().getEAllReferences().iterator(); j.hasNext();) { final EReference eReference = (EReference)j.next(); processReference(eResource, eObject, eReference, partialResult, unresolvedResourceURIs); } } // Add the result for this resource to the overall result for (Iterator i = partialResult.iterator(); i.hasNext();) { Resource rsrc = (Resource)i.next(); if (rsrc != null && !result.contains(rsrc)) { if (!includeExternal && isExternalResource(rsrc)) { continue; } result.add(rsrc); if (recurse) { addExternallyReferencedResources(rsrc, recurse, includeExternal, result, unresolvedResourceURIs); } } } } } /** * Add external resources referenced by the specified XSD resource to the resultant list * * @param eResource the resource to process for references * @param recurse if true, the result will include all direct and indirect dependent resources otherwise only the direct * dependencies are returned. * @param includeExternal If true, external resource references will be included in the resulant array, otherwise they will be * excluded from the result. * @param result the resultant list to add to */ protected void addExternallyReferencedResourcesForXsd( final XSDResourceImpl eResource, final boolean recurse, final boolean includeExternal, final List result, final Set unresolvedResourceURIs ) { if (eResource != null) { // Resolve all schema directives (import/include/redefine) Set visitedXsdResources = new HashSet(); resolveSchemaDirectives(eResource, recurse, visitedXsdResources, unresolvedResourceURIs); // Add the resource referenced through the directive to the overall result XSDSchema schema = eResource.getSchema(); for (final Iterator i = schema.eContents().iterator(); i.hasNext();) { EObject eObj = (EObject)i.next(); if (eObj instanceof XSDSchemaDirective) { XSDSchema resolvedSchema = ((XSDSchemaDirective)eObj).getResolvedSchema(); Resource rsrc = (resolvedSchema != null ? resolvedSchema.eResource() : null); if (rsrc != null && !result.contains(rsrc)) { if (!includeExternal && isExternalResource(rsrc)) { continue; } result.add(rsrc); if (recurse) { addExternallyReferencedResources(rsrc, recurse, includeExternal, result, unresolvedResourceURIs); } } } } // Ensure that the schema for schema resource (e.g. "http://www.w3.org/2001/XMLSchema") is added to the result; if (includeExternal) { Resource rsrc = schema.getSchemaForSchema().eResource(); if (rsrc != null && !result.contains(rsrc)) { result.add(rsrc); } } } } /** * Walk through all XSDDirectives for the specified XSDResource and attempt to resolve those that are undefined. * * @param eResource * @param recurse * @param visited * @since 4.3 */ protected void resolveSchemaDirectives( final XSDResourceImpl eResource, final boolean recurse, final Set visited, final Set unresolvedResourceURIs ) { if (eResource != null && !visited.contains(eResource)) { // The resource must be loaded to retrieve its contents if (!eResource.isLoaded()) { try { eResource.load(getContainer().getLoadOptions()); } catch (IOException err) { String msg = ModelerCore.Util.getString("DefaultResourceFinder.Error_loading_resource", eResource); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.ERROR, msg); } } // Add this resource to the list of those visited visited.add(eResource); // Check all imports to see if they were resolved for (final Iterator i = eResource.getSchema().eContents().iterator(); i.hasNext();) { EObject eObj = (EObject)i.next(); if (eObj instanceof XSDSchemaDirective) { XSDSchema resolvedSchema = resolveSchemaDirective((XSDSchemaDirective)eObj); // Log any unresolved schema directives if (resolvedSchema == null || resolvedSchema.eResource() == null || resolvedSchema.eResource().getResourceSet() == null) { URI unresolvedURI = URI.createURI(((XSDSchemaDirective)eObj).getSchemaLocation()); unresolvedResourceURIs.add(unresolvedURI); continue; } // Follow the chain and resolve all directives for the schema being imported if (recurse) resolveSchemaDirectives((XSDResourceImpl)resolvedSchema.eResource(), recurse, visited, unresolvedResourceURIs); } } } } /** * Resolve the specified XSDSchemaDirective and resolve against resources in the resource set * * @param eResource * @param recurse * @param visited * @since 4.3 */ protected XSDSchema resolveSchemaDirective( final XSDSchemaDirective directive ) { XSDSchema resolvedSchema = null; if (directive != null) { resolvedSchema = directive.getResolvedSchema(); // Import is not yet resolved, attempt to locate the reference ... if (resolvedSchema == null && directive instanceof XSDImportImpl) { resolvedSchema = ((XSDImportImpl)directive).importSchema(); } // If the resolvedSchema reference exists but is an eProxy then attempt to resolve it if (resolvedSchema != null && resolvedSchema.eIsProxy()) { resolvedSchema = (XSDSchema)EcoreUtil.resolve(resolvedSchema, getContainer()); } // Directive is not yet resolved, attempt to locate the referenced // XSDResource using the schema location information in the directive String location = directive.getSchemaLocation(); XSDResourceImpl eResource = (XSDResourceImpl)directive.eResource(); if (resolvedSchema == null && eResource != null && !CoreStringUtil.isEmpty(location)) { XSDResourceImpl refdResource = null; URI schemaLocationUri = UriHelper.makeAbsoluteUri(eResource.getURI(), location); // URI schemaLocationUri = getAbsoluteLocation(eResource.getURI(), location); refdResource = (XSDResourceImpl)findByURI(schemaLocationUri, false); // Update the directive with the resolved schema if (refdResource != null) { resolvedSchema = refdResource.getSchema(); directive.setResolvedSchema(resolvedSchema); if (directive instanceof XSDImport) { ((XSDSchemaImpl)resolvedSchema).imported((XSDImport)directive); } else if (directive instanceof XSDInclude) { ((XSDSchemaImpl)resolvedSchema).included((XSDInclude)directive); } else if (directive instanceof XSDRedefine) { ((XSDSchemaImpl)resolvedSchema).redefined((XSDRedefine)directive); } } } } return resolvedSchema; } /** * Add the specified list any external resource for this EReference feature */ protected void processReference( final Resource eResource, final EObject eObject, final EReference eReference, final List externalResources, final Set unresolvedResourceURIs ) { if (!eReference.isContainment() && !eReference.isContainer() && !eReference.isVolatile()) { // The reference is NOT the container NOR a containment feature ... final Object value = eObject.eGet(eReference, false); if (eReference.isMany()) { // There may be many values ... final Iterator valueIter = ((List)value).iterator(); while (valueIter.hasNext()) { final Object valueInList = valueIter.next(); if (valueInList instanceof EObject) { processReferenceValue(eResource, eObject, eReference, (EObject)valueInList, externalResources, unresolvedResourceURIs); } } } else { // There may be 0..1 value ... if (value instanceof EObject) { processReferenceValue(eResource, eObject, eReference, (EObject)value, externalResources, unresolvedResourceURIs); } } } } /** * Add the specified list any external resource for this EReference feature */ protected void processReferenceValue( final Resource eResource, final EObject eObject, final EReference eReference, final EObject value, final List externalResources, final Set unresolvedResourceURIs ) { if (value == null) { return; } // Check if the object is an EMF proxy ... if (value.eIsProxy()) { if (value instanceof InternalEObject) { final InternalEObject iObject = (InternalEObject)value; final URI proxyUri = iObject.eProxyURI(); CoreArgCheck.isNotNull(proxyUri); // Get the URI of the resource ... URI resourceUri = proxyUri.trimFragment(); // Make the relative URI absolute if necessary URI baseLocationUri = eResource.getURI(); URI proxyLocationUri = UriHelper.makeAbsoluteUri(baseLocationUri, resourceUri); // URI proxyLocationUri = resourceUri; // if (baseLocationUri.isHierarchical() && !baseLocationUri.isRelative() && proxyUri.isRelative()) { // proxyLocationUri = proxyLocationUri.resolve(baseLocationUri); // } Resource rsrc = findByURI(proxyLocationUri, true); // If the resource URI is a workspace relative path (e.g. "/project/.../model.xmi") if (rsrc == null && baseLocationUri.isFile() && resourceUri.toString().charAt(0) == '/') { String baseLocation = URI.decode(baseLocationUri.toFileString()); String projectName = resourceUri.segment(0); String proxyLocation = URI.decode(resourceUri.toString()); int index = baseLocation.indexOf(projectName); if (index != -1) { proxyLocation = baseLocation.substring(0, index - 1) + proxyLocation; rsrc = findByURI(URI.createFileURI(proxyLocation), true); } } if (rsrc != null && eResource != rsrc && !externalResources.contains(rsrc)) { externalResources.add(rsrc); } else if (rsrc == null) { unresolvedResourceURIs.add(resourceUri); } } } else { Resource rsrc = value.eResource(); if (eResource != rsrc && !externalResources.contains(rsrc)) { externalResources.add(rsrc); } } } // protected URI getAbsoluteLocation(final URI baseLocationUri, final String location) { // CoreArgCheck.isNotNull(baseLocationUri); // CoreArgCheck.isNotNull(location); // // // If the base resource URI was created as a file URI then it's path is encoded so before we // // resolve the referenced resource we need to encode it's relative path // URI locationUri = (baseLocationUri.isFile() ? URI.createURI(location, false): URI.createURI(location)); // return getAbsoluteLocation(baseLocationUri,locationUri); // } // // protected URI getAbsoluteLocation(final URI baseLocationUri, final URI relativeLocationUri) { // CoreArgCheck.isNotNull(baseLocationUri); // CoreArgCheck.isNotNull(relativeLocationUri); // // URI locationUri = relativeLocationUri; // if (baseLocationUri.isHierarchical() && !baseLocationUri.isRelative() && locationUri.isRelative()) { // locationUri = locationUri.resolve(baseLocationUri); // } // return locationUri; // } protected ObjectID stringToObjectID( final String str ) { if (str == null || str.length() < UUID_STRING_LENGTH) { return null; } ObjectID uuid = null; // Extract the UUID from the input string String uuidString = extractUuidFromString(str); if (uuidString == null) { // Try to lowercase the string and extract the UUID uuidString = extractUuidFromString(str.toLowerCase()); } if (uuidString != null) { try { uuid = IDGenerator.getInstance().stringToObject(uuidString, UUID.PROTOCOL); } catch (InvalidIDException e) { ModelerCore.Util.log(IStatus.ERROR, e.getMessage()); } } return uuid; } /** */ protected String extractUuidFromString( final String str ) { if (str == null || str.length() < UUID_STRING_LENGTH) { return null; } String uuidString = null; int strLength = str.length(); if (strLength == UUID_STRING_LENGTH) { // The string is of the form "mmuuid:0b5fb081-1275-1eec-8518-c32201e76066" if (str.startsWith(UUID_PROTOCOL_WITH_STANDARD_DELIMITER)) { uuidString = str; // The string is of the form "mmuuid/0b5fb081-1275-1eec-8518-c32201e76066" } else if (str.startsWith(UUID_PROTOCOL_WITH_ALTERNATE_DELIMITER)) { uuidString = UUID_PROTOCOL_WITH_STANDARD_DELIMITER + str.substring(UUID_PROTOCOL_WITH_ALTERNATE_DELIMITER.length()); } } else { // Extract the UUID if it is embedded within a larger string like a eProxy URI // of the form "/project/folder/file.xmi#mmuuid:0b5fb081-1275-1eec-8518-c32201e76066" int beginIndex = str.indexOf(UUID_PROTOCOL_WITH_STANDARD_DELIMITER); if (beginIndex != -1) { int endIndex = Math.min(strLength, beginIndex + UUID_STRING_LENGTH); if (endIndex == strLength) { uuidString = str.substring(beginIndex); } else if (endIndex < strLength) { uuidString = str.substring(beginIndex, endIndex); } } // Extract the UUID if it is embedded within a larger string like a eProxy URI // of the form "/project/folder/file.xmi#mmuuid/0b5fb081-1275-1eec-8518-c32201e76066" beginIndex = str.indexOf(UUID_PROTOCOL_WITH_ALTERNATE_DELIMITER); if (beginIndex != -1) { int endIndex = Math.min(strLength, beginIndex + UUID_STRING_LENGTH); if (endIndex == strLength) { uuidString = UUID_PROTOCOL_WITH_STANDARD_DELIMITER + str.substring(beginIndex + UUID_PROTOCOL_WITH_ALTERNATE_DELIMITER.length()); } else if (endIndex < strLength) { uuidString = UUID_PROTOCOL_WITH_STANDARD_DELIMITER + str.substring(beginIndex + UUID_PROTOCOL_WITH_ALTERNATE_DELIMITER.length(), endIndex); } } } return uuidString; } }