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
This commit is contained in:
Alexander Zolotov
2019-12-17 17:37:53 +00:00
committed by intellij-monorepo-bot
parent 54142b6c5e
commit 8950ac722d
2 changed files with 40 additions and 0 deletions
@@ -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<PluginDescriptor, Disposable> {
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
@@ -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<ExtensionPoint<?>, Collection<WeakReference<Object>>> 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);