| /******************************************************************************* |
| * Copyright (c) 2007 BEA Systems, Inc. |
| * 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: |
| * wharley@bea.com - initial API and implementation |
| * |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.apt.core.internal; |
| |
| import java.util.HashMap; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jdt.apt.core.internal.util.FactoryContainer; |
| import org.eclipse.jdt.apt.core.internal.util.FactoryPath; |
| |
| import com.sun.mirror.apt.AnnotationProcessorFactory; |
| |
| /** |
| * Manages caches of plugins which provide annotation processors. |
| * |
| * @since 3.3 |
| */ |
| public class FactoryPluginManager { |
| /** |
| * Map of factory names -> factories. A single plugin factory container may |
| * contain multiple annotation processor factories, each with a unique name. |
| * To support lazy initialization, this should only be accessed by calling |
| * @see #getJava5PluginFactoryMap() . |
| */ |
| private static final HashMap<String, AnnotationProcessorFactory> PLUGIN_JAVA5_FACTORY_MAP = new HashMap<String, AnnotationProcessorFactory>(); |
| |
| /** |
| * Map of factory names -> factories. A single plugin factory container may |
| * contain multiple annotation processor factories, each with a unique name. |
| * To support lazy initialization, this should only be accessed by calling |
| * @see #getJava5PluginFactoryMap() . |
| */ |
| private static final HashMap<String, IServiceFactory> PLUGIN_JAVA6_FACTORY_MAP = new HashMap<String, IServiceFactory>(); |
| |
| /** |
| * Map of plugin names -> plugin factory containers, sorted by plugin name. |
| * A plugin that contains annotation processor factories (and extends the |
| * corresponding extension point) is a "plugin factory container". |
| * To support lazy initialization, this should only be accessed by calling |
| * @see #getPluginFactoryContainerMap() . |
| */ |
| private static final TreeMap<String, PluginFactoryContainer> PLUGIN_CONTAINER_MAP = new TreeMap<String, PluginFactoryContainer>(); |
| |
| /** |
| * true if PLUGIN_FACTORY_MAP and PLUGIN_CONTAINER_MAP have been initialized, |
| * by calling @see #loadPluginFactories() . |
| */ |
| private static boolean mapsInitialized = false; |
| |
| /** |
| * Returns an ordered list of all the plugin factory containers that have |
| * been registered as plugins. Note that this may include plugins that have |
| * been disabled by the user's configuration. The 'enabled' attribute in the |
| * returned map reflects the 'enableDefault' attribute in the plugin |
| * manifest, rather than the user configuration. |
| * Ordering is alphabetic by plugin id. |
| */ |
| public static synchronized Map<FactoryContainer, FactoryPath.Attributes> getAllPluginFactoryContainers() |
| { |
| Map<FactoryContainer, FactoryPath.Attributes> map = |
| new LinkedHashMap<FactoryContainer, FactoryPath.Attributes>(getPluginContainerMap().size()); |
| for (PluginFactoryContainer pfc : getPluginContainerMap().values()) { |
| FactoryPath.Attributes a = new FactoryPath.Attributes(pfc.getEnableDefault(), false); |
| map.put(pfc, a); |
| } |
| return map; |
| } |
| |
| public static synchronized AnnotationProcessorFactory getJava5FactoryFromPlugin( String factoryName ) |
| { |
| AnnotationProcessorFactory apf = getJava5PluginFactoryMap().get( factoryName ); |
| if ( apf == null ) |
| { |
| String s = "could not find AnnotationProcessorFactory " + //$NON-NLS-1$ |
| factoryName + " from available factories defined by plugins"; //$NON-NLS-1$ |
| AptPlugin.log(new Status(IStatus.WARNING, AptPlugin.PLUGIN_ID, AptPlugin.STATUS_NOTOOLSJAR, s, null)); |
| } |
| return apf; |
| } |
| |
| public static synchronized IServiceFactory getJava6FactoryFromPlugin( String factoryName ) |
| { |
| IServiceFactory isf = getJava6PluginFactoryMap().get( factoryName ); |
| if ( isf == null ) |
| { |
| String s = "could not find annotation processor " + //$NON-NLS-1$ |
| factoryName + " from available factories defined by plugins"; //$NON-NLS-1$ |
| AptPlugin.log(new Status(IStatus.WARNING, AptPlugin.PLUGIN_ID, AptPlugin.STATUS_NOTOOLSJAR, s, null)); |
| } |
| return isf; |
| } |
| |
| /** |
| * Return the factory container corresponding to the specified plugin id. |
| * All plugin factories are loaded at startup time. |
| * @param pluginId the id of a plugin that extends annotationProcessorFactory. |
| * @return a PluginFactoryContainer, or null if the plugin id does not |
| * identify an annotation processor plugin. |
| */ |
| public static synchronized FactoryContainer getPluginFactoryContainer(String pluginId) { |
| return getPluginContainerMap().get(pluginId); |
| } |
| |
| /** |
| * Get the alphabetically sorted map of plugin names to plugin factory containers. |
| * Load plugins if the map has not yet been initialized. |
| */ |
| private static TreeMap<String, PluginFactoryContainer> getPluginContainerMap() { |
| loadFactoryPlugins(); |
| return PLUGIN_CONTAINER_MAP; |
| } |
| |
| /** |
| * Get the map of plugin factory names to plugin factories. |
| * Load plugins if the map has not yet been initialized. |
| */ |
| private static HashMap<String, AnnotationProcessorFactory> getJava5PluginFactoryMap() { |
| loadFactoryPlugins(); |
| return PLUGIN_JAVA5_FACTORY_MAP; |
| } |
| |
| /** |
| * Get the map of plugin factory names to plugin factories. |
| * Load plugins if the map has not yet been initialized. |
| */ |
| private static HashMap<String, IServiceFactory> getJava6PluginFactoryMap() { |
| loadFactoryPlugins(); |
| return PLUGIN_JAVA6_FACTORY_MAP; |
| } |
| |
| /** |
| * Discover and instantiate annotation processor factories by searching for plugins |
| * which contribute to org.eclipse.jdt.apt.core.annotationProcessorFactory. |
| * The first time this method is called, it will load all the plugin factories. |
| * Subsequent calls will be ignored. |
| */ |
| private static synchronized void loadFactoryPlugins() { |
| if (mapsInitialized) { |
| return; |
| } |
| IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint( |
| AptPlugin.PLUGIN_ID, // name of plugin that exposes this extension point |
| "annotationProcessorFactory"); //$NON-NLS-1$ - extension id |
| |
| // Iterate over all declared extensions of this extension point. |
| // A single plugin may extend the extension point more than once, although it's not recommended. |
| for (IExtension extension : extensionPoint.getExtensions()) |
| { |
| // Iterate over the children of the extension to find one named "factories". |
| for(IConfigurationElement factories : extension.getConfigurationElements()) |
| { |
| if ("factories".equals(factories.getName())) { //$NON-NLS-1$ - name of configElement |
| loadJava5Factories(extension, factories); |
| } |
| else if ("java6processors".equals(factories.getName())) { //$NON-NLS-1$ - name of configElement |
| loadJava6Factories(extension, factories); |
| } |
| |
| } |
| } |
| mapsInitialized = true; |
| } |
| |
| private static void loadJava6Factories(IExtension extension, IConfigurationElement factories) { |
| if (!AptPlugin.canRunJava6Processors()) { |
| return; |
| } |
| |
| // Get enableDefault. If the attribute is missing, default to true. |
| String enableDefaultStr = factories.getAttribute("enableDefault"); //$NON-NLS-1$ |
| boolean enableDefault = true; |
| if ("false".equals(enableDefaultStr)) { //$NON-NLS-1$ |
| enableDefault = false; |
| } |
| |
| // Create and cache a PluginFactoryContainer for this plugin. |
| String pluginId = extension.getNamespaceIdentifier(); |
| //TODO: level problem. In the extension point, enableDefault is associated with element, not ext point. |
| PluginFactoryContainer pfc = new PluginFactoryContainer(pluginId, enableDefault); |
| PLUGIN_CONTAINER_MAP.put(pluginId, pfc); |
| |
| // Iterate over the children of the "java6processors" element to find all the ones named "java6processor". |
| for (IConfigurationElement factory : factories.getChildren()) { |
| if (!"java6processor".equals(factory.getName())) { //$NON-NLS-1$ |
| continue; |
| } |
| String factoryName = null; |
| try { |
| factoryName = factory.getAttribute("class"); //$NON-NLS-1$ |
| Object execExt = factory.createExecutableExtension("class"); //$NON-NLS-1$ - attribute name |
| Class<?> clazz = execExt.getClass(); |
| if (AptPlugin.getJava6ProcessorClass().isInstance(execExt)){ |
| assert(clazz.getName().equals(factoryName)); |
| IServiceFactory isf = new ClassServiceFactory(clazz); |
| PLUGIN_JAVA6_FACTORY_MAP.put( factoryName, isf ); |
| pfc.addFactoryName(factoryName, AptPlugin.JAVA6_FACTORY_NAME); |
| } |
| else { |
| reportFailureToLoadProcessor(null, factoryName, extension.getNamespaceIdentifier()); |
| } |
| } catch(CoreException e) { |
| reportFailureToLoadProcessor(e, factoryName, extension.getNamespaceIdentifier()); |
| } |
| } |
| } |
| |
| private static void loadJava5Factories(IExtension extension, IConfigurationElement factories) { |
| // Get enableDefault. If the attribute is missing, default to true. |
| String enableDefaultStr = factories.getAttribute("enableDefault"); //$NON-NLS-1$ |
| boolean enableDefault = true; |
| if ("false".equals(enableDefaultStr)) { //$NON-NLS-1$ |
| enableDefault = false; |
| } |
| |
| // Create and cache a PluginFactoryContainer for this plugin. |
| String pluginId = extension.getNamespaceIdentifier(); |
| PluginFactoryContainer pfc = new PluginFactoryContainer(pluginId, enableDefault); |
| PLUGIN_CONTAINER_MAP.put(pluginId, pfc); |
| |
| // Iterate over the children of the "factories" element to find all the ones named "factory". |
| for (IConfigurationElement factory : factories.getChildren()) { |
| if (!"factory".equals(factory.getName())) { //$NON-NLS-1$ |
| continue; |
| } |
| String factoryName = null; |
| try { |
| factoryName = factory.getAttribute("class"); //$NON-NLS-1$ |
| Object execExt = factory.createExecutableExtension("class"); //$NON-NLS-1$ - attribute name |
| if (execExt instanceof AnnotationProcessorFactory){ |
| assert(execExt.getClass().getName().equals(factoryName)); |
| PLUGIN_JAVA5_FACTORY_MAP.put( factoryName, (AnnotationProcessorFactory)execExt ); |
| pfc.addFactoryName(factoryName, AptPlugin.JAVA5_FACTORY_NAME); |
| } |
| else { |
| reportFailureToLoadProcessor(null, factory.getName(), extension.getNamespaceIdentifier()); |
| } |
| } catch(CoreException e) { |
| reportFailureToLoadProcessor(e, factory.getName(), extension.getNamespaceIdentifier()); |
| } |
| } |
| } |
| |
| private static void reportFailureToLoadProcessor(Exception e, String factoryName, String pluginId) { |
| AptPlugin.log(e, "Unable to load annotation processor "+ factoryName + //$NON-NLS-1$ |
| " from plug-in " + pluginId); //$NON-NLS-1$ |
| } |
| |
| |
| } |