To support correct unload of identical extensions contributed by multiple plugins, check both plugin descriptor and serialized EP representation (IDEA-234849)

GitOrigin-RevId: fbee9d72928fa8a6b5e9bc5929422c9bb4128e16
This commit is contained in:
Dmitry Jemerov
2020-03-10 09:34:33 +00:00
committed by intellij-monorepo-bot
parent 0685ecc3d5
commit bf17d1cd45
5 changed files with 18 additions and 10 deletions
@@ -48,7 +48,7 @@ public final class BeanExtensionPoint<T> extends ExtensionPointImpl<T> {
}
@Override
public void unregisterExtensions(@NotNull List<Element> elements, List<Runnable> listenerCallbacks) {
public void unregisterExtensions(@NotNull PluginDescriptor pluginDescriptor, @NotNull List<Element> elements, List<Runnable> listenerCallbacks) {
Map<String, String> defaultAttributes = new HashMap<>();
ClassLoader classLoader = myDescriptor.getPluginClassLoader();
if (classLoader == null) {
@@ -67,7 +67,7 @@ public final class BeanExtensionPoint<T> extends ExtensionPointImpl<T> {
return true;
}
XmlExtensionAdapter xmlExtensionAdapter = (XmlExtensionAdapter)adapter;
return !xmlExtensionAdapter.isLoadedFromAnyElement(elements, defaultAttributes);
return xmlExtensionAdapter.getPluginDescriptor() != pluginDescriptor || !xmlExtensionAdapter.isLoadedFromAnyElement(elements, defaultAttributes);
}, false, listenerCallbacks);
}
}
@@ -638,7 +638,7 @@ public abstract class ExtensionPointImpl<@NotNull T> implements ExtensionPoint<T
return found;
}
public abstract void unregisterExtensions(@NotNull List<Element> elements, List<Runnable> listenerCallbacks);
public abstract void unregisterExtensions(@NotNull PluginDescriptor pluginDescriptor, @NotNull List<Element> elements, List<Runnable> listenerCallbacks);
private void notifyListeners(@NotNull ExtensionEvent event,
@NotNull T extensionObject,
@@ -51,7 +51,7 @@ public final class InterfaceExtensionPoint<T> extends ExtensionPointImpl<T> {
}
@Override
public void unregisterExtensions(@NotNull List<Element> elements, List<Runnable> listenerCallbacks) {
public void unregisterExtensions(@NotNull PluginDescriptor pluginDescriptor, @NotNull List<Element> elements, List<Runnable> listenerCallbacks) {
Set<String> implementationClassNames = new HashSet<>();
for (Element element : elements) {
implementationClassNames.add(element.getAttributeValue("implementation"));
@@ -84,6 +84,10 @@ class XmlExtensionAdapter extends ExtensionComponentAdapter {
boolean isLoadedFromAnyElement(List<Element> candidateElements, Map<String, String> defaultAttributes) {
SkipDefaultValuesSerializationFilters filter = new SkipDefaultValuesSerializationFilters();
if (myExtensionElement == null && extensionInstance == null) {
// dummy extension with no data; unload based on PluginDescriptor check in calling method
return true;
}
Element serializedElement = myExtensionElement != null ? myExtensionElement : XmlSerializer.serialize(extensionInstance, filter);
Map<String, String> serializedAttributes = getExtensionAttributesMap(serializedElement);
@@ -309,7 +309,7 @@ object DynamicPlugins {
application.runWriteAction {
try {
processOptionalDependenciesOnPlugin(pluginDescriptor) { loadedDescriptorOfDependency, dependencyDescriptor ->
unloadPluginDescriptor(dependencyDescriptor, dependencyDescriptor)
unloadPluginDescriptor(dependencyDescriptor, loadedDescriptorOfDependency, dependencyDescriptor)
if (loadedPluginDescriptor.pluginClassLoader is PluginClassLoader) {
(loadedDescriptorOfDependency.pluginClassLoader as? PluginClassLoader)?.detachParent(loadedPluginDescriptor.pluginClassLoader)
}
@@ -397,7 +397,11 @@ object DynamicPlugins {
GROUP.createNotification(text, notificationType).notify(null)
}
private fun unloadPluginDescriptor(pluginDescriptor: IdeaPluginDescriptorImpl, loadedPluginDescriptor: IdeaPluginDescriptorImpl) {
private fun unloadPluginDescriptor(
pluginDescriptor: IdeaPluginDescriptorImpl,
loadedPluginDescriptor: IdeaPluginDescriptorImpl,
descriptorToUnloadListeners: IdeaPluginDescriptorImpl = loadedPluginDescriptor
) {
val application = ApplicationManager.getApplication() as ApplicationImpl
(ActionManager.getInstance() as ActionManagerImpl).unloadActions(pluginDescriptor)
@@ -408,12 +412,12 @@ object DynamicPlugins {
for ((epName, epExtensions) in extensions) {
val appEp = Extensions.getRootArea().getExtensionPointIfRegistered<Any>(epName) as ExtensionPointImpl<*>?
if (appEp != null) {
appEp.unregisterExtensions(epExtensions, unloadListeners)
appEp.unregisterExtensions(loadedPluginDescriptor, epExtensions, unloadListeners)
}
else {
for (openProject in openProjects) {
val projectEp = openProject.extensionArea.getExtensionPointIfRegistered<Any>(epName) as ExtensionPointImpl<*>?
projectEp?.unregisterExtensions(epExtensions, unloadListeners)
projectEp?.unregisterExtensions(loadedPluginDescriptor, epExtensions, unloadListeners)
}
}
}
@@ -437,7 +441,7 @@ object DynamicPlugins {
for (appServiceInstance in appServiceInstances) {
application.stateStore.unloadComponent(appServiceInstance)
}
(application.messageBus as MessageBusImpl).unsubscribePluginListeners(loadedPluginDescriptor)
(application.messageBus as MessageBusImpl).unsubscribePluginListeners(descriptorToUnloadListeners)
for (project in openProjects) {
val projectServiceInstances = (project as ProjectImpl).unloadServices(pluginDescriptor.project)
@@ -451,7 +455,7 @@ object DynamicPlugins {
module.stateStore.unloadComponent(moduleServiceInstance)
}
}
(project.messageBus as MessageBusImpl).unsubscribePluginListeners(loadedPluginDescriptor)
(project.messageBus as MessageBusImpl).unsubscribePluginListeners(descriptorToUnloadListeners)
}
}