blob: ed7485ceb41faf8300fc08b8f92b0d8bf59772e2 [file] [log] [blame]
/*******************************************************************************
* 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$
}
}