/*
* 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;
}
}