blob: 271961339231ac692ff51d6061b6d9b8effbbba5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.common.componentcore.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jem.util.UIContextDetermination;
import org.eclipse.jem.util.emf.workbench.ProjectUtilities;
import org.eclipse.wst.common.componentcore.IEditModelHandler;
import org.eclipse.wst.common.componentcore.ModuleCoreNature;
import org.eclipse.wst.common.componentcore.UnresolveableURIException;
import org.eclipse.wst.common.componentcore.internal.impl.ModuleURIUtil;
import org.eclipse.wst.common.componentcore.internal.impl.ResourceTreeNode;
import org.eclipse.wst.common.componentcore.internal.util.EclipseResourceAdapter;
import org.eclipse.wst.common.componentcore.resolvers.IReferenceResolver;
import org.eclipse.wst.common.componentcore.resolvers.ReferenceResolverUtil;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
import org.eclipse.wst.common.internal.emf.utilities.ExtendedEcoreUtil;
import org.eclipse.wst.common.internal.emfworkbench.edit.EMFWorkbenchEditContextFactory;
import org.eclipse.wst.common.internal.emfworkbench.validateedit.IValidateEditContext;
/**
* <p>
* Provides a Facade pattern for accessing the Web Tools Platform EMF Module Model. ModuleCore can
* be used as a static utility or an instance adapter.
* </p>
* <p>
* ModuleCore hides the management of accessing EditModels (
* {@see org.eclipse.wst.common.modulecore.ModuleStructuralModel}) correctly. Each project has
* exactly one ({@see org.eclipse.wst.common.modulecore.ModuleStructuralModel}) for read and
* exactly one for write. Each of these is shared among all clients and reference counted as
* necessary. Clients should use ModuleCore when working with the WTP Modules Structural Model.
* </p>
*
* <p>
* Each ModuleCore edit facade is designed to manage the EditModel lifecycle for clients. However,
* while each ModuleCore is designed to be passed around as needed, clients must enforce the
* ModuleCore lifecycle. The most common method of acquiring a ModuleCore edit facade is to use
* {@see #getModuleCoreForRead(IProject)}&nbsp;or {@see #getModuleCoreForWrite(IProject)}.
* </p>
* <p>
* When clients have concluded their use of their ModuleCore instance adapter , <b>clients must call
* {@see #dispose()}</b>.
* </p>
* <p>
* For more information about the underlying EditModel, see <a
* href="ModuleCoreNature.html#module-structural-model">the discussion of the ModuleStructuralModel
* </a>.
* <p>
* The following class is experimental until fully documented.
* </p>
*
* @see org.eclipse.wst.common.componentcore.ModuleCoreNature
* @see org.eclipse.wst.common.componentcore.internal.ModuleStructuralModel
*/
public class StructureEdit implements IEditModelHandler {
public static final Class ADAPTER_TYPE = StructureEdit.class;
public static String MODULE_META_FILE_NAME = ".settings/org.eclipse.wst.common.component"; //$NON-NLS-1$
private final static ComponentcoreFactory COMPONENT_FACTORY = ComponentcoreFactory.eINSTANCE;
private static final ComponentResource[] NO_RESOURCES = new ComponentResource[0];
private final ModuleStructuralModel structuralModel;
private final Map dependentCores = new HashMap();
private IProject aProject;
private boolean isStructuralModelSelfManaged;
private boolean isReadOnly;
private static final WorkbenchComponent[] NO_COMPONENTS = new WorkbenchComponent[0];
/**
*
* <p>
* Each ModuleCore edit facade is tied to a specific project. A project
* may have multiple ModuleCore edit facades live at any given time.
* </p>
* <p>
* Use to acquire a ModuleCore facade for a specific project that will not
* be used for editing. Invocations of any save*() API on an instance
* returned from This method will throw exceptions.
* </p>
*
* @param aProject
* The IProject that contains the WTP Modules model to load
* @return A ModuleCore edit facade to access the WTP Modules Model, null
* for non-flexible projects
*/
public static StructureEdit getStructureEditForRead(IProject aProject) {
ModuleCoreNature nature = ModuleCoreNature.getModuleCoreNature(aProject);
return nature != null ? new StructureEdit(nature, true) : null;
}
/**
*
* <p>
* Each ModuleCore edit facade is tied to a specific project. A project may have multiple
* ModuleCore edit facades live at any given time.
* </p>
* <p>
* Use to acquire a ModuleCore facade for a specific project that may be used to modify the
* model.
* </p>
*
* @param aProject
* The IProject that contains the WTP Modules model to load
* @return A ModuleCore edit facade to access the WTP Modules Model
*/
public static StructureEdit getStructureEditForWrite(IProject aProject) {
ModuleCoreNature nature = ModuleCoreNature.getModuleCoreNature(aProject);
return nature != null ? new StructureEdit(nature, false) : null;
}
/**
* <p>
* A convenience API to fetch the {@see ModuleCoreNature}&nbsp;for a particular module URI. The
* module URI must be of the valid form, or an exception will be thrown. The module URI must be
* contained by a project that has a {@see ModuleCoreNature}&nbsp;or null will be returned.
* </p>
* <p>
* <b>This method may return null. </b>
* </p>
*
* @param aModuleURI
* A valid, fully-qualified module URI
* @return The ModuleCoreNature of the project associated with aModuleURI
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public static ModuleCoreNature getModuleCoreNature(URI aModuleURI) throws UnresolveableURIException {
IProject container = getContainingProject(aModuleURI);
if (container != null)
return ModuleCoreNature.getModuleCoreNature(container);
return null;
}
/**
* <p>
* For {@see WorkbenchComponent}s that are contained within a project, the containing project
* can be determined with the {@see WorkbenchComponent}'s fully-qualified module URI.
* </p>
* <p>
* The following method will return the the corresponding project for the supplied module URI,
* if it can be determined.
* </p>
* <p>
* The method will not return an inaccessible project.
* </p>
* <p>
* <b>This method may return null. </b>
* </p>
*
* @param aModuleURI
* A valid, fully-qualified module URI
* @return The project that contains the module referenced by the module URI
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public static IProject getContainingProject(WorkbenchComponent aComponent) {
IProject project = ProjectUtilities.getProject(aComponent);
if (project != null && project.isAccessible())
return project;
return null;
}
/**
* <p>
* For {@see WorkbenchComponent}s that are contained within a project, the containing project
* can be determined with the {@see WorkbenchComponent}'s fully-qualified module URI.
* </p>
* <p>
* The following method will return the corresponding project for the supplied module URI,
* if it can be determined.
* </p>
* <p>
* The method may return an inaccessible project.
* </p>
* <p>
* <b>This method may return null. </b>
* </p>
*
* @param aModuleURI
* A valid, fully-qualified module URI
* @param onlyAccessibleProjects
* True if the method should return only accessible projects.
* @return The project that contains the module referenced by the module URI
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public static IProject getContainingProject(URI aModuleURI, boolean onlyAccessibleProjects) throws UnresolveableURIException {
ModuleURIUtil.ensureValidFullyQualifiedModuleURI(aModuleURI);
String projectName = aModuleURI.segment(ModuleURIUtil.ModuleURI.PROJECT_NAME_INDX);
if (projectName == null || projectName.length() == 0)
throw new UnresolveableURIException(aModuleURI);
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
if (!onlyAccessibleProjects)
return project;
if (project.isAccessible())
return project;
return null;
}
/**
* <p>
* For {@see WorkbenchComponent}s that are contained within a project, the containing project
* can be determined with the {@see WorkbenchComponent}'s fully-qualified module URI.
* </p>
* <p>
* The following method will return the the corresponding project for the supplied module URI,
* if it can be determined.
* </p>
* <p>
* The method will not return an inaccessible project.
* </p>
* <p>
* <b>This method may return null. </b>
* </p>
*
* @param aModuleURI
* A valid, fully-qualified module URI
* @return The project that contains the module referenced by the module URI
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public static IProject getContainingProject(URI aModuleURI) throws UnresolveableURIException {
return getContainingProject(aModuleURI, true);
}
/**
* <p>
* Returns the corresponding Eclipse IResource, if it can be determined, for the given
* {@see ComponentResource}. The {@see ComponentResource#getSourcePath()} &nbsp;must return a
* valid resource path for This method to return a valid value. The returned value may be either
* an {@see org.eclipse.core.resources.IFile}&nbsp;or {@see org.eclipse.core.resources.IFolder}.
* A client may use the return value of {@see IResource#getType()}&nbsp;to determine what type
* of resource was returned. (@see IResource#FILE} or {@see IResource#FOLDER}).
* </p>
* <p>
* <b>This method may return null. </b>
* </p>
*
* @param aModuleResource
* A ComponentResource with a valid sourcePath
* @return The corresponding Eclipse IResource, if available.
*/
public static IResource getEclipseResource(ComponentResource aModuleResource) {
EclipseResourceAdapter eclipseResourceAdapter = (EclipseResourceAdapter) ExtendedEcoreUtil.getAdapter(aModuleResource,aModuleResource.eAdapters(), EclipseResourceAdapter.ADAPTER_TYPE);
if (eclipseResourceAdapter != null)
return eclipseResourceAdapter.getEclipseResource();
eclipseResourceAdapter = new EclipseResourceAdapter();
eclipseResourceAdapter.setTarget(aModuleResource);
aModuleResource.eAdapters().add(eclipseResourceAdapter);
return eclipseResourceAdapter.getEclipseResource();
}
/**
* <p>
* Parses the supplied URI for the deployed name name of the {@see WorkbenchComponent}&nbsp;referenced
* by the URI.
* </p>
*
* @param aFullyQualifiedModuleURI
* A valid, fully-qualified module URI
* @return The deployed name of the referenced {@see WorkbenchComponent}
* @throws UnresolveableURIException
* If the supplied URI is invalid or unresolveable
*/
public static String getDeployedName(URI aFullyQualifiedModuleURI) throws UnresolveableURIException {
return ModuleURIUtil.getDeployedName(aFullyQualifiedModuleURI);
}
//public static ComponentType getComponentType(IVirtualContainer aComponent) {
public static ComponentType getComponentType(IVirtualComponent aComponent) {
StructureEdit componentCore = null;
ComponentType componentType = null;
try {
componentCore = StructureEdit.getStructureEditForRead(aComponent.getProject());
WorkbenchComponent wbComponent = componentCore.getComponent();
componentType = wbComponent.getComponentType();
} finally {
if (componentCore != null)
componentCore.dispose();
}
return componentType;
}
public static IVirtualReference createVirtualReference(IVirtualComponent context, ReferencedComponent reference) {
IReferenceResolver resolver = ReferenceResolverUtil.getDefault().getResolver(context, reference);
return resolver.resolve(context, reference);
}
protected StructureEdit(ModuleCoreNature aNature, boolean toAccessAsReadOnly) {
// always get the write editmodel - one instance only
structuralModel = aNature.getModuleStructuralModelForWrite(this);
aProject = aNature.getProject();
isReadOnly = toAccessAsReadOnly;
isStructuralModelSelfManaged = true;
}
/**
* <p>
* The following constructor is used to manage an already loaded model. Clients should use the
* following line if they intend to use this constructor: <br>
* <br>
* <code>ModuleCore componentCore = (ModuleCore) aStructuralModel.getAdapter(ModuleCore.ADAPTER_TYPE)</code>.
* </p>
*
* @param aStructuralModel
* The edit model to be managed by this ModuleCore
*/
public StructureEdit(ModuleStructuralModel aStructuralModel) {
structuralModel = aStructuralModel;
aProject = aStructuralModel.getProject();
}
/**
* <p>
* Force a save of the underlying model. The following method should be used with care. Unless
* required, use {@see #saveIfNecessary(IProgressMonitor) instead.
* </p>
* {@inheritDoc}
*
* @see org.eclipse.wst.common.componentcore.IEditModelHandler#save()
* @throws IllegalStateException
* If the ModuleCore object was created as read-only
*/
public void save(IProgressMonitor aMonitor) {
if (isReadOnly)
throwAttemptedReadOnlyModification();
else if (validateEdit().isOK()) {
// Make sure we obtain workspace rule before saving
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
try {
//OK wait to get workspace root before refreshing
Job.getJobManager().beginRule(root, null);
synchronized (structuralModel) {
if (!structuralModel.isDisposed())
structuralModel.save(aMonitor, this);
}
} finally {
Job.getJobManager().endRule(root);
}
}
}
/**
* <p>
* Save the underlying model only if no other clients are currently using the model. If the
* model is not shared, it will be saved. If it is shared, the save will be deferred.
* </p>
* {@inheritDoc}
*
* @see org.eclipse.wst.common.componentcore.IEditModelHandler#saveIfNecessary()
* @throws IllegalStateException
* If the ModuleCore object was created as read-only
*/
public void saveIfNecessary(IProgressMonitor aMonitor) {
if (isReadOnly)
throwAttemptedReadOnlyModification();
else if (structuralModel.isDirty() && validateEdit().isOK()) {
if (!structuralModel.isDisposed())
structuralModel.saveIfNecessary(aMonitor, this);
}
}
/**
* <p>
* Clients must call the following method when they have finished using the model, even if the
* ModuleCore edit facade was created as read-only.
* </p>
* {@inheritDoc}
*
* @see org.eclipse.wst.common.componentcore.IEditModelHandler#dispose()
*/
public void dispose() {
if (isStructuralModelSelfManaged && structuralModel!=null) {
synchronized (structuralModel) {
if (!structuralModel.isDisposed())
structuralModel.releaseAccess(this);
}
}
if (dependentCores!=null && dependentCores.size() > 0) {
synchronized (dependentCores) {
for (Iterator cores = dependentCores.values().iterator(); cores.hasNext();) {
StructureEdit core = (StructureEdit) cores.next();
if (core != null)
core.dispose();
}
}
}
}
/**
* <p>
* Creates a default WTP Module Structural Metamodel file if necessary.
* </p>
*/
public void prepareProjectComponentsIfNecessary() {
synchronized (structuralModel) {
if (!structuralModel.isDisposed()) {
try {
structuralModel.prepareProjectModulesIfNecessary();
} catch (CoreException e) {
ModulecorePlugin.logError(e);
}
}
}
}
/**
* <p>
* When loaded for write, the current ModuleCore may return the root object, which can be used
* to add or remove {@see WorkbenchComponent}s. If a client needs to just read the existing
* {@see WorkbenchComponent}s, use {@see #getWorkbenchModules()}.
* </p>
* <p>
* Deadlock Warning: Calling this method requires two locks. First the component file's file lock
* is required and then the EMFWorkbenchEditContextFactory's projectILock is required. If another
* thread acquires these same two locks in the opposite order, deadlock could occur.
* </p>
*
* @return The root object of the underlying model
*/
public ProjectComponents getComponentModelRoot() {
IFile file = structuralModel.getComponentFile();
if (file == null) return null;
ProjectComponents comps = null;
ILock lock = EMFWorkbenchEditContextFactory.getProjectLockObject(structuralModel.getProject());
try{
if(null != lock){
lock.acquire();
}
synchronized(structuralModel){
if (!structuralModel.isDisposed())
comps = (ProjectComponents) structuralModel.getPrimaryRootObject();
}
} finally{
if(null != lock){
lock.release();
}
}
return comps;
}
/**
* <p>
* Return the an array of ComponentResource which basically represent the source containers of a
* WorkbenchResource.
* <p>
*
* @param component
* @return
*/
public ComponentResource[] getSourceContainers(WorkbenchComponent component) {
// TODO Api in progress: Need to return the Java Source containers of the project
// TODO MDE: I don't know if I agree with the placement of this method.
return null;
}
/**
* <p>
* Clients that wish to modify the individual {@see WorkbenchComponent}&nbsp;instances may use
* this method. If clients need to add or remove {@see WorkbenchComponent}&nbsp;instances, use
* {@see #getProjectModules()}&nbsp;to get the root object and then access the contained
* {@see WorkbenchComponent}s through {@see ProjectComponents#getWorkbenchModules()}.
*
* @return The WorkbenchModules of the underlying model, if any.
*/
public WorkbenchComponent[] getWorkbenchModules() {
ProjectComponents pc = getComponentModelRoot();
if(pc != null) {
List wbModules = pc.getComponents();
return (WorkbenchComponent[]) wbModules.toArray(new WorkbenchComponent[wbModules.size()]);
}
return NO_COMPONENTS;
}
/**
* <p>
* Create a {@see WorkbenchComponent}&nbsp;with the given deployed name. The returned module
* will be contained by the root object of the current ModuleCore (so no need to re-add it to
* the Module Module root object). The current ModuleCore must not be read-only to invoke This
* method.
* </p>
*
* @param aDeployName
* A non-null String that will be assigned as the deployed-name
* @return A {@see WorkbenchComponent}associated with the current ModuleCore with the supplied
* deployed name
* @throws IllegalStateException
* If the current ModuleCore was created as read-only
*/
public WorkbenchComponent createWorkbenchModule(String aDeployName) {
if (isReadOnly)
throwAttemptedReadOnlyModification();
WorkbenchComponent module = COMPONENT_FACTORY.createWorkbenchComponent();
module.setName(aDeployName);
getComponentModelRoot().getComponents().add(module);
return module;
}
/**
* <p>
* Create a {@see ComponentResource}&nbsp;with the sourcePath of aResource. The current
* ModuleCore must not be read-only to invoke This method.
* </p>
*
* @param aModule
* A non-null {@see WorkbenchComponent}to contain the created
* {@see ComponentResource}
* @param aResource
* A non-null IResource that will be used to set the sourcePath
* @return A {@see ComponentResource}associated with the current ModuleCore with its sourcePath
* equivalent to aResource
* @throws IllegalStateException
* If the current ModuleCore was created as read-only
*/
public ComponentResource createWorkbenchModuleResource(IResource aResource) {
if (isReadOnly)
throwAttemptedReadOnlyModification();
ComponentResource moduleResource = COMPONENT_FACTORY.createComponentResource();
moduleResource.setSourcePath(aResource.getProjectRelativePath().makeAbsolute());
return moduleResource;
}
/**
* <p>
* Create a {@see ComponentType}&nbsp;with the sourcePath of aResource. The returned resource
* will be associated with the current ModuleCore. The current ModuleCore must not be read-only
* to invoke This method.
* </p>
*
* @param aResource
* A non-null IResource that will be used to set the sourcePath
* @return A {@see ComponentResource}associated with the current ModuleCore with its sourcePath
* equivalent to aResource
* @throws IllegalStateException
* If the current ModuleCore was created as read-only
*/
public ComponentType createModuleType(String aModuleTypeId) {
if (isReadOnly)
throwAttemptedReadOnlyModification();
ComponentType moduleType = COMPONENT_FACTORY.createComponentType();
moduleType.setComponentTypeId(aModuleTypeId);
return moduleType;
}
/**
* <p>
* Search the given module (indicated by aModuleURI) for the {@see ComponentResource}s
* identified by the module-relative path (indicated by aDeployedResourcePath).
* </p>
* @deprecated To be removed at next Integration Build 04/14/05 MDE. No substitute. (No clients).
*
* @param aModuleURI
* A valid, fully-qualified module URI
* @param aDeployedResourcePath
* A module-relative path to a deployed file
* @return An array of WorkbenchModuleResources that contain the URI specified by the
* module-relative aDeployedResourcePath
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public ComponentResource[] findResourcesByRuntimePath(URI aModuleURI, URI aDeployedResourcePath) throws UnresolveableURIException {
WorkbenchComponent module = getComponent();
return module.findResourcesByRuntimePath(new Path(aDeployedResourcePath.path()));
}
/**
* <p>
* Search the the module (indicated by the root of aModuleResourcePath) for the
* {@see ComponentResource}s identified by the module-qualified path (indicated by
* aDeployedResourcePath).
* </p>
* @deprecated To be removed at next Integration Build 04/14/05 MDE Use IPath Signature instead.
*
* @param aModuleResourcePath
* A valid fully-qualified URI of a deployed resource within a specific
* WorkbenchComponent
* @return An array of WorkbenchModuleResources that contain the URI specified by
* aModuleResourcePath
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public ComponentResource[] findResourcesByRuntimePath(URI aModuleResourcePath) throws UnresolveableURIException {
URI deployedURI = ModuleURIUtil.trimToDeployPathSegment(aModuleResourcePath);
IPath deployedPath = new Path(deployedURI.path());
return findResourcesByRuntimePath(ModuleURIUtil.getDeployedName(aModuleResourcePath), deployedPath);
}
/**
* <p>
* Search the the module (indicated by the root of aModuleResourcePath) for the
* {@see ComponentResource}s identified by the module-qualified path (indicated by
* aDeployedResourcePath).
* </p>
*
* @param aModuleResourcePath
* A valid fully-qualified URI of a deployed resource within a specific
* WorkbenchComponent
* @return An array of WorkbenchModuleResources that contain the URI specified by
* aModuleResourcePath
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public ComponentResource[] findResourcesByRuntimePath(String aModuleName, IPath aModuleResourcePath) {
WorkbenchComponent module = getComponent();
return module.findResourcesByRuntimePath(aModuleResourcePath);
}
public ComponentResource[] findResourcesBySourcePath(URI aWorkspaceRelativePath) throws UnresolveableURIException {
return findResourcesBySourcePath(aWorkspaceRelativePath,ResourceTreeNode.CREATE_NONE);
}
/**
* <p>
* Locates the {@see ComponentResource}s that contain the supplied resource in their source
* path. There are no representations about the containment of the {@see ComponentResource}s
* which are returned. The only guarantee is that the returned elements are contained within the
* same project.
* </p>
* <p>
* The sourcePath of each {@see ComponentResource}&nbsp;will be mapped to either an IFile or an
* IFolder. As a result, if the {@see ComponentResource}&nbsp;is a container mapping, the path
* of the supplied resource may not be identical the sourcePath of the {@see ComponentResource}.
* </p>
* @deprecated To be removed at next Integration Build 04/14/05 MDE Use IPath Signature instead.
*
* @param aWorkspaceRelativePath
* A valid fully-qualified workspace-relative path of a given resource
* @return An array of WorkbenchModuleResources which have sourcePaths that contain the given
* resource
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public ComponentResource[] findResourcesBySourcePath(URI aWorkspaceRelativePath, int resourceFlag) throws UnresolveableURIException {
return findResourcesBySourcePath(new Path(aWorkspaceRelativePath.path()),resourceFlag);
}
public ComponentResource[] findResourcesBySourcePath(IPath aProjectRelativePath) throws UnresolveableURIException {
return findResourcesBySourcePath(aProjectRelativePath,ResourceTreeNode.CREATE_NONE);
}
/**
* <p>
* Locates the {@see WorkbenchComponent}s that contains the resource with the given source
* path. There are no representations about the containment of the {@see ComponentResource}s
* which are returned. The only guarantee is that the returned elements are contained within the
* same project.
* </p>
* <p>
* The sourcePath of each {@see ComponentResource}&nbsp;will be mapped to either an IFile or an
* IFolder. As a result, if the {@see ComponentResource}&nbsp;is a container mapping, the path
* of the supplied resource may not be identical the sourcePath of the {@see ComponentResource}.
* </p>
*
* @param aProjectRelativePath
* A valid project-relative path of a given resource
* resourceFlag
* A bit flag that determines if Resources should be created during the search
* CREATE_NONE
* CREATE_RESOURCE_ALWAYS
* CREATE_TREENODE_IFNEC
* @return An array of WorkbenchModuleResources which have sourcePaths that contain the given
* resource
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public WorkbenchComponent findComponent(IPath aProjectRelativeResourcePath, int resourceFlag) throws UnresolveableURIException {
ProjectComponents projectModules = getComponentModelRoot();
if (projectModules == null) return null;
EList modules = projectModules.getComponents();
WorkbenchComponent module = null;
boolean resourceExists = false;
for (int i = 0; i < modules.size(); i++) {
module = (WorkbenchComponent) modules.get(i);
resourceExists = module.exists(aProjectRelativeResourcePath,resourceFlag);
if (!resourceExists && aProjectRelativeResourcePath.segments().length > 1) {
resourceExists = module.exists(aProjectRelativeResourcePath.removeFirstSegments(1),resourceFlag);
}
if (resourceExists)
return module;
}
return null;
}
/**
* <p>
* Locates the {@see ComponentResource}s that contain the supplied resource in their source
* path. There are no representations about the containment of the {@see ComponentResource}s
* which are returned. The only guarantee is that the returned elements are contained within the
* same project.
* </p>
* <p>
* The sourcePath of each {@see ComponentResource}&nbsp;will be mapped to either an IFile or an
* IFolder. As a result, if the {@see ComponentResource}&nbsp;is a container mapping, the path
* of the supplied resource may not be identical the sourcePath of the {@see ComponentResource}.
* </p>
*
* @param aProjectRelativePath
* A valid project-relative path of a given resource
* resourceFlag
* A bit flag that determines if Resources should be created during the search
* CREATE_NONE
* CREATE_RESOURCE_ALWAYS
* CREATE_TREENODE_IFNEC
* @return An array of WorkbenchModuleResources which have sourcePaths that contain the given
* resource
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
public ComponentResource[] findResourcesBySourcePath(IPath aProjectRelativePath, int resourceFlag) throws UnresolveableURIException {
ProjectComponents projectModules = getComponentModelRoot();
if (projectModules==null)
return NO_RESOURCES;
EList modules = projectModules.getComponents();
WorkbenchComponent module = null;
ComponentResource[] resources = null;
List foundResources = new ArrayList();
for (int i = 0; i < modules.size(); i++) {
module = (WorkbenchComponent) modules.get(i);
resources = module.findResourcesBySourcePath(aProjectRelativePath,resourceFlag);
if (resources != null && resources.length != 0)
foundResources.addAll(Arrays.asList(resources));
else if (aProjectRelativePath.segments().length > 1) {
resources = module.findResourcesBySourcePath(aProjectRelativePath.removeFirstSegments(1),resourceFlag);
if (resources != null && resources.length != 0)
foundResources.addAll(Arrays.asList(resources));
}
}
if (foundResources.size() > 0)
return (ComponentResource[]) foundResources.toArray(new ComponentResource[foundResources.size()]);
return NO_RESOURCES;
}
/**
* <p>
* Returns the {@see WorkbenchComponent}&nbsp;contained by the current ModuleCore with the
* deploy name aModuleName.
* </p>
* <p>
* <b>This method may return null. </b>
* </p>
*
* @param aModuleName
* @return The {@see WorkbenchComponent}contained by the current ModuleCore with the deploy
* name aModuleName
* @see WorkbenchComponent#getDeployedName()
* @deprecated - Use getComponent() - Only one component per project
*/
public WorkbenchComponent findComponentByName(String aModuleName) {
return getComponentModelRoot() != null ? getComponentModelRoot().findWorkbenchModule(aModuleName) : null;
}
/**
* <p>
* Locate and return the {@see WorkbenchComponent}&nbsp;referenced by the fully-qualified
* aModuleURI. The method will work correctly even if the requested {@see WorkbenchComponent}
* &nbsp;is contained by another project.
* </p>
*
* @param aModuleURI
* A valid, fully-qualified module URI
* @return The {@see WorkbenchComponent}referenced by aModuleURI
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
* @see WorkbenchComponent#getHandle()
*/
public WorkbenchComponent findComponentByURI(URI aModuleURI) throws UnresolveableURIException {
if (aModuleURI == null)
return null;
if(aModuleURI.scheme() == null && aModuleURI.segmentCount() == 1)
return getComponent();
ModuleURIUtil.ensureValidFullyQualifiedModuleURI(aModuleURI);
String projectName = aModuleURI.segment(ModuleURIUtil.ModuleURI.PROJECT_NAME_INDX);
/* Accessing a local module */
if (getProject()!=null && getProject().getName().equals(projectName))
return getComponent();
StructureEdit dependentCore = getDependentModuleCore(aModuleURI);
if (dependentCore != null)
return dependentCore.getComponent();
return null;
}
/**
* <p>
* Searches the available {@see WorkbenchComponent}s as available through
* {@see #getWorkbenchModules()}&nbsp;for {@see WorkbenchComponent}s that have a
* {@see WorkbenchComponent#getModuleType()}with a a module type Id as specified by
* aModuleTypeId.
* </p>
*
* @param aModuleTypeId
* A non-null module type id ({@see ComponentType#getModuleTypeId()})
* @return A non-null array of the {@see WorkbenchComponent}s that match the given module type
* id
*/
// public WorkbenchComponent[] findComponentsByType(String aModuleTypeId) {
// WorkbenchComponent[] availableModules = getWorkbenchModules();
// ComponentType moduleType;
// List results = new ArrayList();
// for (int i = 0; i < availableModules.length; i++) {
// moduleType = availableModules[i].getComponentType();
// if (moduleType != null && aModuleTypeId.equals(moduleType.getComponentTypeId()))
// results.add(availableModules[i]);
// }
// if (results.size() == 0)
// return NO_MODULES;
// return (WorkbenchComponent[]) results.toArray(new WorkbenchComponent[results.size()]);
// }
/**
* Find and return the ReferencedComponent that represents the depedency from aComponent to aReferencedComponent.
* <p>This method could return null.</p>
* @param aComponent
* @param aReferencedComponent
* @return
*/
public ReferencedComponent findReferencedComponent(WorkbenchComponent aComponent, WorkbenchComponent aReferencedComponent) {
if(aComponent == null || aReferencedComponent == null)
return null;
IProject referencedProject = getContainingProject(aReferencedComponent);
EList referencedComponents = aComponent.getReferencedComponents();
String dependentProjectName = null;
for (Iterator iter = referencedComponents.iterator(); iter.hasNext();) {
ReferencedComponent referencedComponent = (ReferencedComponent) iter.next();
dependentProjectName = referencedComponent.getHandle().segment(ModuleURIUtil.ModuleURI.PROJECT_NAME_INDX);
if(referencedProject.getName().equals(dependentProjectName))
return referencedComponent;
}
return null;
}
/**
* <p>
* Returns true if the {@see ReferencedComponent}&nbsp;references a {@see WorkbenchComponent}(
* {@see ReferencedComponent#getHandle()}) which is contained by the project that the current
* ModuleCore is managing. The following method will determine if the dependency can be
* satisfied by the current project.
* </p>
*
* @param aDependentModule
* @return True if the {@see ReferencedComponent}references a {@see WorkbenchComponent}managed
* directly by the current ModuleCore
*/
public boolean isLocalDependency(ReferencedComponent aDependentModule) {
if (aDependentModule == null || aDependentModule.getHandle()==null)
return false;
URI dependentHandle = aDependentModule.getHandle();
// with no scheme and a simple name, the referenced component must be local
if(dependentHandle.scheme() == null && dependentHandle.segmentCount() == 1)
return true;
try {
String localProjectName = getProject().getName();
if(ModuleURIUtil.ensureValidFullyQualifiedModuleURI(dependentHandle, false)) {
String dependentProjectName = aDependentModule.getHandle().segment(ModuleURIUtil.ModuleURI.PROJECT_NAME_INDX);
return localProjectName.equals(dependentProjectName);
}
} catch (UnresolveableURIException e) {
// Ignore
}
return false;
}
/**
* @param aModuleURI
* A valid, fully-qualified module URI
* @return The ModuleCore facade for the supplied URI
* @throws UnresolveableURIException
* If the supplied module URI is invalid or unresolveable.
*/
private StructureEdit getDependentModuleCore(URI aModuleURI) throws UnresolveableURIException {
StructureEdit dependentCore = (StructureEdit) dependentCores.get(aModuleURI);
if (dependentCore != null)
return dependentCore;
synchronized (dependentCores) {
dependentCore = (StructureEdit) dependentCores.get(aModuleURI);
if (dependentCore == null) {
IProject container = getContainingProject(aModuleURI);
if (container != null) {
dependentCore = getStructureEditForRead(container);
dependentCores.put(aModuleURI, dependentCore);
} else
throw new UnresolveableURIException(aModuleURI);
}
}
return dependentCore;
}
private void throwAttemptedReadOnlyModification() {
throw new IllegalStateException("Attempt to modify a ModuleCore edit facade that was loaded as read-only.");
}
/**
* temporary method to return first module in the project
*
* @return first module in the project
* @deprecated
*/
public WorkbenchComponent getFirstModule() {
return getComponent();
}
/**
* returns the one and only component in the project
*
* @return the component in the project if exists or null
*
*/
public WorkbenchComponent getComponent() {
WorkbenchComponent[] comps = getWorkbenchModules();
if (comps.length > 0)
return comps[0];
return null;
}
public static URI createComponentURI(IProject aContainingProject, String aComponentName) {
return ModuleURIUtil.fullyQualifyURI(aContainingProject, aComponentName);
}
protected IProject getProject() {
return aProject;
}
public ModuleStructuralModel getModuleStructuralModel() {
return structuralModel;
}
/**
* Validate edit for resource state
*/
protected IStatus validateEdit() {
IValidateEditContext validator = (IValidateEditContext) UIContextDetermination.createInstance(IValidateEditContext.CLASS_KEY);
return validator.validateState(getModuleStructuralModel());
}
}