| /******************************************************************************* |
| * Copyright (c) 2000, 2009 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.core.internal.filebuffers; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.ILog; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.content.IContentType; |
| import org.eclipse.core.runtime.content.IContentTypeManager; |
| |
| import org.eclipse.core.filebuffers.IAnnotationModelFactory; |
| import org.eclipse.core.filebuffers.IDocumentSetupParticipant; |
| import org.eclipse.core.filebuffers.LocationKind; |
| |
| |
| /** |
| * This registry manages sharable document factories and setup |
| * participants that are specified in <code>plugin.xml</code>. |
| */ |
| public class ExtensionsRegistry { |
| |
| /** |
| * Adapts {@link IContentType} with the ability to check equality. This allows to use them in a |
| * collection. |
| */ |
| private static class ContentTypeAdapter { |
| |
| /** The adapted content type. */ |
| private IContentType fContentType; |
| |
| /** |
| * Creates a new content type adapter for the |
| * given content type. |
| * |
| * @param contentType the content type to be adapted |
| */ |
| public ContentTypeAdapter(IContentType contentType) { |
| Assert.isNotNull(contentType); |
| fContentType= contentType; |
| } |
| |
| /** |
| * Return the id of the adapted content type. |
| * |
| * @return the id |
| */ |
| public String getId() { |
| return fContentType.getId(); |
| } |
| |
| /* |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| public boolean equals(Object obj) { |
| return obj instanceof ContentTypeAdapter && fContentType.getId().equals(((ContentTypeAdapter)obj).getId()); |
| } |
| |
| /* |
| * @see java.lang.Object#hashCode() |
| */ |
| public int hashCode() { |
| return fContentType.getId().hashCode(); |
| } |
| } |
| |
| protected static final String WILDCARD= "*"; //$NON-NLS-1$ |
| |
| /** The mapping between file attributes and configuration elements describing document factories. */ |
| private Map fFactoryDescriptors= new HashMap(); |
| /** The mapping between configuration elements for document factories and instantiated document factories. */ |
| private Map fFactories= new HashMap(); |
| /** The mapping between file attributes and configuration elements describing document setup participants. */ |
| private Map fSetupParticipantDescriptors= new HashMap(); |
| /** The mapping between configuration elements for setup participants and instantiated setup participants. */ |
| private Map fSetupParticipants= new HashMap(); |
| /** The mapping between file attributes and configuration elements describing annotation model factories. */ |
| private Map fAnnotationModelFactoryDescriptors= new HashMap(); |
| /** The mapping between configuration elements for annotation model factories */ |
| private Map fAnnotationModelFactories= new HashMap(); |
| /** The content type manager. */ |
| protected IContentTypeManager fContentTypeManager= Platform.getContentTypeManager(); |
| |
| |
| /** |
| * Creates a new document factory registry and initializes it with the information |
| * found in the plug-in registry. |
| */ |
| public ExtensionsRegistry() { |
| initialize("documentCreation", "contentTypeId", true, fFactoryDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| initialize("documentCreation", "fileNames", false, fFactoryDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| initialize("documentCreation", "extensions", false, fFactoryDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| initialize("documentSetup", "contentTypeId", true, fSetupParticipantDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| initialize("documentSetup", "fileNames", false, fSetupParticipantDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| initialize("documentSetup", "extensions", false, fSetupParticipantDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| initialize("annotationModelCreation", "contentTypeId", true, fAnnotationModelFactoryDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| initialize("annotationModelCreation", "fileNames", false, fAnnotationModelFactoryDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| initialize("annotationModelCreation", "extensions", false, fAnnotationModelFactoryDescriptors); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| } |
| |
| /** |
| * Reads the comma-separated value from the given configuration element for the given attribute name and remembers |
| * the configuration element in the given map under the individual tokens of the attribute value. |
| * |
| * @param attributeName the name of the attribute |
| * @param element the configuration element |
| * @param map the map which remembers the configuration element |
| */ |
| private void read(String attributeName, IConfigurationElement element, Map map) { |
| String value= element.getAttribute(attributeName); |
| if (value != null) { |
| StringTokenizer tokenizer= new StringTokenizer(value, ","); //$NON-NLS-1$ |
| while (tokenizer.hasMoreTokens()) { |
| String token= tokenizer.nextToken().trim(); |
| |
| Set s= (Set) map.get(token); |
| if (s == null) { |
| s= new HashSet(); |
| map.put(token, s); |
| } |
| s.add(element); |
| } |
| } |
| } |
| |
| /** |
| * Reads the value from the given configuration element for the given attribute name and remembers |
| * the configuration element in the given map under the individual content type of the attribute value. |
| * |
| * @param attributeName the name of the attribute |
| * @param element the configuration element |
| * @param map the map which remembers the configuration element |
| */ |
| private void readContentType(String attributeName, IConfigurationElement element, Map map) { |
| String value= element.getAttribute(attributeName); |
| if (value != null) { |
| IContentType contentType= fContentTypeManager.getContentType(value); |
| if (contentType == null) { |
| log(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, IStatus.OK, NLSUtility.format(FileBuffersMessages.ExtensionsRegistry_error_contentTypeDoesNotExist, value), null)); |
| return; |
| } |
| ContentTypeAdapter adapter= new ContentTypeAdapter(contentType); |
| Set s= (Set) map.get(adapter); |
| if (s == null) { |
| s= new HashSet(); |
| map.put(adapter, s); |
| } |
| s.add(element); |
| } |
| } |
| |
| /** |
| * Adds an entry to the log of this plug-in for the given status |
| * @param status the status to log |
| */ |
| private void log(IStatus status) { |
| ILog log= FileBuffersPlugin.getDefault().getLog(); |
| log.log(status); |
| } |
| |
| /** |
| * Initializes this registry. It retrieves all implementers of the given |
| * extension point and remembers those implementers based on the |
| * file name extensions in the given map. |
| * |
| * @param extensionPointName the name of the extension point |
| * @param childElementName the name of the child elements |
| * @param isContentTypeId the child element is a content type id |
| * @param descriptors the map to be filled |
| */ |
| private void initialize(String extensionPointName, String childElementName, boolean isContentTypeId, Map descriptors) { |
| |
| IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(FileBuffersPlugin.PLUGIN_ID, extensionPointName); |
| if (extensionPoint == null) { |
| log(new Status(IStatus.ERROR, FileBuffersPlugin.PLUGIN_ID, 0, NLSUtility.format(FileBuffersMessages.ExtensionsRegistry_error_extensionPointNotFound, extensionPointName), null)); |
| return; |
| } |
| |
| IConfigurationElement[] elements= extensionPoint.getConfigurationElements(); |
| for (int i= 0; i < elements.length; i++) { |
| if (isContentTypeId) |
| readContentType(childElementName, elements[i], descriptors); |
| else |
| read(childElementName, elements[i], descriptors); |
| } |
| } |
| |
| /** |
| * Returns the executable extension for the given configuration element. |
| * If there is no instantiated extension remembered for this |
| * element, a new extension is created and put into the cache if it is of the requested type. |
| * |
| * @param entry the configuration element |
| * @param extensions the map of instantiated extensions |
| * @param extensionType the requested result type |
| * @return the executable extension for the given configuration element. |
| */ |
| private Object getExtension(IConfigurationElement entry, Map extensions, Class extensionType) { |
| Object extension= extensions.get(entry); |
| if (extension != null) |
| return extension; |
| |
| try { |
| extension= entry.createExecutableExtension("class"); //$NON-NLS-1$ |
| } catch (CoreException x) { |
| log(x.getStatus()); |
| } |
| |
| if (extensionType.isInstance(extension)) { |
| extensions.put(entry, extension); |
| return extension; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the first enumerated element of the given set. |
| * |
| * @param set the set from which to choose |
| * @return the selected configuration element |
| */ |
| private IConfigurationElement selectConfigurationElement(Set set) { |
| if (set != null && !set.isEmpty()) { |
| Iterator e= set.iterator(); |
| return (IConfigurationElement) e.next(); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a sharable document factory for the given file name or file extension. |
| * |
| * @param nameOrExtension the name or extension to be used for lookup |
| * @return the sharable document factory or <code>null</code> |
| * @deprecated As of 3.5 |
| */ |
| protected org.eclipse.core.filebuffers.IDocumentFactory getDocumentFactory(String nameOrExtension) { |
| Set set= (Set) fFactoryDescriptors.get(nameOrExtension); |
| if (set != null) { |
| IConfigurationElement entry= selectConfigurationElement(set); |
| return (org.eclipse.core.filebuffers.IDocumentFactory)getExtension(entry, fFactories, org.eclipse.core.filebuffers.IDocumentFactory.class); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a sharable document factory for the given content types. |
| * |
| * @param contentTypes the content types used to find the factory |
| * @return the sharable document factory or <code>null</code> |
| * @deprecated As of 3.5 |
| */ |
| protected org.eclipse.core.filebuffers.IDocumentFactory doGetDocumentFactory(IContentType[] contentTypes) { |
| Set set= null; |
| int i= 0; |
| while (i < contentTypes.length && set == null) { |
| set= (Set) fFactoryDescriptors.get(new ContentTypeAdapter(contentTypes[i++])); |
| } |
| |
| if (set != null) { |
| IConfigurationElement entry= selectConfigurationElement(set); |
| return (org.eclipse.core.filebuffers.IDocumentFactory)getExtension(entry, fFactories, org.eclipse.core.filebuffers.IDocumentFactory.class); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a sharable document factory for the given content types. This method considers the |
| * base content types of the given set of content types. |
| * |
| * @param contentTypes the content types used to find the factory |
| * @return the sharable document factory or <code>null</code> |
| * @deprecated As of 3.5 |
| */ |
| protected org.eclipse.core.filebuffers.IDocumentFactory getDocumentFactory(IContentType[] contentTypes) { |
| org.eclipse.core.filebuffers.IDocumentFactory factory= doGetDocumentFactory(contentTypes); |
| while (factory == null) { |
| contentTypes= computeBaseContentTypes(contentTypes); |
| if (contentTypes == null) |
| break; |
| factory= doGetDocumentFactory(contentTypes); |
| } |
| return factory; |
| } |
| |
| /** |
| * Returns the set of setup participants for the given file name or extension. |
| * |
| * @param nameOrExtension the name or extension to be used for lookup |
| * @return the sharable set of document setup participants |
| */ |
| protected List getDocumentSetupParticipants(String nameOrExtension) { |
| Set set= (Set) fSetupParticipantDescriptors.get(nameOrExtension); |
| if (set == null) |
| return null; |
| |
| List participants= new ArrayList(); |
| Iterator e= set.iterator(); |
| while (e.hasNext()) { |
| IConfigurationElement entry= (IConfigurationElement) e.next(); |
| Object participant= getExtension(entry, fSetupParticipants, IDocumentSetupParticipant.class); |
| if (participant != null) |
| participants.add(participant); |
| } |
| |
| return participants; |
| } |
| |
| /** |
| * Returns the set of setup participants for the given content types. |
| * |
| * @param contentTypes the contentTypes to be used for lookup |
| * @return the sharable set of document setup participants |
| */ |
| private List doGetDocumentSetupParticipants(IContentType[] contentTypes) { |
| Set resultSet= new HashSet(); |
| int i= 0; |
| while (i < contentTypes.length) { |
| Set set= (Set) fSetupParticipantDescriptors.get(new ContentTypeAdapter(contentTypes[i++])); |
| if (set != null) |
| resultSet.addAll(set); |
| } |
| |
| List participants= new ArrayList(); |
| Iterator e= resultSet.iterator(); |
| while (e.hasNext()) { |
| IConfigurationElement entry= (IConfigurationElement) e.next(); |
| Object participant= getExtension(entry, fSetupParticipants, IDocumentSetupParticipant.class); |
| if (participant != null) |
| participants.add(participant); |
| } |
| |
| return participants.isEmpty() ? null : participants; |
| } |
| |
| /** |
| * Returns the set of setup participants for the given content types. This |
| * method considers the base content types of the given set of content |
| * types. |
| * |
| * @param contentTypes the contentTypes to be used for lookup |
| * @return the sharable set of document setup participants |
| */ |
| protected List getDocumentSetupParticipants(IContentType[] contentTypes) { |
| List participants= doGetDocumentSetupParticipants(contentTypes); |
| while (participants == null) { |
| contentTypes= computeBaseContentTypes(contentTypes); |
| if (contentTypes == null) |
| break; |
| participants= doGetDocumentSetupParticipants(contentTypes); |
| } |
| return participants; |
| } |
| |
| /** |
| * Returns a sharable annotation model factory for the given content types. |
| * |
| * @param contentTypes the content types used to find the factory |
| * @return the sharable annotation model factory or <code>null</code> |
| */ |
| private IAnnotationModelFactory doGetAnnotationModelFactory(IContentType[] contentTypes) { |
| Set set= null; |
| int i= 0; |
| while (i < contentTypes.length && set == null) { |
| set= (Set) fAnnotationModelFactoryDescriptors.get(new ContentTypeAdapter(contentTypes[i++])); |
| } |
| |
| if (set != null) { |
| IConfigurationElement entry= selectConfigurationElement(set); |
| return (IAnnotationModelFactory) getExtension(entry, fAnnotationModelFactories, IAnnotationModelFactory.class); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a sharable annotation model factory for the given content types. |
| * This method considers the base content types of the given set of content |
| * types. |
| * |
| * @param contentTypes the content types used to find the factory |
| * @return the sharable annotation model factory or <code>null</code> |
| */ |
| protected IAnnotationModelFactory getAnnotationModelFactory(IContentType[] contentTypes) { |
| IAnnotationModelFactory factory= doGetAnnotationModelFactory(contentTypes); |
| while (factory == null) { |
| contentTypes= computeBaseContentTypes(contentTypes); |
| if (contentTypes == null) |
| break; |
| factory= doGetAnnotationModelFactory(contentTypes); |
| } |
| return factory; |
| } |
| |
| /** |
| * Returns a sharable annotation model factory for the given file name or file extension. |
| * |
| * @param extension the name or extension to be used for lookup |
| * @return the sharable document factory or <code>null</code> |
| */ |
| protected IAnnotationModelFactory getAnnotationModelFactory(String extension) { |
| Set set= (Set) fAnnotationModelFactoryDescriptors.get(extension); |
| if (set != null) { |
| IConfigurationElement entry= selectConfigurationElement(set); |
| return (IAnnotationModelFactory) getExtension(entry, fAnnotationModelFactories, IAnnotationModelFactory.class); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the set of content types for the given location. |
| * |
| * @param location the location for which to look up the content types |
| * @param locationKind the kind of the given location |
| * @return the set of content types for the location |
| * @since 3.3 |
| */ |
| protected IContentType[] findContentTypes(IPath location, LocationKind locationKind) { |
| Assert.isLegal(locationKind != LocationKind.IFILE); |
| return fContentTypeManager.findContentTypesFor(location.lastSegment()); |
| } |
| |
| /** |
| * Returns the set of direct base content types for the given set of content |
| * types. Returns <code>null</code> if non of the given content types has |
| * a direct base content type. |
| * |
| * @param contentTypes the content types |
| * @return the set of direct base content types |
| */ |
| private IContentType[] computeBaseContentTypes(IContentType[] contentTypes) { |
| List baseTypes= new ArrayList(); |
| for (int i= 0; i < contentTypes.length; i++) { |
| IContentType baseType= contentTypes[i].getBaseType(); |
| if (baseType != null) |
| baseTypes.add(baseType); |
| } |
| |
| IContentType[] result= null; |
| int size= baseTypes.size(); |
| if (size > 0) { |
| result= new IContentType[size]; |
| baseTypes.toArray(result); |
| } |
| return result; |
| } |
| |
| /** |
| * Returns the sharable document factory for the given location. |
| * |
| * @param location the location for which to looked up the factory |
| * @param locationKind the kind of the given location |
| * @return the sharable document factory |
| * @since 3.3 |
| * @deprecated As of 3.5 |
| */ |
| public org.eclipse.core.filebuffers.IDocumentFactory getDocumentFactory(IPath location, LocationKind locationKind) { |
| org.eclipse.core.filebuffers.IDocumentFactory factory= getDocumentFactory(findContentTypes(location, locationKind)); |
| if (factory == null) |
| factory= getDocumentFactory(location.lastSegment()); |
| if (factory == null) |
| factory= getDocumentFactory(location.getFileExtension()); |
| if (factory == null) |
| factory= getDocumentFactory(WILDCARD); |
| return factory; |
| } |
| |
| /** |
| * Returns the sharable set of document setup participants for the given location. |
| * |
| * @param location the location for which to look up the setup participants |
| * @param locationKind the kind of the given location |
| * @return the sharable set of document setup participants |
| * @since 3.3 |
| */ |
| public IDocumentSetupParticipant[] getDocumentSetupParticipants(IPath location, LocationKind locationKind) { |
| Set participants= new HashSet(); |
| |
| List p= getDocumentSetupParticipants(findContentTypes(location, locationKind)); |
| if (p != null) |
| participants.addAll(p); |
| |
| p= getDocumentSetupParticipants(location.lastSegment()); |
| if (p != null) |
| participants.addAll(p); |
| |
| p= getDocumentSetupParticipants(location.getFileExtension()); |
| if (p != null) |
| participants.addAll(p); |
| |
| p= getDocumentSetupParticipants(WILDCARD); |
| if (p != null) |
| participants.addAll(p); |
| |
| IDocumentSetupParticipant[] result= new IDocumentSetupParticipant[participants.size()]; |
| participants.toArray(result); |
| return result; |
| } |
| |
| /** |
| * Returns the sharable annotation model factory for the given location. |
| * |
| * @param location the location for which to look up the factory |
| * @param locationKind the kind of the given location |
| * @return the sharable annotation model factory |
| * @since 3.3 |
| */ |
| public IAnnotationModelFactory getAnnotationModelFactory(IPath location, LocationKind locationKind) { |
| IAnnotationModelFactory factory= getAnnotationModelFactory(findContentTypes(location, locationKind)); |
| if (factory == null) |
| factory= getAnnotationModelFactory(location.lastSegment()); |
| if (factory == null) |
| factory= getAnnotationModelFactory(location.getFileExtension()); |
| if (factory == null) |
| factory= getAnnotationModelFactory(WILDCARD); |
| return factory; |
| } |
| |
| } |