diff --git a/extensions/source/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java b/extensions/source/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java index c75cea3b07c3..681cce89c223 100644 --- a/extensions/source/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java +++ b/extensions/source/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java @@ -45,7 +45,7 @@ public class ExtensionComponentAdapter extends ConstructorInjectionComponentAdap readerConfigurator.configureReader(xStream); } xStream.alias(myExtensionElement.getName(), componentInstance.getClass()); - myComponentInstance = xStream.unmarshal(new JDomReader(myExtensionElement), componentInstance); + myComponentInstance = xStream.unmarshal(new JDomExtensionsReader(myExtensionElement), componentInstance); } else { myComponentInstance = myExtensionElement; diff --git a/lib/commons-collections.jar b/lib/commons-collections.jar new file mode 100644 index 000000000000..f66c6d277588 Binary files /dev/null and b/lib/commons-collections.jar differ diff --git a/openapi/openapi.iml b/openapi/openapi.iml index 999a8b3d2400..7772e98a8e80 100644 --- a/openapi/openapi.iml +++ b/openapi/openapi.iml @@ -28,6 +28,7 @@ + diff --git a/openapi/src/com/intellij/openapi/module/Module.java b/openapi/src/com/intellij/openapi/module/Module.java index 94cf3a0750a1..9d4f283dab47 100644 --- a/openapi/src/com/intellij/openapi/module/Module.java +++ b/openapi/src/com/intellij/openapi/module/Module.java @@ -7,9 +7,10 @@ package com.intellij.openapi.module; import com.intellij.openapi.components.ComponentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.extensions.AreaInstance; import com.intellij.pom.PomModule; -public interface Module extends ComponentManager { +public interface Module extends ComponentManager, AreaInstance { Module[] EMPTY_ARRAY = new Module[0]; VirtualFile getModuleFile(); diff --git a/openapi/src/com/intellij/openapi/project/Project.java b/openapi/src/com/intellij/openapi/project/Project.java index e8ff13751058..8bd8cd4c509f 100644 --- a/openapi/src/com/intellij/openapi/project/Project.java +++ b/openapi/src/com/intellij/openapi/project/Project.java @@ -6,6 +6,7 @@ package com.intellij.openapi.project; import com.intellij.openapi.components.ComponentManager; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.extensions.AreaInstance; import com.intellij.pom.PomModel; @@ -13,7 +14,7 @@ import com.intellij.pom.PomModel; /** * Project interface class. */ -public interface Project extends ComponentManager { +public interface Project extends ComponentManager, AreaInstance { VirtualFile getProjectFile(); String getName(); /** diff --git a/plugins/conditionalOperatorConvertor/META-INF/plugin.xml b/plugins/conditionalOperatorConvertor/META-INF/plugin.xml index 7060820fdb50..262fdf8aedc9 100644 --- a/plugins/conditionalOperatorConvertor/META-INF/plugin.xml +++ b/plugins/conditionalOperatorConvertor/META-INF/plugin.xml @@ -1,14 +1,17 @@ - + ConditionalOperatorConverter Intention to convert a conditional operator into if 1.3 JetBrains - - - com.intellij.codeInsight.intention.ConditionalOperatorConvertor + + + com.intellij.codeInsight.intention.ConditionalOperatorConvertor + + + - + diff --git a/source/com/intellij/ide/plugins/PluginManager.java b/source/com/intellij/ide/plugins/PluginManager.java index bfd60c3f47c2..bdbb5e62f8dc 100644 --- a/source/com/intellij/ide/plugins/PluginManager.java +++ b/source/com/intellij/ide/plugins/PluginManager.java @@ -4,8 +4,10 @@ import com.intellij.ide.plugins.cl.IdeaClassLoader; import com.intellij.ide.plugins.cl.PluginClassLoader; import com.intellij.ide.startup.StartupActionScriptManager; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.extensions.*; import com.intellij.util.ArrayUtil; import com.intellij.util.graph.CachingSemiGraph; import com.intellij.util.graph.DFSTBuilder; @@ -35,6 +37,7 @@ import java.util.zip.ZipFile; public class PluginManager { //Logger is lasy-initialized in order not to use it outside the appClassLoader private static Logger ourLogger = null; + public static final String COMPONENT_EXTENSION_POINT = "com.intellij.plugins.component"; private static Logger getLogger() { if (ourLogger == null) { @@ -74,31 +77,78 @@ public class PluginManager { */ public static PluginDescriptor[] getPlugins() { if (ourPlugins == null) { - final PluginDescriptor[] pluginDescriptors = loadDescriptors(); + initializePlugins(); - final Map idToDescriptorMap = new HashMap(); - for (int idx = 0; idx < pluginDescriptors.length; idx++) { - final PluginDescriptor descriptor = pluginDescriptors[idx]; - idToDescriptorMap.put(descriptor.getId(), descriptor); - } - // sort descriptors according to plugin dependencies - Arrays.sort(pluginDescriptors, getPluginDescriptorComparator(idToDescriptorMap)); - - final Class callerClass = Reflection.getCallerClass(1); - final ClassLoader parentLoader = callerClass.getClassLoader(); - for (int idx = 0; idx < pluginDescriptors.length; idx++) { - final PluginDescriptor pluginDescriptor = pluginDescriptors[idx]; - final List classPath = pluginDescriptor.getClassPath(); - final String[] dependentPluginIds = pluginDescriptor.getDependentPluginIds(); - final ClassLoader[] parentLoaders = dependentPluginIds.length > 0? getParentLoaders(idToDescriptorMap, dependentPluginIds): new ClassLoader[] {parentLoader}; - final PluginClassLoader pluginClassLoader = createPluginClassLoader((File[])classPath.toArray(new File[classPath.size()]), pluginDescriptor.getName(), parentLoaders, pluginDescriptor.getPath()); - pluginDescriptor.setLoader(pluginClassLoader); - } - ourPlugins = pluginDescriptors; } return ourPlugins; } + private static void initializePlugins() { + if (!shouldLoadPlugins()) return; + + configureExtensions(); + + final PluginDescriptor[] pluginDescriptors = loadDescriptors(); + + final Map idToDescriptorMap = new HashMap(); + for (int idx = 0; idx < pluginDescriptors.length; idx++) { + final PluginDescriptor descriptor = pluginDescriptors[idx]; + idToDescriptorMap.put(descriptor.getId(), descriptor); + } + // sort descriptors according to plugin dependencies + Arrays.sort(pluginDescriptors, getPluginDescriptorComparator(idToDescriptorMap)); + + final Class callerClass = Reflection.getCallerClass(1); + final ClassLoader parentLoader = callerClass.getClassLoader(); + for (int idx = 0; idx < pluginDescriptors.length; idx++) { + final PluginDescriptor pluginDescriptor = pluginDescriptors[idx]; + final List classPath = pluginDescriptor.getClassPath(); + final String[] dependentPluginIds = pluginDescriptor.getDependentPluginIds(); + final ClassLoader[] parentLoaders = dependentPluginIds.length > 0? getParentLoaders(idToDescriptorMap, dependentPluginIds): new ClassLoader[] {parentLoader}; + final PluginClassLoader pluginClassLoader = createPluginClassLoader((File[])classPath.toArray(new File[classPath.size()]), pluginDescriptor.getName(), parentLoaders, pluginDescriptor.getPath()); + pluginDescriptor.setLoader(pluginClassLoader); + pluginDescriptor.registerExtensions(); + } + ourPlugins = pluginDescriptors; + } + + private static void configureExtensions() { + Extensions.setLogProvider(new IdeaLogProvider()); + Extensions.registerAreaClass("PROJECT", null); + Extensions.registerAreaClass("MODULE", "PROJECT"); + + Extensions.getRootArea().registerExtensionPoint(COMPONENT_EXTENSION_POINT, ComponentDescriptor.class.getName()); + + Extensions.getRootArea().getExtensionPoint(Extensions.AREA_LISTENER_EXTENSION_POINT).registerExtension(new AreaListener() { + public void areaCreated(String areaClass, AreaInstance areaInstance) { + if ("PROJECT".equals(areaClass) || "MODULE".equals(areaClass)) { + Extensions.getArea(areaInstance).registerExtensionPoint(COMPONENT_EXTENSION_POINT, ComponentDescriptor.class.getName()); + } + } + + public void areaDisposing(String areaClass, AreaInstance areaInstance) { + } + }, LoadingOrder.FIRST); + } + + public static boolean shouldLoadPlugins() { + try { + // no plugins during bootstrap + Class.forName("com.intellij.openapi.extensions.Extensions"); + } + catch (ClassNotFoundException e) { + return false; + } + final String loadPlugins = System.getProperty("idea.load.plugins"); + return ApplicationManagerEx.getApplicationEx() != null && !ApplicationManagerEx.getApplicationEx().isUnitTestMode() && (loadPlugins == null || "true".equals(loadPlugins)); + } + + public static boolean shouldLoadPlugin(PluginDescriptor descriptor) { + final String loadPluginCategory = System.getProperty("idea.load.plugins.category"); + return loadPluginCategory == null || loadPluginCategory.equals(descriptor.getCategory()); + } + + private static Comparator getPluginDescriptorComparator(Map idToDescriptorMap) { final Graph graph = createPluginIdGraph(idToDescriptorMap); final DFSTBuilder builder = new DFSTBuilder(graph); @@ -259,6 +309,12 @@ public class PluginManager { message.insert(0, "Problems found loading plugins:\n"); return message.toString(); } + for (Iterator iterator = result.iterator(); iterator.hasNext();) { + PluginDescriptor descriptor = iterator.next(); + if (!shouldLoadPlugins() || !shouldLoadPlugin(descriptor)) { + iterator.remove(); + } + } return null; } @@ -586,4 +642,30 @@ public class PluginManager { public static String getPluginByClassName (String className) { return ourPluginClasses != null? ourPluginClasses.get(className) : null; } + + private static class IdeaLogProvider implements LogProvider { + public void error(String message) { + getLogger().error(message); + } + + public void error(String message, Throwable t) { + getLogger().error(message, t); + } + + public void error(Throwable t) { + getLogger().error(t); + } + + public void warn(String message) { + getLogger().info(message); + } + + public void warn(String message, Throwable t) { + getLogger().info(message, t); + } + + public void warn(Throwable t) { + getLogger().info(t); + } + } } diff --git a/source/com/intellij/openapi/application/ex/ApplicationEx.java b/source/com/intellij/openapi/application/ex/ApplicationEx.java index cdec786f5154..c8f0cf82692b 100644 --- a/source/com/intellij/openapi/application/ex/ApplicationEx.java +++ b/source/com/intellij/openapi/application/ex/ApplicationEx.java @@ -14,10 +14,10 @@ import java.io.IOException; public interface ApplicationEx extends Application { /** * Loads the application configuration from the specified path - * + * * @param optionsPath Path to /config folder - * @throws IOException - * @throws InvalidDataException + * @throws IOException + * @throws InvalidDataException */ void load(String optionsPath) throws IOException, InvalidDataException; @@ -25,8 +25,6 @@ public interface ApplicationEx extends Application { boolean isAspectJSupportEnabled(); - boolean shouldLoadPlugins(); - String getComponentsDescriptor(); String getName(); @@ -37,8 +35,6 @@ public interface ApplicationEx extends Application { void doNotSave(); - boolean shouldLoadPlugin(PluginDescriptor descriptor); - boolean runProcessWithProgressSynchronously(Runnable process, String progressTitle, boolean canBeCanceled, diff --git a/source/com/intellij/openapi/application/impl/ApplicationImpl.java b/source/com/intellij/openapi/application/impl/ApplicationImpl.java index 29648112cff9..ba194a6463b9 100644 --- a/source/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/source/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -30,6 +30,9 @@ import com.intellij.openapi.project.impl.convertors.Convertor34; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.extensions.AreaInstance; +import com.intellij.openapi.extensions.ExtensionsArea; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.util.ArrayUtil; import com.intellij.util.concurrency.ReentrantWriterPreferenceReadWriteLock; @@ -120,14 +123,19 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application return myName; } + protected void initComponents() { + initComponentsFromExtensions(Extensions.getRootArea()); + super.initComponents(); + } + private void loadApplicationComponents() { loadComponentsConfiguration(APPLICATION_LAYER); - if (shouldLoadPlugins()) { + if (PluginManager.shouldLoadPlugins()) { final PluginDescriptor[] plugins = PluginManager.getPlugins(); for (int i = 0; i < plugins.length; i++) { PluginDescriptor plugin = plugins[i]; - if (!shouldLoadPlugin(plugin)) continue; + if (!PluginManager.shouldLoadPlugin(plugin)) continue; final Element appComponents = plugin.getAppComponents(); if (appComponents != null) { loadComponentsConfiguration(appComponents, plugin); @@ -148,16 +156,6 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application return myAspectJSupportEnabled || isUnitTestMode(); } - public boolean shouldLoadPlugins() { - final String loadPlugins = System.getProperty("idea.load.plugins"); - return !isUnitTestMode() && (loadPlugins == null || "true".equals(loadPlugins)); - } - - public boolean shouldLoadPlugin(PluginDescriptor descriptor) { - final String loadPluginCategory = System.getProperty("idea.load.plugins.category"); - return loadPluginCategory == null || loadPluginCategory.equals(descriptor.getCategory()); - } - private static Thread ourDispatchThread = null; public boolean isDispatchThread() { @@ -175,7 +173,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application } if (ourDispatchThread == currentThread) return true; - + if (ourDispatchThread != null && !ourDispatchThread.isAlive()) { ourDispatchThread = null; return isDispatchThread(currentThread); @@ -386,18 +384,18 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application disposeComponents(); } } - + public boolean runProcessWithProgressSynchronously(final Runnable process, String progressTitle, boolean canBeCanceled, Project project) { return runProcessWithProgressSynchronously(process, progressTitle, canBeCanceled, project, true); } - + public boolean runProcessWithProgressSynchronously(final Runnable process, String progressTitle, boolean canBeCanceled, - Project project, + Project project, boolean smoothProgress) { assertIsDispatchThread(); diff --git a/source/com/intellij/openapi/components/impl/ComponentManagerImpl.java b/source/com/intellij/openapi/components/impl/ComponentManagerImpl.java index 3aed64a6d0c1..9d73529a486b 100644 --- a/source/com/intellij/openapi/components/impl/ComponentManagerImpl.java +++ b/source/com/intellij/openapi/components/impl/ComponentManagerImpl.java @@ -1,21 +1,24 @@ package com.intellij.openapi.components.impl; import com.intellij.diagnostic.PluginException; +import com.intellij.ide.plugins.ComponentDescriptor; import com.intellij.ide.plugins.PluginDescriptor; +import com.intellij.ide.plugins.PluginManager; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.application.ex.DecodeDefaultsUtil; import com.intellij.openapi.components.BaseComponent; -import com.intellij.openapi.components.SettingsSavingComponent; import com.intellij.openapi.components.LoadCancelledException; +import com.intellij.openapi.components.SettingsSavingComponent; import com.intellij.openapi.components.ex.ComponentManagerEx; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.ExtensionsArea; import com.intellij.openapi.util.*; +import com.intellij.util.containers.HashMap; +import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; -import org.jdom.Document; import org.picocontainer.*; import org.picocontainer.defaults.*; -import com.intellij.util.containers.HashMap; import java.io.IOException; import java.io.InputStream; @@ -173,7 +176,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements synchronized (this) { myInitializingComponents.remove(component); myInitializedComponents.put(interfaceClass, component); - } + } } return (T)component; } @@ -363,6 +366,37 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements return myPicoContainer; } + protected void initComponentsFromExtensions(final ExtensionsArea extensionsArea) { + final ComponentDescriptor[] componentDescriptors = + (ComponentDescriptor[])extensionsArea.getExtensionPoint(PluginManager.COMPONENT_EXTENSION_POINT).getExtensions(); + for (int i = 0; i < componentDescriptors.length; i++) { + ComponentDescriptor descriptor = componentDescriptors[i]; + final Map options = descriptor.getOptionsMap(); + if (isComponentSuitable(options)) { + ClassLoader loader = findLoader(descriptor.getPluginName()); + try { + registerComponent(Class.forName(descriptor.getInterface(), true, loader), Class.forName(descriptor.getImplementation(), true, loader), options, true, + isTrue(options, "lazy")); + } + catch (Exception e) { + LOG.error(new PluginException(e, PluginManager.getPlugin(descriptor.getPluginName()))); + } + catch (Error e) { + LOG.error(new PluginException(e, PluginManager.getPlugin(descriptor.getPluginName()))); + } + } + } + + } + + private ClassLoader findLoader(final String pluginName) { + ClassLoader loader = PluginManager.getPlugin(pluginName).getLoader(); + if (loader == null) { + loader = getClass().getClassLoader(); + } + return loader; + } + protected static class InvalidComponentDataException extends RuntimeException { public InvalidComponentDataException(InvalidDataException exception) { super(exception); @@ -524,7 +558,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements throws PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException { - + DecoratingComponentAdapter initializingAdapter = new DecoratingComponentAdapter(new ConstructorInjectionComponentAdapter(componentKey, componentImplementation, parameters, true)) { public Object getComponentInstance(PicoContainer picoContainer) throws PicoInitializationException, PicoIntrospectionException { Object componentInstance = super.getComponentInstance(picoContainer); diff --git a/source/com/intellij/openapi/module/impl/ModuleImpl.java b/source/com/intellij/openapi/module/impl/ModuleImpl.java index 73d1251f6883..f9cb64dfa783 100644 --- a/source/com/intellij/openapi/module/impl/ModuleImpl.java +++ b/source/com/intellij/openapi/module/impl/ModuleImpl.java @@ -21,6 +21,8 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.pointers.VirtualFilePointer; import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; +import com.intellij.openapi.extensions.AreaInstance; +import com.intellij.openapi.extensions.Extensions; import com.intellij.pom.PomModel; import com.intellij.pom.PomModule; import com.intellij.pom.core.impl.PomModuleImpl; @@ -56,6 +58,7 @@ public class ModuleImpl extends BaseFileConfigurable implements Module { super(false, pathMacros); myProject = project; myPomModel = pomModel; + Extensions.instantiateArea("MODULE", this, project); init(filePath); } @@ -79,12 +82,12 @@ public class ModuleImpl extends BaseFileConfigurable implements Module { public void loadModuleComponents() { loadComponentsConfiguration(MODULE_LAYER); - ApplicationEx app = ApplicationManagerEx.getApplicationEx(); - if (app.shouldLoadPlugins()) { + if (PluginManager.shouldLoadPlugins()) { final PluginDescriptor[] plugins = PluginManager.getPlugins(); for (int i = 0; i < plugins.length; i++) { PluginDescriptor plugin = plugins[i]; - if (!app.shouldLoadPlugin(plugin)) continue; + if (!PluginManager.shouldLoadPlugin(plugin)) continue; + final Element moduleComponents = plugin.getModuleComponents(); if (moduleComponents != null) { loadComponentsConfiguration(moduleComponents, plugin); diff --git a/source/com/intellij/openapi/project/impl/ProjectImpl.java b/source/com/intellij/openapi/project/impl/ProjectImpl.java index 2a97aa3fbafc..2bbb2970f057 100644 --- a/source/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/source/com/intellij/openapi/project/impl/ProjectImpl.java @@ -35,6 +35,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.pointers.VirtualFilePointer; import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.extensions.AreaInstance; import com.intellij.pom.PomModel; import com.intellij.util.ArrayUtil; import org.jdom.Document; @@ -50,7 +52,7 @@ import java.util.*; /** * */ -public class ProjectImpl extends BaseFileConfigurable implements ProjectEx { +public class ProjectImpl extends BaseFileConfigurable implements ProjectEx, AreaInstance { private static final Logger LOG = Logger.getInstance("#com.intellij.project.impl.ProjectImpl"); private ProjectManagerImpl myManager; @@ -85,6 +87,8 @@ public class ProjectImpl extends BaseFileConfigurable implements ProjectEx { myOptimiseTestLoadSpeed = isOptimiseTestLoadSpeed; + Extensions.instantiateArea("PROJECT", this, null); + getPicoContainer().registerComponentInstance(Project.class, this); myManager = manager; @@ -139,12 +143,11 @@ public class ProjectImpl extends BaseFileConfigurable implements ProjectEx { public void loadProjectComponents() { loadComponentsConfiguration(PROJECT_LAYER); - ApplicationEx app = ApplicationManagerEx.getApplicationEx(); - if (app.shouldLoadPlugins()) { + if (PluginManager.shouldLoadPlugins()) { final PluginDescriptor[] plugins = PluginManager.getPlugins(); for (int i = 0; i < plugins.length; i++) { PluginDescriptor plugin = plugins[i]; - if (!app.shouldLoadPlugin(plugin)) continue; + if (!PluginManager.shouldLoadPlugin(plugin)) continue; final Element projectComponents = plugin.getProjectComponents(); if (projectComponents != null) { loadComponentsConfiguration(projectComponents, plugin); diff --git a/testSource/com/intellij/mock/MockApplication.java b/testSource/com/intellij/mock/MockApplication.java index 3b054df65644..f3f05186efd4 100644 --- a/testSource/com/intellij/mock/MockApplication.java +++ b/testSource/com/intellij/mock/MockApplication.java @@ -61,10 +61,6 @@ public class MockApplication extends UserDataHolderBase implements ApplicationEx return true; } - public boolean shouldLoadPlugins() { - return false; - } - public BaseComponent getComponent(String name) { return null; } @@ -124,10 +120,6 @@ public class MockApplication extends UserDataHolderBase implements ApplicationEx public void doNotSave() { } - public boolean shouldLoadPlugin(PluginDescriptor descriptor) { - return false; - } - public boolean runProcessWithProgressSynchronously(Runnable process, String progressTitle, boolean canBeCanceled,