From aacf1e4c19e25f3e0d501e48635713cafc7f3390 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 25 Sep 2013 11:46:56 +0200 Subject: [PATCH] IDEA-113844 (handling of core component initialization failures when spoiled by plugins) --- .../impl/ExtensionComponentAdapter.java | 62 ++++++++++--------- ...luginExtensionInitializationException.java | 32 ++++++++++ .../intellij/ide/plugins/PluginManager.java | 19 +++++- 3 files changed, 83 insertions(+), 30 deletions(-) create mode 100644 platform/extensions/src/com/intellij/openapi/extensions/impl/PicoPluginExtensionInitializationException.java diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java index 8e46a2f0b18a..51fb0d6823ad 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionComponentAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +22,8 @@ import com.intellij.util.xmlb.XmlSerializer; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.picocontainer.*; -import org.picocontainer.defaults.AssignabilityRegistrationException; import org.picocontainer.defaults.CachingComponentAdapter; import org.picocontainer.defaults.ConstructorInjectionComponentAdapter; -import org.picocontainer.defaults.NotConcreteRegistrationException; /** * @author Alexander Kireyev @@ -33,6 +31,7 @@ import org.picocontainer.defaults.NotConcreteRegistrationException; */ public class ExtensionComponentAdapter implements LoadingOrder.Orderable, AssignableToComponentAdapter { public static final ExtensionComponentAdapter[] EMPTY_ARRAY = new ExtensionComponentAdapter[0]; + private Object myComponentInstance; private final String myImplementationClassName; private final Element myExtensionElement; @@ -65,36 +64,42 @@ public class ExtensionComponentAdapter implements LoadingOrder.Orderable, Assign } @Override - public Object getComponentInstance(final PicoContainer container) - throws PicoInitializationException, - PicoIntrospectionException, - AssignabilityRegistrationException, - NotConcreteRegistrationException, - ProcessCanceledException { + public Object getComponentInstance(final PicoContainer container) throws PicoException, ProcessCanceledException { if (myComponentInstance == null) { - if (Element.class.equals(getComponentImplementation())) { - myComponentInstance = myExtensionElement; - } - else { - Object componentInstance = getDelegate().getComponentInstance(container); - - if (myDeserializeInstance) { - try { - XmlSerializer.deserializeInto(componentInstance, myExtensionElement); - } - catch (Exception e) { - throw new PicoInitializationException(e); - } + try { + if (Element.class.equals(getComponentImplementation())) { + myComponentInstance = myExtensionElement; } + else { + Object componentInstance = getDelegate().getComponentInstance(container); - ExtensionInitializer initializer = (ExtensionInitializer)container.getComponentInstance(ExtensionInitializer.class); - if (initializer != null) { - initializer.initExtension(componentInstance); + if (myDeserializeInstance) { + try { + XmlSerializer.deserializeInto(componentInstance, myExtensionElement); + } + catch (Exception e) { + throw new PicoInitializationException(e); + } + } + + ExtensionInitializer initializer = (ExtensionInitializer)container.getComponentInstance(ExtensionInitializer.class); + if (initializer != null) { + initializer.initExtension(componentInstance); + } + + myComponentInstance = componentInstance; } - myComponentInstance = componentInstance; } + catch (ProcessCanceledException e) { + throw e; + } + catch (Throwable t) { + PluginId pluginId = myPluginDescriptor != null ? myPluginDescriptor.getPluginId() : null; + throw new PicoPluginExtensionInitializationException(t.getMessage(), t, pluginId); + } + if (myComponentInstance instanceof PluginAware) { - PluginAware pluginAware = (PluginAware) myComponentInstance; + PluginAware pluginAware = (PluginAware)myComponentInstance; pluginAware.setPluginDescriptor(myPluginDescriptor); } } @@ -161,7 +166,8 @@ public class ExtensionComponentAdapter implements LoadingOrder.Orderable, Assign private synchronized ComponentAdapter getDelegate() { if (myDelegate == null) { - myDelegate = new CachingComponentAdapter(new ConstructorInjectionComponentAdapter(getComponentKey(), loadClass(myImplementationClassName), null, true)); + Class impl = loadClass(myImplementationClassName); + myDelegate = new CachingComponentAdapter(new ConstructorInjectionComponentAdapter(getComponentKey(), impl, null, true)); } return myDelegate; diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/PicoPluginExtensionInitializationException.java b/platform/extensions/src/com/intellij/openapi/extensions/impl/PicoPluginExtensionInitializationException.java new file mode 100644 index 000000000000..07ac622d8c1e --- /dev/null +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/PicoPluginExtensionInitializationException.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.extensions.impl; + +import com.intellij.openapi.extensions.PluginId; +import org.picocontainer.PicoInitializationException; + +public class PicoPluginExtensionInitializationException extends PicoInitializationException { + private final PluginId myPluginId; + + public PicoPluginExtensionInitializationException(String message, Throwable cause, PluginId id) { + super(message, cause); + myPluginId = id; + } + + public PluginId getPluginId() { + return myPluginId; + } +} diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java index 95bbfdc6bd81..4037066bab40 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java @@ -27,6 +27,7 @@ import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.components.ComponentConfig; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.extensions.impl.PicoPluginExtensionInitializationException; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Comparing; @@ -99,6 +100,9 @@ public class PluginManager extends PluginManagerCore { if (t instanceof StartupAbortedException) { se = (StartupAbortedException)t; } + else if (t.getCause() instanceof StartupAbortedException) { + se = (StartupAbortedException)t.getCause(); + } else if (!IdeaApplication.isLoaded()) { se = new StartupAbortedException(t); } @@ -196,7 +200,18 @@ public class PluginManager extends PluginManagerCore { throw (StartupAbortedException)t; } - PluginId pluginId = config != null ? config.getPluginId() : getPluginByClassName(componentClassName); + PluginId pluginId = null; + if (config != null) { + pluginId = config.getPluginId(); + } + if (pluginId == null || CORE_PLUGIN_ID.equals(pluginId.getIdString())) { + pluginId = getPluginByClassName(componentClassName); + } + if (pluginId == null || CORE_PLUGIN_ID.equals(pluginId.getIdString())) { + if (t instanceof PicoPluginExtensionInitializationException) { + pluginId = ((PicoPluginExtensionInitializationException)t).getPluginId(); + } + } if (pluginId != null && !CORE_PLUGIN_ID.equals(pluginId.getIdString())) { getLogger().warn(t); @@ -206,7 +221,7 @@ public class PluginManager extends PluginManagerCore { String message = "Plugin '" + pluginId.getIdString() + "' failed to initialize and will be disabled\n" + "(reason: " + t.getMessage() + ")\n\n" + - ApplicationNamesInfo.getInstance().getFullProductName() + " will be restarted."; + "Please restart " + ApplicationNamesInfo.getInstance().getFullProductName() + "."; Main.showMessage("Plugin Error", message, false); throw new StartupAbortedException(t).exitCode(Main.PLUGIN_ERROR).logError(false);