| /******************************************************************************* |
| * Copyright (c) 2003, 2007 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.impl; |
| |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.ISafeRunnable; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.core.runtime.content.IContentDescription; |
| import org.eclipse.core.runtime.content.IContentType; |
| import org.eclipse.core.runtime.jobs.ILock; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.Resource.Factory; |
| import org.eclipse.jem.util.RegistryReader; |
| import org.eclipse.wst.common.componentcore.ComponentCore; |
| import org.eclipse.wst.common.componentcore.UnresolveableURIException; |
| import org.eclipse.wst.common.componentcore.internal.ModulecorePlugin; |
| import org.eclipse.wst.common.componentcore.internal.StructureEdit; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualFile; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualFolder; |
| import org.eclipse.wst.common.internal.emf.resource.FileNameResourceFactoryRegistry; |
| import org.eclipse.wst.common.internal.emf.resource.ResourceFactoryDescriptor; |
| import org.eclipse.wst.common.internal.emf.utilities.DefaultOverridableResourceFactoryRegistry; |
| import org.eclipse.wst.common.internal.emfworkbench.WorkbenchResourceHelper; |
| import org.eclipse.wst.common.internal.emfworkbench.edit.EMFWorkbenchEditContextFactory; |
| |
| /** |
| * <p> |
| * The following class is experimental until fully documented. |
| * </p> |
| */ |
| public class WTPResourceFactoryRegistry extends FileNameResourceFactoryRegistry { |
| |
| public static final WTPResourceFactoryRegistry INSTANCE = new WTPResourceFactoryRegistry(); |
| |
| private final static boolean LOG_WARNINGS = false; |
| |
| |
| private WTPResourceFactoryRegistry() { |
| new ResourceFactoryRegistryReader().readRegistry(); |
| } |
| |
| public Resource.Factory delegatedGetFactory(URI uri) { |
| if (WTPResourceFactoryRegistry.INSTANCE == this) |
| return super.delegatedGetFactory(uri); |
| return WTPResourceFactoryRegistry.INSTANCE.getFactory(uri); |
| } |
| |
| public Resource.Factory getFactory(URI uri, IContentDescription description) { |
| IProject componentProject = null; |
| try { |
| componentProject = StructureEdit.getContainingProject(uri); |
| } catch (UnresolveableURIException e) { |
| // don't do anything |
| } |
| ILock lock = EMFWorkbenchEditContextFactory.getProjectLockObject(componentProject); |
| try{ |
| if(null != lock){ |
| lock.acquire(); |
| } |
| synchronized(this){ |
| Resource.Factory resourceFactory = null; |
| if(uri != null && uri.lastSegment() != null) { |
| ResourceFactoryDescriptor descriptor = null; |
| if(null == description){ |
| descriptor = getDescriptor(uri); |
| } else { |
| descriptor = getDescriptor(uri, description); |
| } |
| |
| if(descriptor != null) { |
| resourceFactory = getFactory(descriptor); |
| } |
| } |
| if(resourceFactory == null) |
| resourceFactory = super.getFactory(uri); |
| return resourceFactory; |
| } |
| } finally{ |
| if(null != lock){ |
| lock.release(); |
| } |
| } |
| } |
| |
| public Resource.Factory getFactory(URI uri) { |
| return getFactory(uri, (IContentDescription)null); |
| } |
| |
| |
| /** |
| * Register a file name representing the last segment of a URI with the corresponding |
| * Resource.Factory. |
| */ |
| public synchronized void registerLastFileSegment(String aSimpleFileName, Resource.Factory aFactory) { |
| |
| if(LOG_WARNINGS) { |
| /* the third entry in the array is this stack frame, we walk back from there. */ |
| StackTraceElement[] stackTrace = (new Exception()).getStackTrace(); |
| if(stackTrace.length > 4) { |
| StringBuffer warningMessage = new StringBuffer("WTPResourceFactoryRegistry.registerLastFileSegment() was called explicitly from " + stackTrace[3]); |
| warningMessage.append("\nThis happened around: \n"); |
| for (int i = 4; (i < stackTrace.length) && i < 8; i++) { |
| warningMessage.append("\tnear ").append(stackTrace[i]).append('\n'); |
| } |
| warningMessage.append(".\nClients should use the org.eclipse.wst.common.modulecore.resourceFactories extension point instead."); |
| ModulecorePlugin.log(IStatus.INFO, 0, warningMessage.toString(), null); |
| } |
| } |
| |
| super.registerLastFileSegment(aSimpleFileName, aFactory); |
| |
| } |
| private WTPResourceFactoryRegistryKey getKey(ResourceFactoryDescriptor descriptor) { |
| WTPResourceFactoryRegistryKey key = new WTPResourceFactoryRegistryKey(); |
| key.shortName = descriptor.getShortSegment(); |
| key.type = descriptor.getContentType(); |
| key.isDefault = descriptor.isDefault(); |
| if(descriptor instanceof ConfigurationResourceFactoryDescriptor){ |
| ConfigurationResourceFactoryDescriptor configurationDescriptor = (ConfigurationResourceFactoryDescriptor)descriptor; |
| key.factoryClassName = configurationDescriptor.getFactoryClassName(); |
| key.overridesFactoryClassName = configurationDescriptor.getOverridesFactoryClassName(); |
| } |
| return key; |
| } |
| |
| /** |
| * Declares a subclass to create Resource.Factory(ies) from an extension. |
| */ |
| private class ConfigurationResourceFactoryDescriptor extends ResourceFactoryDescriptor implements IResourceFactoryExtPtConstants { |
| |
| private String shortSegment; |
| private IContentType contentType; |
| private boolean isDefault = true; |
| private String factoryClassName = null; |
| private String overridesFactoryClassName = null; |
| private final IConfigurationElement element; |
| |
| public ConfigurationResourceFactoryDescriptor(IConfigurationElement ext) throws CoreException { |
| Assert.isNotNull(ext); |
| element = ext; |
| init(); |
| } |
| |
| public String getOverridesFactoryClassName() { |
| return overridesFactoryClassName; |
| } |
| |
| public String getFactoryClassName() { |
| return factoryClassName; |
| } |
| |
| private void init() throws CoreException { |
| shortSegment = element.getAttribute(ATT_SHORT_SEGMENT); |
| |
| IConfigurationElement[] bindings = element.getChildren(TAG_CONTENTTYPE); |
| if (bindings.length > 0) { |
| String contentTypeId = null; |
| contentTypeId = bindings[0].getAttribute(ATT_CONTENTTYPEID); |
| if (contentTypeId != null) |
| contentType = Platform.getContentTypeManager().getContentType(contentTypeId); |
| } |
| |
| if ((shortSegment == null || shortSegment.trim().length() == 0) |
| && contentType == null) { |
| throw new CoreException( |
| ModulecorePlugin.createErrorStatus(0, |
| "Either the shortSegment attribute or the contentType element of " //$NON-NLS-1$ |
| + TAG_RESOURCE_FACTORY |
| + " must be specified in " |
| + element.getNamespaceIdentifier() |
| + ". The shortSegment attribute is specified with a valid, non-null, " //$NON-NLS-1$ |
| + "non-empty value, and the contentType element is specified with a " //$NON-NLS-1$ |
| + "valid, non-null, non-empty contentTypeId." //$NON-NLS-1$ |
| , null)); |
| } |
| |
| if ("false".equals(element.getAttribute(ATT_ISDEFAULT))) |
| isDefault = false; |
| |
| factoryClassName = element.getAttribute(ATT_CLASS); |
| overridesFactoryClassName = element.getAttribute(ATT_OVERRIDES_FACTORY); |
| } |
| |
| public boolean isEnabledFor(URI fileURI) { |
| // Not sure where this is actually used, so not sure what the proper |
| // implementation should be, so simply checking the short segment for now |
| if (fileURI != null && fileURI.lastSegment() != null && shortSegment != null) { |
| return shortSegment.equals(fileURI.lastSegment()); |
| } |
| return false; |
| } |
| |
| public Resource.Factory createFactory() { |
| |
| final Resource.Factory[] factory = new Resource.Factory[1]; |
| |
| SafeRunner.run(new ISafeRunnable() { |
| |
| public void run() throws Exception { |
| factory[0] = (Resource.Factory) element.createExecutableExtension(ATT_CLASS); |
| } |
| |
| public void handleException(Throwable exception) { |
| ModulecorePlugin.log(ModulecorePlugin.createErrorStatus(0, exception.getMessage(), exception)); |
| } |
| }); |
| |
| return factory[0] != null ? factory[0] : DefaultOverridableResourceFactoryRegistry.GLOBAL_FACTORY; |
| |
| } |
| |
| public String getShortSegment() { |
| return shortSegment; |
| } |
| |
| public IContentType getContentType() { |
| return contentType; |
| } |
| |
| public boolean isDefault() { |
| return isDefault; |
| } |
| |
| public int hashCode() { |
| int hashCode = 0; |
| if (getContentType() != null) { |
| hashCode |= getContentType().hashCode(); |
| } |
| if (getShortSegment() != null) { |
| hashCode |= getShortSegment().hashCode(); |
| } |
| return hashCode; |
| } |
| |
| public boolean equals(Object o) { |
| if (! (o instanceof ResourceFactoryDescriptor)) { |
| return false; |
| } |
| ResourceFactoryDescriptor rfdo = (ResourceFactoryDescriptor) o; |
| boolean equals = true; |
| equals &= (getContentType() == null) ? rfdo.getContentType() == null : |
| getContentType().equals(rfdo.getContentType()); |
| equals &= (getShortSegment() == null) ? rfdo.getShortSegment() == null : |
| getShortSegment().equals(rfdo.getShortSegment()); |
| return equals; |
| } |
| } |
| |
| |
| private class ResourceFactoryRegistryReader extends RegistryReader implements IResourceFactoryExtPtConstants { |
| |
| public ResourceFactoryRegistryReader() { |
| super(ModulecorePlugin.PLUGIN_ID, EXTPT_RESOURCE_FACTORIES); |
| } |
| |
| public boolean readElement(final IConfigurationElement element) { |
| |
| if(element != null && TAG_RESOURCE_FACTORY.equals(element.getName())) { |
| final boolean[] success = new boolean[] { true }; |
| SafeRunner.run(new ISafeRunnable() { |
| |
| public void run() throws Exception { |
| addDescriptor(new ConfigurationResourceFactoryDescriptor(element)); |
| } |
| |
| public void handleException(Throwable exception) { |
| ModulecorePlugin.log(ModulecorePlugin.createErrorStatus(0, exception.getMessage(), exception)); |
| success[0] = false; |
| } |
| }); |
| return success[0]; |
| } else { |
| return false; |
| } |
| } |
| } |
| private class WTPResourceFactoryRegistryKey { |
| |
| public String overridesFactoryClassName; |
| public String factoryClassName; |
| public String shortName; |
| public IContentType type; |
| public boolean isDefault = true; |
| public WTPResourceFactoryRegistryKey() { |
| super(); |
| } |
| |
| /** |
| * Sort in the following manner: |
| * First, sort by shortName, if shortName is null, then it comes last |
| * If shortNames are equal, then sort by isDefault |
| * If isDefault is also equal, then the one defining a factoryClassName wins |
| * If both have factoryClassNames, then check to see if one overrides the other via overridesFactoryClassName |
| * If neither override the other factory class, then sort by factoryClassname |
| * @param other |
| * @return |
| */ |
| public int compareTo(WTPResourceFactoryRegistryKey other){ |
| if(this == other){ |
| return 0; |
| } |
| if(shortName == null && other.shortName == null){ |
| return 0; |
| } else if(shortName == null){ |
| return 1; |
| } else if(other.shortName == null){ |
| return -1; |
| } |
| |
| int shortNameCompare = this.shortName.compareTo(other.shortName); |
| if(shortNameCompare != 0){ |
| return shortNameCompare; |
| } else { |
| if(this.isDefault != other.isDefault){ |
| if(this.isDefault){ |
| return -1; |
| } else { |
| return 1; |
| } |
| } else { |
| if(this.factoryClassName == null && other.factoryClassName == null){ |
| return 0; |
| } else if(other.factoryClassName == null){ |
| return -1; |
| } else if (this.factoryClassName == null){ |
| return 1; |
| } else if(other.factoryClassName.equals(this.overridesFactoryClassName)){ |
| return -1; |
| } else if(this.factoryClassName.equals(other.overridesFactoryClassName)){ |
| return 1; |
| } else { |
| return this.factoryClassName.compareTo(other.factoryClassName); |
| } |
| } |
| } |
| } |
| } |
| |
| protected void addDescriptor(ResourceFactoryDescriptor descriptor) { |
| getDescriptors().put(getKey(descriptor), descriptor); |
| } |
| |
| private WTPResourceFactoryRegistryKey [] sortedDescriptors = null; |
| |
| private WTPResourceFactoryRegistryKey [] getSortedDescriptorKeys() { |
| if(sortedDescriptors == null || sortedDescriptors.length != getDescriptors().size()){ |
| Set keys = getDescriptors().keySet(); |
| WTPResourceFactoryRegistryKey [] array = new WTPResourceFactoryRegistryKey [keys.size()]; |
| int count = 0; |
| for (Iterator iterator = keys.iterator(); iterator.hasNext();count++) { |
| WTPResourceFactoryRegistryKey key = (WTPResourceFactoryRegistryKey) iterator.next(); |
| array[count] = key; |
| } |
| Arrays.sort(array, new Comparator<WTPResourceFactoryRegistryKey>() { |
| public int compare(WTPResourceFactoryRegistryKey key1, |
| WTPResourceFactoryRegistryKey key2) { |
| return key1.compareTo(key2); |
| } |
| }); |
| sortedDescriptors = array; |
| } |
| return sortedDescriptors; |
| } |
| |
| protected synchronized ResourceFactoryDescriptor getDescriptor(URI uri, IContentDescription description) { |
| WTPResourceFactoryRegistryKey [] keys = getSortedDescriptorKeys(); |
| ResourceFactoryDescriptor defaultDescriptor = null; |
| |
| // first check content type |
| if (description != null) { |
| for (WTPResourceFactoryRegistryKey key : keys) { |
| ResourceFactoryDescriptor descriptor = (ResourceFactoryDescriptor) getDescriptors().get(key); |
| |
| if ((key.type != null) && (description.getContentType().equals(key.type))) { |
| if ((defaultDescriptor == null) || (key.isDefault)) { |
| defaultDescriptor = descriptor; |
| } |
| } |
| } |
| } |
| |
| // then check short name, overriding default if necessary |
| for (WTPResourceFactoryRegistryKey key : keys) { |
| ResourceFactoryDescriptor descriptor = (ResourceFactoryDescriptor) getDescriptors().get(key); |
| |
| if ((key.shortName != null) && (uri.lastSegment().equals(key.shortName))) { |
| if ((defaultDescriptor == null) |
| || ((description == null) && (key.isDefault))) { |
| defaultDescriptor = descriptor; |
| } |
| } |
| } |
| |
| return defaultDescriptor; |
| } |
| |
| private URI newPlatformURI(URI aNewURI, IProject project) { |
| |
| if (project == null) |
| return ModuleURIUtil.trimToDeployPathSegment(aNewURI); |
| try { |
| IVirtualComponent component = ComponentCore.createComponent(project); |
| |
| URI deployPathSegment = ModuleURIUtil.trimToDeployPathSegment(aNewURI); |
| |
| //IVirtualFile newFile = component.getFile(new Path(deployPathSegment.path())); |
| IVirtualFolder rootFolder = component.getRootFolder(); |
| IVirtualFile newFile = rootFolder.getFile(new Path(deployPathSegment.path())); |
| |
| return URI.createPlatformResourceURI(newFile.getWorkspaceRelativePath().toString()); |
| |
| } catch(Exception e) { |
| ModulecorePlugin.logError(e); |
| } |
| return null; |
| } |
| |
| private IContentDescription getDescriptionFromURI(URI uri) { |
| String contentTypeIdentifier = ModuleURIUtil.getContentTypeName(uri); |
| if (contentTypeIdentifier != null) |
| return Platform.getContentTypeManager().getContentType(contentTypeIdentifier).getDefaultDescription(); |
| else |
| return null; |
| |
| } |
| |
| protected synchronized ResourceFactoryDescriptor getDescriptor(URI uri) { |
| IFile file = WorkbenchResourceHelper.getPlatformFile(uri); |
| IContentDescription description = null; |
| if (file != null && file.exists()) { |
| try { |
| description = file.getContentDescription(); |
| } catch (CoreException e) { |
| ModulecorePlugin.logError(e); |
| } |
| } |
| if (description == null) {//Check for optional embedded uri segment, then normalize |
| description = getDescriptionFromURI(uri); |
| try { |
| if (description != null) { |
| IProject componentProject = null; |
| try { |
| componentProject = StructureEdit.getContainingProject(uri); |
| } catch (UnresolveableURIException e) { |
| ModulecorePlugin.logError(e); |
| } |
| uri = PlatformURLModuleConnection.resolve(uri); |
| uri = newPlatformURI(uri,componentProject); |
| } |
| } catch (IOException e) { |
| ModulecorePlugin.logError(e); |
| } |
| } |
| |
| ResourceFactoryDescriptor defaultDesc = getDescriptor(uri, description); |
| // Ok no content type match - go to super |
| if (defaultDesc != null){ |
| return defaultDesc; |
| } |
| else{ |
| return super.getDescriptor(uri); |
| } |
| } |
| |
| public Factory getFactory(URI uri, String contentType) { |
| IContentType type = Platform.getContentTypeManager().getContentType(contentType); |
| if (type != null) |
| return getFactory(uri, type.getDefaultDescription()); |
| return super.getFactory(uri, contentType); |
| } |
| |
| |
| /** |
| * Returns true if the uri is found in the WTPResourceFactoryRegistry descriptor. |
| * This will not load any extension points |
| */ |
| public synchronized boolean shortNameRegistered(URI uri) { |
| Map m = getDescriptors(); |
| Collection c = m.values(); |
| Iterator iter = c.iterator(); |
| String uriLastSegment = uri.lastSegment(); |
| while(iter.hasNext()) { |
| ResourceFactoryDescriptor descriptor = (ResourceFactoryDescriptor) iter.next(); |
| if(descriptor.getShortSegment() != null && descriptor.getShortSegment().equals(uriLastSegment)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |