IDEA-113844 (handling of core component initialization failures when spoiled by plugins)

This commit is contained in:
Roman Shevchenko
2013-09-25 11:47:25 +02:00
parent 8dc3ede247
commit aacf1e4c19
3 changed files with 83 additions and 30 deletions
@@ -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;
@@ -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;
}
}
@@ -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);