/*
* 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.workspace;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.teiid.core.designer.TeiidDesignerException;
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.common.xsd.XsdHeader;
import org.teiid.designer.common.xsd.XsdHeaderReader;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.reader.ZipReaderCallback;
import org.teiid.designer.core.types.DatatypeConstants;
import org.teiid.designer.core.xmi.ModelImportInfo;
import org.teiid.designer.core.xmi.XMIHeader;
import org.teiid.designer.core.xmi.XMIHeaderReader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* WorkspaceResourceFinder
*
* @since 8.0
*/
public class WorkspaceResourceFinderUtil {
protected static final String URI_REFERENCE_DELIMITER = DatatypeConstants.URI_REFERENCE_DELIMITER;
/**
* Resource filter for return only VDB archive files
*/
public static final ResourceFilter VDB_RESOURCE_FILTER = new VdbResourceFilter();
private static final String SCHEME_PLATFORM = "platform:"; //$NON-NLS-1$
private static final String SCHEME_FILE = "file:"; //$NON-NLS-1$
private static final String PLATFORM_RESOURCE_SEGMENT = "/resource"; //$NON-NLS-1$
private static final char DEVICE_IDENTIFIER = ':';
private static final String AUTHORITY_SEPARATOR = "//"; //$NON-NLS-1$
private static final char SEGMENT_SEPARATOR = '/';
protected static final String XML_SCHEMA_ECLIPSE_PLATFORM_URI_PREFIX = ModelerCore.XML_SCHEMA_ECLIPSE_PLATFORM_URI_PREFIX;
protected static final String XML_SCHEMA_ECLIPSE_PLATFORM_URI_SUFFIX = "XMLSchema.xsd"; //$NON-NLS-1$
protected static final String XML_MAGIC_SCHEMA_ECLIPSE_PLATFORM_URI_SUFFIX = "MagicXMLSchema.xsd"; //$NON-NLS-1$
protected static final String XML_SCHEMA_INSTANCE_ECLIPSE_PLATFORM_URI_SUFFIX = "XMLSchema-instance.xsd"; //$NON-NLS-1$
/** Defines the expected name of the primitive types model file */
public static final String UML_PRIMITIVE_TYPES_MODEL_FILE_NAME = "primitiveTypes.xmi"; //$NON-NLS-1$
/** Defines the expected primitive types internal URI */
protected static final String UML_PRIMITIVE_TYPES_INTERNAL_URI = "http://www.metamatrix.com/metamodels/UmlPrimitiveTypes-instance"; //$NON-NLS-1$
/** Defines the expected UML2 metamodel URI */
protected static final String UML_METAMODEL_URI = "pathmap://UML2_METAMODELS/UML2.metamodel.uml2"; //$NON-NLS-1$
/** Defines the expected name of the relationship types model file */
public static final String RELATIONSHIP_PRIMITIVE_TYPES_MODEL_FILE_NAME = "builtInRelationshipTypes.xmi"; //$NON-NLS-1$
/** Defines the expected relationship types internal URI */
protected static final String RELATIONSHIP_PRIMITIVE_TYPES_INTERNAL_URI = "http://www.metamatrix.com/relationships/BuiltInRelationshipTypes-instance"; //$NON-NLS-1$
/**
* Return the IResource instance corresponding to the specified EMF resource. If the resource is one of the well-known Teiid
* Designer/EMF global resources such as
* <p>
* "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance" "http://www.w3.org/2001/XMLSchema"
* "http://www.w3.org/2001/MagicXMLSchema" "http://www.w3.org/2001/XMLSchema-instance"
* </p>
* then null is returned since there is no IResource in the workspace that represents any one of those models.
*
* @param resource
* @return the IResource identified by the URI if it exists; may return null
*/
public static IResource findIResource( final Resource resource ) {
try {
if (resource != null && resource.getURI() != null && getWorkspace() != null) return findIResource(resource.getURI());
} catch (final IllegalStateException ise) {
// do nothing
}
return null;
}
/**
* Return the IResource instance corresponding to the specified URI string. The URI represents a relative path within the
* workspace to particular file resource. If the URI is one of the well-known Teiid Designer/EMF identifiers to a global
* resource such as
* <p>
* "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance" "http://www.w3.org/2001/XMLSchema"
* "http://www.w3.org/2001/MagicXMLSchema" "http://www.w3.org/2001/XMLSchema-instance"
* </p>
* then null is returned since there is no IResource in the workspace that represents any one of those models.
*
* @param workspaceUri the URI string
* @return the IFile identified by the URI if it exists; may return null
*/
public static IFile findIResource( final String workspaceUri ) {
if (!isValidWorkspaceUri(workspaceUri)) return null;
final String normalizedUriString = normalizeUriString(workspaceUri);
// MyDefect : 16368 Refactored methods.
IFile fileResource;
final Collection<IFile> fileResources = getProjectFileResources();
// If the workspace URI starts with "http" then check it against the target
// namespaces of any XML schema in the workspace ...
fileResource = getResourceStartsWithHttp(fileResources, normalizedUriString);
if (fileResource != null) return fileResource;
// Try to convert the workspace URI to a relative path and then match
// this path in workspace to one of the IResource paths instances
fileResource = getResourceStartsWithPathSeparator(fileResources, normalizedUriString);
if (fileResource != null) return fileResource;
// Try to match the workspace URI to a IResource location ...
fileResource = getResourceByLocation(fileResources, normalizedUriString);
if (fileResource != null) return fileResource;
return null;
}
/**
* Return the IResource instance corresponding to the specified URI string. The URI represents a relative path within the
* workspace to particular file resource. If the URI is one of the well-known Teiid Designer/EMF identifiers to a global
* resource such as
* <p>
* "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance" "http://www.w3.org/2001/XMLSchema"
* "http://www.w3.org/2001/MagicXMLSchema" "http://www.w3.org/2001/XMLSchema-instance"
* </p>
* then null is returned since there is no IResource in the workspace that represents any one of those models.
*
* @param resourceUri the URI
* @return the IResource identified by the URI if it exists; may return null
*/
public static IResource findIResource( final URI resourceUri ) {
try {
if (resourceUri != null && getWorkspace() != null) {
// Match the Emf resource location against the location
final String uriString = normalizeUriToString(resourceUri);
final Collection<IFile> fileResources = getProjectFileResources();
final IFile fileResource = getResourceByLocation(fileResources, uriString);
if (fileResource != null) return fileResource;
}
} catch (final IllegalStateException ise) {
// do nothing
// MyDefect : getWorkspace() now throws this IllegalStateException exception.
ModelerCore.Util.log(ise);
}
return null;
}
/**
* Return the collection of {@link IFile} instances that match the specified name.
* The name must consist of only one path segment and may or may not have
* a file extension. If no {@link IFile} instances are found that match this name an
* empty collection is returned.
*
* @param name the name of the IResource
* @return the {@link IFile} collection
*/
public static Collection<IFile> findIResourceByName( final String name ) {
if (name == null || name.length() == 0 || getWorkspace() == null)
return Collections.emptyList();
FileNameResourceCollectorVisitor visitor = new FileNameResourceCollectorVisitor(name);
getProjectFileResources(visitor);
return visitor.getFileResources();
}
/**
* Return the collection of {@link IFile} instances that match the specified name.
* The name must consist of only one path segment and may or may not have a
* file extension. If no {@link IFile} instances are found that match this name
* an empty collection is returned.
*
* @param name the name of the IResource
* @param project the target project
* @return the {@link IFile} collection
*/
public static Collection<IFile> findIResourceInProjectByName( final String name, final IProject project) {
if (name == null || name.length() == 0 || getWorkspace() == null)
return Collections.emptyList();
FileNameResourceCollectorVisitor visitor = new FileNameResourceCollectorVisitor(name);
try {
project.accept(visitor);
} catch (final CoreException e) {
// do nothing
ModelerCore.Util.log(e);
}
return visitor.getFileResources();
}
/**
* Return the {@link IFile} instance that matches the specified path.
* The path is the relative path in the workspace. If no
* file is found that match this path a null is returned.
*
* @param workspacePath the path to the resource
* @return the {@link IFile}
*/
public static IFile findIResourceByPath( final IPath workspacePath ) {
if (workspacePath == null || workspacePath.isEmpty() || getWorkspace() == null)
return null;
FileResourceCollectorVisitor visitor = new FileResourceCollectorVisitor() {
@Override
public boolean visit(IResource resource) {
if (! resource.exists() || resource.getType() != IResource.FILE || !getResourceFilter().accept(resource))
return false;
IPath path = resource.getFullPath();
// Do not process file names staring with '.' since these
// are considered reserved for Eclipse specific files
if (path.lastSegment().charAt(0) == '.')
return false;
if (path.equals(workspacePath))
addResource(resource);
return true;
}
};
getProjectFileResources(visitor);
if (visitor.getFileResources().size() == 0)
return null;
// Return the first one in the collection as there should be only one
return visitor.getFileResources().iterator().next();
}
/**
* Return the {@link IFile} instance that matches the stringified UUID.
* If the stringified UUID is null, empty, does not have a
* UUID.PROTOCOL prefix or no match is found then null is returned.
*
* @param stringifiedUuid the stringified form of a UUID instance
* @return the {@link IFile}
*/
public static IFile findIResourceByUUID( final String stringifiedUuid ) {
if (CoreStringUtil.isEmpty(stringifiedUuid) || !stringifiedUuid.startsWith(UUID.PROTOCOL) || getWorkspace() == null) return null;
// Visitor should only look for XMI files with UUIDs in them
// If the resource is a FOLDER or PROJECT we should return TRUE so that the resource's children will get visited
// If we encounter a XSD or XMI file, we return false so the visitation stops at the model
FileResourceCollectorVisitor visitor = new FileResourceCollectorVisitor() {
@Override
public boolean visit(IResource resource) {
if (resource.exists() && resource.getType() == IResource.FILE && getResourceFilter().accept(resource) ) {
if (ModelUtil.isXsdFile(resource))
return false;
if( ModelUtil.isModelFile(resource, true)) {
XMIHeader header = ModelUtil.getXmiHeader(resource);
if (header != null && stringifiedUuid.equals(header.getUUID())) {
addResource(resource);
}
return false;
}
if( resource.getType() == IResource.PROJECT ||
resource.getType() == IResource.FOLDER ) {
return true;
}
return false;
}
return true;
}
};
getProjectFileResources(visitor);
if (visitor.getFileResources().size() == 0)
return null;
// Return the first one in the collection as there should be only one
return visitor.getFileResources().iterator().next();
}
/**
* Get the absolute location of give relative path using the given base
*
* @param base
* @param relativePath
*
* @return absolute file path
*/
public static String getAbsoluteLocation( final File base, final String relativePath ) {
final URI baseLocation = URI.createFileURI(base.getAbsolutePath());
URI relLocation = URI.createURI(relativePath, false);
if (baseLocation.isHierarchical() && !baseLocation.isRelative() && relLocation.isRelative()) relLocation = relLocation.resolve(baseLocation);
return URI.decode(relLocation.toString());
}
/**
* Find all files in open modelling projects,
* ie. this will ignore projects that lack a modelling nature
*
* @return collection of file resources
*/
public static Collection<IFile> getProjectFileResources() {
final FileResourceCollectorVisitor visitor = new FileResourceCollectorVisitor();
getProjectFileResources(visitor);
return visitor.getFileResources();
}
/**
* Find all files in open modelling projects using the given visitor.
*
* @param visitor
*/
public static void getProjectFileResources(IResourceVisitor visitor) {
final IWorkspace workspace = getWorkspace();
if (workspace == null || workspace.getRoot() == null)
return;
final IWorkspaceRoot wsRoot = workspace.getRoot();
final IProject[] projects = wsRoot.getProjects();
for (final IProject project : projects) {
if (! project.isOpen())
continue;
// Ignore of projects without a modelling nature
if (! ModelerCore.hasModelNature(project))
continue;
try {
project.accept(visitor);
} catch (final CoreException e) {
// do nothing
ModelerCore.Util.log(e);
}
}
}
/**
* Get all file resources contained in the given project
*
* @param project
*
* @return collection of file resources
*/
public static Collection<IFile> getProjectFileResources(final IProject project) {
return getProjectFileResources(project, null);
}
/**
* Get all file resources contained in the given project,
* filtered by the given filter.
*
* @param project
* @param filter
*
* @return collection of file resources
*/
public static Collection<IFile> getProjectFileResources(final IProject project, final ResourceFilter filter ) {
CoreArgCheck.isNotNull(project);
if (! ModelerCore.hasModelNature(project))
return Collections.emptyList();
// Collect all IResources within the given project
final FileResourceCollectorVisitor visitor = new FileResourceCollectorVisitor(filter);
try {
project.accept(visitor);
} catch (final CoreException e) {
ModelerCore.Util.log(e);
}
// List is required since visitor's collection is unmodifiable
final Collection<IFile> fileResources = new ArrayList<IFile>(visitor.getFileResources());
final Iterator<IFile> iterator = fileResources.iterator();
while(iterator.hasNext()) {
final IFile fileResource = iterator.next();
final IPath path = fileResource.getFullPath();
// Do not process file names starting with '.' since these
// are considered reserved for Eclipse specific files
if (path.lastSegment().charAt(0) == '.')
iterator.remove();
}
return fileResources;
}
/**
* Return IResource[] array representing the dependent IResource instances. The dependent resources are found by reading the
* model imports declarations in the specified resource. Only references to IResource instances that can be found in the
* workspace will be returned. If an import declaration to one of the well-know Teiid Designer/EMF global resources such as
* <p>
* "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance" "http://www.w3.org/2001/XMLSchema"
* "http://www.w3.org/2001/MagicXMLSchema" "http://www.w3.org/2001/XMLSchema-instance"
* </p>
* is encountered, a corresponding IResource does not exist in the workspace and, therefore, cannot be returned as part of the
* result. If the method is called outside of the Eclipse runtime environment, or if the specified IResource is null or cannot
* be found on the file system then an empty list will be returned.
*
* @param iResource the IResource to examine for import declarations. If null, or it not running in a Eclipse runtime
* environment, an empty list will be returned.
* @return the IResource[] references of dependent resources
*/
public static List<IFile> getDependentResources( final IResource iResource ) {
if (iResource == null || getWorkspace() == null)
return Collections.emptyList();
final List<IFile> result = new ArrayList();
try {
final File iResourceFile = ModelUtil.getLocation(iResource).toFile();
if (!iResourceFile.exists())
return Collections.emptyList();
// Get the header information from the XSD file
if (ModelUtil.isXsdFile(iResource)) {
final XsdHeader header = XsdHeaderReader.readHeader(iResourceFile);
if (header != null) {
// Add all the imported schema locations
String[] locations = header.getImportSchemaLocations();
for (int i = 0; i != locations.length; ++i) {
final String location = locations[i];
IFile dependentIResource = findIResource(location);
if (dependentIResource == null) {
final String absolutePath = getAbsoluteLocation(iResourceFile, location);
dependentIResource = findIResource(absolutePath);
}
if (dependentIResource != null && !result.contains(dependentIResource)) result.add(dependentIResource);
}
// Add all the included schema locations
locations = header.getIncludeSchemaLocations();
for (int i = 0; i != locations.length; ++i) {
final String location = locations[i];
IFile dependentIResource = findIResource(location);
if (dependentIResource == null) {
final String absolutePath = getAbsoluteLocation(iResourceFile, location);
dependentIResource = findIResource(absolutePath);
}
if (dependentIResource != null && !result.contains(dependentIResource)) result.add(dependentIResource);
}
}
// Get the header information from the XMI file
} else if (ModelUtil.isModelFile(iResource)) {
final XMIHeader header = XMIHeaderReader.readHeader(iResourceFile);
if (header != null) {
final ModelImportInfo[] infos = header.getModelImportInfos();
for (final ModelImportInfo info : infos) {
IFile dependentIResource = null;
final String location = info.getLocation();
final String path = info.getPath();
if (!CoreStringUtil.isEmpty(path)) dependentIResource = findIResource(path);
else if (!CoreStringUtil.isEmpty(location)) {
final String depPath = iResource.getFullPath().removeLastSegments(1).append(location).toString();
if (!isGlobalResource(depPath)) {
dependentIResource = findIResource(depPath);
if (dependentIResource == null) {
final String absolutePath = getAbsoluteLocation(iResourceFile, location);
dependentIResource = findIResource(absolutePath);
}
}
}
if (dependentIResource != null && !result.contains(dependentIResource)) result.add(dependentIResource);
}
}
// Get the header information from the VDB archive file
} else if (ModelUtil.isVdbArchiveFile(iResource)) {
final XMIHeader header = ModelUtil.getXmiHeader(iResourceFile);
if (header != null) {
final ModelImportInfo[] infos = header.getModelImportInfos();
for (final ModelImportInfo info : infos) {
IFile dependentIResource = null;
final String location = info.getLocation();
final String path = info.getPath();
if (!CoreStringUtil.isEmpty(path)) dependentIResource = findIResource(path);
else if (!CoreStringUtil.isEmpty(location)) if (!isGlobalResource(location)) {
dependentIResource = findIResource(location);
if (dependentIResource == null) {
final String absolutePath = getAbsoluteLocation(iResourceFile, location);
dependentIResource = findIResource(absolutePath);
}
}
if (dependentIResource != null && !result.contains(dependentIResource)) result.add(dependentIResource);
}
}
}
} catch (final Exception err) {
final Object[] params = new Object[] {iResource.getFullPath()};
final String msg = ModelerCore.Util.getString("WorkspaceResourceFinderUtil.Error_getting_model_imports_from_resource", params); //$NON-NLS-1$
ModelerCore.Util.log(IStatus.ERROR, err, msg);
}
return result;
}
/**
* Returns a valid path reference if the specified URI string is one of the
* well-known Teiid Designer/EMF identifiers to a global resource such as
* <p>
* "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance"
* "http://www.metamatrix.com/metamodels/UmlPrimitiveTypes-instance"
* "http://www.metamatrix.com/relationships/BuiltInRelationshipTypes-instance" "http://www.w3.org/2001/XMLSchema"
* "http://www.w3.org/2001/MagicXMLSchema" "http://www.w3.org/2001/XMLSchema-instance"
* </p>
* otherwise null is returned.
*
* @param uri the URI string
* @return a valid path reference or null
*/
public static String getGlobalResourceUri( final String uri ) {
if (uri == null) return null;
// If the URI is to the Teiid Designer built-in datatypes model ...
if (uri.startsWith(DatatypeConstants.BUILTIN_DATATYPES_URI)) return DatatypeConstants.BUILTIN_DATATYPES_URI;
if (uri.endsWith(DatatypeConstants.DATATYPES_MODEL_FILE_NAME)) return DatatypeConstants.BUILTIN_DATATYPES_URI;
// If the URI is to the Teiid Designer built-in UML primitive types model ...
if (uri.startsWith(UML_PRIMITIVE_TYPES_INTERNAL_URI)) return UML_PRIMITIVE_TYPES_INTERNAL_URI;
if (uri.endsWith(UML_PRIMITIVE_TYPES_MODEL_FILE_NAME)) return UML_PRIMITIVE_TYPES_INTERNAL_URI;
if (uri.startsWith(UML_METAMODEL_URI)) return UML_METAMODEL_URI;
// If the URI is to the Teiid Designer built-in relationship model ...
if (uri.endsWith(RELATIONSHIP_PRIMITIVE_TYPES_INTERNAL_URI)) return RELATIONSHIP_PRIMITIVE_TYPES_INTERNAL_URI;
if (uri.endsWith(RELATIONSHIP_PRIMITIVE_TYPES_MODEL_FILE_NAME)) return RELATIONSHIP_PRIMITIVE_TYPES_INTERNAL_URI;
// If the URI is to one of the Emf XMLSchema resources ...
if (uri.startsWith(ModelerCore.XML_SCHEMA_INSTANCE_GENERAL_URI)) return ModelerCore.XML_SCHEMA_INSTANCE_GENERAL_URI;
if (uri.startsWith(ModelerCore.XML_SCHEMA_GENERAL_URI)) return ModelerCore.XML_SCHEMA_GENERAL_URI;
if (uri.startsWith(ModelerCore.XML_MAGIC_SCHEMA_GENERAL_URI)) return ModelerCore.XML_MAGIC_SCHEMA_GENERAL_URI;
if (uri.equals(ModelerCore.XML_XSD_GENERAL_URI)) return ModelerCore.XML_XSD_GENERAL_URI;
// If the URI is in the form of an Eclipse platform path to
// one of the Emf XMLSchema resources ...
if (uri.startsWith(XML_SCHEMA_ECLIPSE_PLATFORM_URI_PREFIX)) // MagicXMLSchema.xsd suffix on the resource URI
if (uri.indexOf(XML_MAGIC_SCHEMA_ECLIPSE_PLATFORM_URI_SUFFIX) > 0) return ModelerCore.XML_MAGIC_SCHEMA_GENERAL_URI;
else if (uri.indexOf(XML_SCHEMA_ECLIPSE_PLATFORM_URI_SUFFIX) > 0) return ModelerCore.XML_SCHEMA_GENERAL_URI;
else if (uri.indexOf(XML_SCHEMA_INSTANCE_ECLIPSE_PLATFORM_URI_SUFFIX) > 0) return ModelerCore.XML_SCHEMA_INSTANCE_GENERAL_URI;
// Next check if the import reference is to one of our system models
try {
final Resource[] systemModels = ModelerCore.getSystemVdbResources();
for (int i = 0; i != systemModels.length; ++i) {
final String systemModelUri = URI.decode(systemModels[i].getURI().toString());
if (uri.equalsIgnoreCase(systemModelUri)) return systemModelUri;
}
} catch (final Exception e) {
// do nothing
}
// Next check if the import reference is to one of our metamodels
try {
if (ModelerCore.getMetamodelRegistry().containsURI(uri)) {
final URI metamodelUri = ModelerCore.getMetamodelRegistry().getURI(uri);
return ModelerCore.getMetamodelRegistry().getMetamodelDescriptor(metamodelUri).getNamespaceURI();
}
} catch (final Exception e) {
// do nothing
}
return null;
}
private static IFile getResourceByLocation( final Collection<IFile> fileResources, final String workspaceUri ) {
String resourceLocation;
// Try to match the workspace URI to a IResource location ...
for (final IFile fileResource : fileResources) {
IPath location = fileResource.getLocation();
resourceLocation = location.toOSString();
if (workspaceUri.endsWith(resourceLocation))
return fileResource;
if (resourceLocation.endsWith(workspaceUri))
return fileResource;
resourceLocation = location.toString();
if (workspaceUri.endsWith(resourceLocation))
return fileResource;
if (resourceLocation.endsWith(workspaceUri))
return fileResource;
// Case 5683 - look for a match of the supplied workspaceUri (usually file.ext) to the
// last segment of the fileResource path.
final String fileNameSegment = location.lastSegment();
if (workspaceUri.equalsIgnoreCase(fileNameSegment))
return fileResource;
}
return null;
}
private static IFile getResourceStartsWithHttp( final Collection<IFile> fileResources, final String workspaceUri ) {
String targetNamespace;
if (! workspaceUri.startsWith("http")) //$NON-NLS-1$
return null;
for (final IFile fileResource : fileResources) {
targetNamespace = getXsdTargetNamespace(fileResource);
if (workspaceUri.equals(targetNamespace))
return fileResource;
}
return null;
}
private static IFile getResourceStartsWithPathSeparator( final Collection<IFile> fileResources, final String workspaceUri ) {
if (workspaceUri.charAt(0) != IPath.SEPARATOR)
return null;
IPath pathInWorkspace = new Path(workspaceUri);
for (final IFile fileResource : fileResources) {
if (fileResource == null)
continue;
if (fileResource.getFullPath().equals(pathInWorkspace))
return fileResource;
}
return null;
}
/**
* Find all resources in the same project that use the given resource.
* <p>
* To control the depth of the search so as to find indirect relationships between
* resources, set the depth value accordingly:
* <ul>
* <li>{@link IResource#DEPTH_ZERO} only direct resource dependencies;</li>
* <li>{@link IResource#DEPTH_INFINITE} direct and indirect resource dependencies</li>
* </ul>
*
* @param resource
* @param depth one of {@link IResource#DEPTH_ZERO} or {@link IResource#DEPTH_INFINITE}
*
* @return collection of resources that use the given resource
*/
public static Collection<IFile> getResourcesThatUse( final IResource resource, int depth ) {
return getResourcesThatUse(resource, null, depth);
}
/**
* Find all resources in the same project that use the given resource,
* filtered by the given filter.
* <p>
* To control the depth of the search so as to find indirect relationships between
* resources, set the depth value accordingly:
* <ul>
* <li>{@link IResource#DEPTH_ZERO} only direct resource dependencies;</li>
* <li>{@link IResource#DEPTH_INFINITE} direct and indirect resource dependencies</li>
* </ul>
*
* @param resource
* @param filter
* @param depth one of {@link IResource#DEPTH_ZERO} or {@link IResource#DEPTH_INFINITE}
* @return collection of resources that use the given resource
*/
public static Collection<IFile> getResourcesThatUse( final IResource resource, final ResourceFilter filter, int depth ) {
Collection<IFile> fileResources = new HashSet<IFile>();
getResourcesThatUse(resource, filter, depth, fileResources);
return fileResources;
}
private static void getResourcesThatUse(final IResource resource, final ResourceFilter filter, int depth, Collection<IFile> resultDependents) {
// search the resource's project for any models that import anything beneath the path of the resource
IProject project = resource.getProject();
IPath targetPath = resource.getFullPath();
Collection<IFile> projectResources = getProjectFileResources(project, filter);
/* Check to see if any of the resources found
* depend upon the specified resource
*/
// Iterate through all the file resources
for (IFile fileResource : projectResources) {
// Get all the dependents of this file resource
final Collection<IFile> dependents = getDependentResources(fileResource);
// Iterate through the dependents
for (final IResource dependent : dependents) {
if (! targetPath.equals(dependent.getFullPath()))
continue;
// This dependent imports the target resource
final String modelPath = fileResource.getFullPath().toString();
// If the URI is to the Teiid Designer built-in datatypes resource or to one
// of the Emf XMLSchema resources then continue since there is no
// ModelReference to add.
if (isGlobalResource(modelPath))
continue;
// only add and recurse if haven't already
if (resultDependents.add(fileResource) && (IResource.DEPTH_INFINITE == depth)) {
getResourcesThatUse(fileResource, filter, depth, resultDependents);
}
break;
}
}
}
private static boolean dependsOn(final IResource resourceBeingChecked,
final IResource model) {
final Collection<IFile> dependents = getDependentResources(resourceBeingChecked);
for (final IResource dependent : dependents) {
if (model.equals(dependent)) {
return true;
}
// recurse
if (dependsOn(dependent, model)) {
return true;
}
}
return false;
}
/**
* @param model the model being checked (cannot be <code>null</code>)
* @return the model that is causing the circular dependencies (can be <code>null</code> if no circular dependencies)
*/
public static IFile getFirstResourceHavingCircularDependency(final IResource model) {
final Collection<IFile> dependents = getDependentResources(model);
if ((dependents == null) || dependents.isEmpty()) {
return null;
}
for (final IFile dependent : dependents) {
if (dependsOn(dependent, model)) {
return dependent;
}
}
return null;
}
/**
* Return {@link IFile} collection representing vdb instances in the given resources' projects that contain a
* version of any resource in the specified collection.
*
* If the method is called outside of the Eclipse runtime environment, or if the specified collection is null,
* empty or contains resource instances that cannot be found on the file system then an empty
* collection will be returned.
*
* @param resources the collection to search all vdb archive files for references to. If null or it not
* running in a Eclipse runtime environment, an empty collection will be returned.
* @return the {@link IFile} collection representing vdb archive files within the workspace
*/
public static Collection<IFile> getVdbResourcesThatContain( final Collection<IResource> resources ) {
if (resources == null || resources.isEmpty() || getWorkspace() == null)
return Collections.emptyList();
// Retrieve any vdb archive resources that reference the specified IResource
final Collection result = new HashSet();
for (IResource resource : resources) {
result.addAll(getVdbResourcesThatContain(resource));
}
return result;
}
/**
* Return {@link IFile} collection representing vdb instances in the given resource's project that contains a
* version of the given resource.
*
* If the method is called outside of the Eclipse runtime environment, or if the given resource is null,
* or the resource cannot be found on the file system then an empty collection will be returned.
*
* @param resource to search all vdb archive files for references to. If null or it not
* running in a Eclipse runtime environment, an empty collection will be returned.
* @return the {@link IFile} collection representing vdb archive files within the workspace
*/
public static Collection<IFile> getVdbResourcesThatContain( final IResource resource ) {
if (resource == null || !resource.exists() || getWorkspace() == null)
return Collections.emptyList();
final Collection result = new HashSet();
// Collect vdb resources from resource's project
final Collection<IFile> vdbResources = getProjectFileResources(resource.getProject(), VDB_RESOURCE_FILTER);
result.addAll(getVdbResourcesThatContain(resource, vdbResources));
return result;
}
private static boolean vdbContainsResource(File vdbFile, final IPath targetResourcePath) {
final Boolean[] status = new Boolean[1];
status[0] = false;
try {
ZipReaderCallback callback = new ZipReaderCallback() {
@Override
public void process(InputStream inputStream) throws Exception {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document xmlDocument = dBuilder.parse(inputStream);
NodeList modelList = xmlDocument.getElementsByTagName("model"); //$NON-NLS-1$
for (int i = 0; i < modelList.getLength(); ++i) {
Node modelNode = modelList.item(i);
if (modelNode.getNodeType() != Node.ELEMENT_NODE)
continue;
Element element = (Element)modelNode;
if (!element.hasAttribute("path")) //$NON-NLS-1$
continue;
String path = element.getAttribute("path"); //$NON-NLS-1$
if (path.equals(targetResourcePath.toOSString())) {
status[0] = true;
return;
}
}
}
};
ModelUtil.readVdbHeader(vdbFile, callback);
} catch (Exception ex) {
ModelerCore.Util.log(ex);
}
return status[0];
}
/**
* From the collection of workspace resources return the vdb archive resources that reference this IResource
*
* @param resource
* @param workspaceResources
* @return
* @since 4.3
*/
private static Collection getVdbResourcesThatContain( final IResource resource,
final Collection<IFile> workspaceResources ) {
Collection<IResource> result = Collections.emptyList();
if (resource == null || !resource.exists() || ModelUtil.isVdbArchiveFile(resource))
return result;
if (workspaceResources == null || workspaceResources.isEmpty())
return result;
// Check if any vdb archive resources in the workspace reference this resource ...
result = new ArrayList<IResource>();
// Match the full path of the specified resource to those referenced in the vdb manifest
for (IFile fileResource : workspaceResources) {
if (!ModelUtil.isVdbArchiveFile(fileResource))
continue;
File vdbFile = null;
try {
vdbFile = ModelUtil.getLocation(fileResource).toFile();
} catch (CoreException ex) {
ModelerCore.Util.log(ex);
}
if (vdbFile == null || ! vdbFile.exists())
continue;
if (vdbContainsResource(vdbFile, resource.getFullPath().makeAbsolute()))
result.add(fileResource);
}
return result;
}
/**
* Returns the workbench associated with this object.
*/
private static IWorkspace getWorkspace() {
return ModelerCore.getWorkspace();
}
/**
* Return the URI string defining the relative path within the workspace for the specified IResource.
*
* @param resource
* @return string representation of the resource URI
*/
public static String getWorkspaceUri( final IResource resource ) {
if (resource != null) return resource.getFullPath().toString();
return null;
}
/**
* Return the URI string defining the relative path within the workspace for the specified EMF resource. If the resource is one
* of the well-known Teiid Designer/EMF global resources such as
* <p>
* "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance" "http://www.w3.org/2001/XMLSchema"
* "http://www.w3.org/2001/MagicXMLSchema" "http://www.w3.org/2001/XMLSchema-instance"
* </p>
* then a logic URI is returned null since there is no IResource in the workspace that represents any one of those models.
*
* @param resource
* @return string representation of the resource URI
*/
public static String getWorkspaceUri( final Resource resource ) {
if (resource == null || resource.getURI() == null || getWorkspace() == null)
return null;
// If the resource is the Teiid Designer built-in datatypes model
// then return the specific logical URI for that model
final URI resourceUri = resource.getURI();
// if it is a global resource just return the uri
String resourceUriString = resourceUri.toString();
if (isGlobalResource(resourceUriString))
return getGlobalResourceUri(resourceUriString);
resourceUriString = normalizeUriToString(resourceUri);
if (isGlobalResource(resourceUriString))
return getGlobalResourceUri(resourceUriString);
// If the corresponding IResource can be found then
// return the relative path within the workspace
final IResource iResource = findIResource(resource);
if (iResource != null)
return iResource.getFullPath().toString();
// Try and compute the relative path for the Emf resource
// by checking its path against those of all known workspace
// projects. If the resource URI is prefixed by a known
// project location path then remove that path from the resource
// URI in order to create a relative path.
String path = resourceUriString;
try {
final IProject[] projects = getWorkspace().getRoot().getProjects();
for (final IProject project : projects) {
final IPath iPath = project.getLocation().removeLastSegments(1);
final String projectLocation = iPath.toString();
int beginIndex = path.indexOf(projectLocation);
if (beginIndex >= 0) {
beginIndex = beginIndex + projectLocation.length();
return path.substring(beginIndex);
}
}
} catch (final Exception e) {
path = resourceUriString;
}
// Try and compute the relative path from the Emf resource
// URI and the Platform installation location
path = resourceUriString;
final String osPath = resourceUri.toFileString();
if (osPath == null)
return null;
// Remove the path to the workspace from the resource path ...
final IPath wsPath = Platform.getLocation();
final String wsPathStr = wsPath.toOSString();
if (osPath.startsWith(wsPathStr))
path = osPath.substring(wsPathStr.length());
return path;
}
private static String getXsdTargetNamespace( final IResource iResource ) {
if (ModelUtil.isXsdFile(iResource)) {
final String location = iResource.getLocation().toOSString();
final File resourceFile = new File(location);
if (resourceFile.exists()) try {
final XsdHeader header = XsdHeaderReader.readHeader(resourceFile);
if (header != null) return header.getTargetNamespaceURI();
} catch (final TeiidDesignerException e) {
ModelerCore.Util.log(IStatus.ERROR, e, e.getMessage());
}
}
return null;
}
/**
* Returns true if the specified URI string is one of the well-known Teiid Designer/EMF identifiers to a global resource such as
* <p>
* "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance"
* "http://www.metamatrix.com/metamodels/UmlPrimitiveTypes-instance"
* "http://www.metamatrix.com/relationships/BuiltInRelationshipTypes-instance" "http://www.w3.org/2001/XMLSchema"
* "http://www.w3.org/2001/MagicXMLSchema" "http://www.w3.org/2001/XMLSchema-instance"
* </p>
* otherwise false is returned.
*
* @param uri the URI string
* @return true if the uri represents a global resource or false otherwise
*/
public static boolean isGlobalResource( final String uri ) {
if (uri == null) return false;
// http://www.w3.org/2001/xml.xsd
// "http://www.w3.org/2001/XMLSchema"; //$NON-NLS-1$
// "http://www.w3.org/2001/MagicXMLSchema"; //$NON-NLS-1$
// "http://www.w3.org/2001/XMLSchema-instance"; //$NON-NLS-1$
// If the URI is to the Teiid Designer built-in datatypes model ...
if (uri.startsWith(DatatypeConstants.BUILTIN_DATATYPES_URI)) return true;
if (uri.endsWith(DatatypeConstants.DATATYPES_MODEL_FILE_NAME)) return true;
// If the URI is to the Teiid Designer built-in UML primitive types model ...
if (uri.startsWith(UML_PRIMITIVE_TYPES_INTERNAL_URI)) return true;
if (uri.endsWith(UML_PRIMITIVE_TYPES_MODEL_FILE_NAME)) return true;
if (uri.startsWith(UML_METAMODEL_URI)) return true;
// If the URI is to the Teiid Designer built-in relationship model ...
if (uri.endsWith(RELATIONSHIP_PRIMITIVE_TYPES_INTERNAL_URI)) return true;
if (uri.endsWith(RELATIONSHIP_PRIMITIVE_TYPES_MODEL_FILE_NAME)) return true;
// If the URI is to one of the Emf XMLSchema resources ...
if (uri.startsWith(ModelerCore.XML_SCHEMA_INSTANCE_GENERAL_URI) || uri.startsWith(ModelerCore.XML_MAGIC_SCHEMA_GENERAL_URI)
|| uri.startsWith(ModelerCore.XML_SCHEMA_GENERAL_URI) || uri.startsWith(ModelerCore.XML_XSD_GENERAL_URI)) return true;
// If the URI is in the form of an Eclipse platform path to
// one of the Emf XMLSchema resources ...
if (uri.startsWith(XML_SCHEMA_ECLIPSE_PLATFORM_URI_PREFIX)) // MagicXMLSchema.xsd suffix on the resource URI
if (uri.indexOf(XML_MAGIC_SCHEMA_ECLIPSE_PLATFORM_URI_SUFFIX) > 0) return true;
else if (uri.indexOf(XML_SCHEMA_ECLIPSE_PLATFORM_URI_SUFFIX) > 0) return true;
else if (uri.indexOf(XML_SCHEMA_INSTANCE_ECLIPSE_PLATFORM_URI_SUFFIX) > 0) return true;
// Next check if the import reference is to one of our system models
try {
final Resource[] systemModels = ModelerCore.getSystemVdbResources();
for (int i = 0; i != systemModels.length; ++i) {
final String systemModelUri = URI.decode(systemModels[i].getURI().toString());
if (uri.equalsIgnoreCase(systemModelUri)) return true;
}
} catch (final Exception e) {
// do nothing
}
// Next check if the import reference is to one of our metamodels
try {
if (ModelerCore.getMetamodelRegistry().containsURI(uri)) return true;
} catch (final Exception e) {
// do nothing
}
// MyCode : 18565
if (isLocalResource(uri)) return false;
return false;
}
private static boolean isLocalResource( final String uri ) {
boolean found = false;
try {
final String uriName = URI.createURI(uri).lastSegment();
final Resource[] systemModels = ModelerCore.getModelContainer().getResourceFinder().findByName(uriName, false, false);
if ((systemModels != null) && (systemModels.length != 0)) {
for (int i = 0; i != systemModels.length; ++i) {
final URI resUri = systemModels[i].getURI();
if (resUri.lastSegment().equalsIgnoreCase(uriName)) found = true;
}
}
} catch (final Exception e) {
ModelerCore.Util.log(e);
}
return found;
}
/**
* Is the given workspace URI valid.
*
* @param workspaceUri
*
* @return true if valid, false otherwise
*/
public static boolean isValidWorkspaceUri( final String workspaceUri ) {
if (workspaceUri == null || workspaceUri.length() == 0 || getWorkspace() == null) return false;
// If the URI is to the Teiid Designer built-in datatypes resource or to one
// of the Emf XMLSchema resources then return null since there is no
// IResource in the workspace for any of these models
if (isGlobalResource(workspaceUri)) return false;
return true;
}
/**
* Normalise the given uri string reprentation
*
* @param uriString
*
* @return normalized uri string
*/
public static String normalizeUriString( final String uriString ) {
final String normalizedUriString = removeSchemeAndAuthority(uriString);
return normalizedUriString;
}
private static String normalizeUriToString( final URI uri ) {
final String uriString = new Path(URI.decode(uri.toString())).toString();
return normalizeUriString(uriString);
}
private static String removeSchemeAndAuthority( final String uri ) {
String normalizedUri = uri;
// EMF resource URIs are generally of the form
// scheme://authority/device/pathSegment1/pathSegment2...
// in which the scheme and/or authority may or may not exist
if (normalizedUri != null) {
// remove scheme from the URI string
if (normalizedUri.startsWith(SCHEME_FILE)) normalizedUri = normalizedUri.substring(SCHEME_FILE.length());
else if (normalizedUri.startsWith(SCHEME_PLATFORM)) {
normalizedUri = normalizedUri.substring(SCHEME_PLATFORM.length());
if (normalizedUri.startsWith(PLATFORM_RESOURCE_SEGMENT)) normalizedUri = normalizedUri.substring(PLATFORM_RESOURCE_SEGMENT.length());
}
// remove the authority
if (normalizedUri.startsWith(AUTHORITY_SEPARATOR)) {
normalizedUri = normalizedUri.substring(AUTHORITY_SEPARATOR.length());
final int beginIndex = normalizedUri.indexOf(SEGMENT_SEPARATOR);
if (beginIndex > -1) normalizedUri = normalizedUri.substring(beginIndex);
}
// remove the leading separator if it preceeds a device
if (normalizedUri.indexOf(DEVICE_IDENTIFIER) > 0 && normalizedUri.charAt(0) == SEGMENT_SEPARATOR) normalizedUri = normalizedUri.substring(1);
}
return normalizedUri;
}
/**
* Visitor that collects file resources conforming to an optional filter
*/
public static class FileResourceCollectorVisitor implements IResourceVisitor {
private final List resources;
protected ResourceFilter resourceFilter;
/**
* Create a new default instance with an 'accept everything filter'
*/
public FileResourceCollectorVisitor() {
this(ResourceFilter.ACCEPT_ALL);
}
/**
* Create a new instance with filter
*
* @param resourceFilter
*/
public FileResourceCollectorVisitor( final ResourceFilter resourceFilter ) {
this.resources = new ArrayList();
if (resourceFilter != null)
this.resourceFilter = resourceFilter;
else
this.resourceFilter = ResourceFilter.ACCEPT_ALL;
}
protected boolean addResource(final IResource resource) {
return resources.add(resource);
}
protected ResourceFilter getResourceFilter() {
return resourceFilter;
}
/**
* Get the found file resource collection
*
* @return collection of {@link IFile} resources
*/
public Collection<IFile> getFileResources() {
return Collections.unmodifiableCollection(resources);
}
@Override
public boolean visit( final IResource resource ) {
if (resource.exists() && resource.getType() == IResource.FILE && getResourceFilter().accept(resource))
addResource(resource);
return true;
}
}
/**
* Visits resources and returns those that match a particular name
*/
private static class FileNameResourceCollectorVisitor extends FileResourceCollectorVisitor {
private final String name;
private final boolean removeExtension;
/**
* Create new instance
*
* @param name
*/
public FileNameResourceCollectorVisitor(String name) {
this.name = name;
this.removeExtension = name.indexOf('.') == -1;
}
@Override
public boolean visit(IResource resource) {
/*
* Always needs to return true since the search will not recurse into
* projects and folders!
*
* However, we only add the resource if it matches the name.
*/
if (! resource.exists() || resource.getType() != IResource.FILE || ! getResourceFilter().accept(resource))
return true;
IPath path = resource.getFullPath();
// Do not process file names staring with '.' since these
// are considered reserved for Eclipse specific files
if (path.lastSegment().charAt(0) == '.')
return true;
if (removeExtension)
path = path.removeFileExtension();
if (name.equalsIgnoreCase(path.lastSegment()))
addResource(resource);
return true;
}
}
/**
* Visitor that collects vdb resources
*/
public static class VdbResourceCollectorVisitor extends FileResourceCollectorVisitor {
private final String optionalName;
/**
* Create a default instance which will simply find all vdb files
*/
public VdbResourceCollectorVisitor() {
this(null);
}
/**
* Create an instance which will find vdb files with the given name
*
* @param vdbName
*/
public VdbResourceCollectorVisitor(String vdbName) {
this.optionalName = vdbName;
this.resourceFilter = new VdbResourceFilter();
}
@Override
public boolean visit(IResource resource) {
/*
* Always needs to return true since the search will not recurse into
* projects and folders!
*
* However, we only add the resource if its a vdb, which is determined via the
* resource filter.
*/
if (! resource.exists() || resource.getType() != IResource.FILE || ! getResourceFilter().accept(resource))
return true;
if (optionalName == null) {// no optional name specified
addResource(resource);
}
else if (optionalName != null && optionalName.equalsIgnoreCase(resource.getFullPath().lastSegment())) {
// optional name specified
addResource(resource);
}
return true;
}
}
/**
* Filter to find the vdb resources
*/
private static class VdbResourceFilter implements ResourceFilter {
@Override
public boolean accept( final IResource res ) {
return ModelUtil.isVdbArchiveFile(res);
}
}
}