From 8950ac722dcb75a9a75ff6b9d4e0f8234ea02e09 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Tue, 17 Dec 2019 18:58:42 +0300 Subject: [PATCH] Introduce plugin disposables Using plugin disposables (DynamicPlugins#pluginDisposable(class)) listeners can be registered until plugin is unloaded. Plugin disposable wrapper (DynamicPlugins#pluginDisposable(class, disposable)) allows to register listener until plugin is unloaded or default disposable is disposed. GitOrigin-RevId: ef73ce1c5a5b9895b94a96fda2c4b4dd65e61f8d --- .../intellij/ide/plugins/DynamicPlugins.kt | 34 +++++++++++++++++++ .../testFramework/src/_LastInSuiteTest.java | 6 ++++ 2 files changed, 40 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/DynamicPlugins.kt b/platform/platform-impl/src/com/intellij/ide/plugins/DynamicPlugins.kt index 19d6ac19bdd7..afd988c3d31c 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/DynamicPlugins.kt +++ b/platform/platform-impl/src/com/intellij/ide/plugins/DynamicPlugins.kt @@ -2,6 +2,7 @@ package com.intellij.ide.plugins import com.intellij.configurationStore.jdomSerializer +import com.intellij.ide.plugins.cl.PluginClassLoader import com.intellij.ide.ui.UIThemeProvider import com.intellij.notification.NotificationDisplayType import com.intellij.notification.NotificationGroup @@ -14,6 +15,7 @@ import com.intellij.openapi.application.impl.ApplicationImpl import com.intellij.openapi.components.stateStore import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.extensions.Extensions +import com.intellij.openapi.extensions.PluginDescriptor import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl import com.intellij.openapi.keymap.impl.BundledKeymapBean import com.intellij.openapi.keymap.impl.BundledKeymapProvider @@ -29,6 +31,7 @@ import com.intellij.util.ArrayUtil import com.intellij.util.CachedValuesManagerImpl import com.intellij.util.MemoryDumpHelper import com.intellij.util.SystemProperties +import com.intellij.util.containers.ConcurrentFactoryMap import com.intellij.util.messages.Topic import com.intellij.util.messages.impl.MessageBusImpl import com.intellij.util.ui.UIUtil @@ -65,6 +68,10 @@ object DynamicPlugins { private val LOG = Logger.getInstance(DynamicPlugins::class.java) private val GROUP = NotificationGroup("Dynamic plugin installation", NotificationDisplayType.BALLOON, false) + val pluginDisposables = ConcurrentFactoryMap.createWeakMap { + plugin -> Disposer.newDisposable("Plugin disposable [${plugin.name}]") + } + @JvmStatic fun allowLoadUnloadWithoutRestart(pluginDescriptor: IdeaPluginDescriptorImpl): Boolean { if (!ApplicationManager.getApplication().isInternal) { @@ -234,6 +241,10 @@ object DynamicPlugins { return classLoaderUnloaded } finally { + val disposable = pluginDisposables.remove(pluginDescriptor) + if (disposable != null) { + Disposer.dispose(disposable) + } application.messageBus.syncPublisher(DynamicPluginListener.TOPIC).pluginUnloaded(pluginDescriptor, isUpdate) } } @@ -271,7 +282,30 @@ object DynamicPlugins { } finally { application.messageBus.syncPublisher(DynamicPluginListener.TOPIC).pluginLoaded(pluginDescriptor) } + } + @JvmStatic + fun pluginDisposable(clazz: Class<*>): Disposable? { + val classLoader = clazz.classLoader + if (classLoader is PluginClassLoader) { + val pluginDescriptor = classLoader.pluginDescriptor + if (pluginDescriptor != null) { + return pluginDisposables[pluginDescriptor] + } + } + return null + } + + @JvmStatic + fun pluginDisposableWrapper(clazz: Class<*>, defaultValue: Disposable): Disposable { + val pluginDisposable = pluginDisposable(clazz) + if (pluginDisposable != null) { + val result = Disposer.newDisposable() + Disposer.register(pluginDisposable, result) + Disposer.register(defaultValue, result) + return result + } + return defaultValue } @JvmStatic diff --git a/platform/testFramework/src/_LastInSuiteTest.java b/platform/testFramework/src/_LastInSuiteTest.java index 76746587dbcb..23cafcc1c2c8 100644 --- a/platform/testFramework/src/_LastInSuiteTest.java +++ b/platform/testFramework/src/_LastInSuiteTest.java @@ -2,6 +2,7 @@ import com.intellij.ide.IdeEventQueue; import com.intellij.ide.plugins.DynamicPluginListener; +import com.intellij.ide.plugins.DynamicPlugins; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.openapi.application.Application; @@ -70,6 +71,7 @@ public class _LastInSuiteTest extends TestCase { Map, Collection>> extensions = collectDynamicNonPlatformExtensions(); unloadExtensionPoints(extensions.keySet()); + disposePluginDisposables(); ProjectManager pm = ProjectManager.getInstanceIfCreated(); if (pm != null) { for (Project project : pm.getOpenProjects()) { @@ -107,6 +109,10 @@ public class _LastInSuiteTest extends TestCase { } } + private static void disposePluginDisposables() { + DynamicPlugins.INSTANCE.getPluginDisposables().forEach((plugin, disposable) -> Disposer.dispose(disposable)); + } + @NotNull private static String escape(String s) { return MapSerializerUtil.escapeStr(s, MapSerializerUtil.STD_ESCAPER);