From b22f775cc21fbe5d43997b162d4fe0cc30f755f5 Mon Sep 17 00:00:00 2001 From: Sergei Vorobyov Date: Tue, 16 Jul 2019 13:43:04 +0300 Subject: [PATCH] IDEA-CR-49630 added unsubscription from external system API events GitOrigin-RevId: 6b0f0f2f8f595fe7743ca4cb5ed6b0dd53290267 --- .../AbstractExternalSystemSettings.java | 18 ++++++++ .../util/ExternalSystemApiUtil.java | 11 ++++- .../gradle/settings/GradleSettings.java | 9 +++- .../startup/GradleUnlinkedProjectProcessor.kt | 15 ++++++- .../gradle/settings/GradleSubscriptionTest.kt | 34 ++++++++++++++ .../settings/GradleSubscriptionTestCase.kt | 44 +++++++++++++++++++ 6 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/settings/GradleSubscriptionTest.kt create mode 100644 plugins/gradle/testSources/org/jetbrains/plugins/gradle/settings/GradleSubscriptionTestCase.kt diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java index 7630132ebc5b..5dd9daef4bb4 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/AbstractExternalSystemSettings.java @@ -71,10 +71,28 @@ public abstract class AbstractExternalSystemSettings< *

* That's why this method allows to wrap given 'generic listener' into external system-specific one. * + * @param subscription is a disposable to unsubscribe from external system settings events * @param listener target generic listener to wrap to external system-specific implementation */ + public void subscribe(@NotNull Disposable subscription, @NotNull ExternalSystemSettingsListener listener) { + subscribe(listener); + } + + /** + * @deprecated use {@link AbstractExternalSystemSettings#subscribe(Disposable, ExternalSystemSettingsListener)} instead + */ + @Deprecated public abstract void subscribe(@NotNull ExternalSystemSettingsListener listener); + /** + * Generic subscribe implementation + * + * @see AbstractExternalSystemSettings#subscribe(Disposable, ExternalSystemSettingsListener) + */ + protected void doSubscribe(@NotNull Disposable subscription, @NotNull L listener) { + getProject().getMessageBus().connect(subscription).subscribe(getChangesTopic(), listener); + } + public void copyFrom(@NotNull SS settings) { for (PS projectSettings : settings.getLinkedProjectsSettings()) { myLinkedProjectsSettings.put(projectSettings.getExternalProjectPath(), projectSettings); diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java index dfcacdcc5d01..0feb96abeade 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/util/ExternalSystemApiUtil.java @@ -3,6 +3,7 @@ package com.intellij.openapi.externalSystem.util; import com.intellij.execution.rmi.RemoteUtil; import com.intellij.ide.highlighter.ArchiveFileType; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.*; import com.intellij.openapi.externalSystem.ExternalSystemAutoImportAware; import com.intellij.openapi.externalSystem.ExternalSystemManager; @@ -683,7 +684,15 @@ public class ExternalSystemApiUtil { @NotNull ProjectSystemId systemId, @NotNull ExternalSystemSettingsListener listener) { //noinspection unchecked - getSettings(project, systemId).subscribe(listener); + getSettings(project, systemId).subscribe(project, listener); + } + + public static void subscribe(@NotNull Project project, + @NotNull ProjectSystemId systemId, + @NotNull Disposable subscription, + @NotNull ExternalSystemSettingsListener listener) { + //noinspection unchecked + getSettings(project, systemId).subscribe(subscription, listener); } @NotNull diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java index 5fa145a953f8..d888783ae1ce 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java @@ -1,6 +1,7 @@ // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.gradle.settings; +import com.intellij.openapi.Disposable; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.State; @@ -43,8 +44,12 @@ public class GradleSettings extends AbstractExternalSystemSettings listener) { - getProject().getMessageBus().connect(getProject()).subscribe(GradleSettingsListener.TOPIC, - new DelegatingGradleSettingsListenerAdapter(listener)); + subscribe(getProject(), listener); + } + + @Override + public void subscribe(@NotNull Disposable subscription, @NotNull ExternalSystemSettingsListener listener) { + doSubscribe(subscription, new DelegatingGradleSettingsListenerAdapter(listener)); } @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/startup/GradleUnlinkedProjectProcessor.kt b/plugins/gradle/src/org/jetbrains/plugins/gradle/startup/GradleUnlinkedProjectProcessor.kt index 6f73ed931133..faae53e849c6 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/startup/GradleUnlinkedProjectProcessor.kt +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/startup/GradleUnlinkedProjectProcessor.kt @@ -6,12 +6,14 @@ import com.intellij.notification.NotificationAction import com.intellij.notification.NotificationType import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.application.ApplicationNamesInfo +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.project.DumbAware import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.Project import com.intellij.openapi.startup.StartupActivity +import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter import org.jetbrains.plugins.gradle.service.project.GradleNotification @@ -30,7 +32,9 @@ class GradleUnlinkedProjectProcessor : StartupActivity, DumbAware { } companion object { - private const val SHOW_UNLINKED_GRADLE_POPUP = "show.inlinked.gradle.project.popup" + private const val SHOW_UNLINKED_GRADLE_POPUP = "show.unlinked.gradle.project.popup" + + private val LOG = Logger.getInstance(GradleUnlinkedProjectProcessor::class.java) private fun showNotification(project: Project) { if (!GradleSettings.getInstance(project).linkedProjectsSettings.isEmpty()) return @@ -61,12 +65,15 @@ class GradleUnlinkedProjectProcessor : StartupActivity, DumbAware { override fun actionPerformed(e: AnActionEvent) {} } + val subscription = Disposer.newDisposable() val settingsListener = object : GradleSettingsListenerAdapter() { override fun onProjectsLinked(settings: MutableCollection) { notification.expire() + debug("Unlinked project notification expired") + Disposer.dispose(subscription) } } - ExternalSystemApiUtil.subscribe(project, GradleConstants.SYSTEM_ID, settingsListener) + ExternalSystemApiUtil.subscribe(project, GradleConstants.SYSTEM_ID, subscription, settingsListener) notification.notify(project) } @@ -82,5 +89,9 @@ class GradleUnlinkedProjectProcessor : StartupActivity, DumbAware { fun enableNotifications(project: Project) { PropertiesComponent.getInstance(project).setValue(SHOW_UNLINKED_GRADLE_POPUP, true, false) } + + private fun debug(message: String) { + if (LOG.isDebugEnabled) LOG.debug(message) + } } } \ No newline at end of file diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/settings/GradleSubscriptionTest.kt b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/settings/GradleSubscriptionTest.kt new file mode 100644 index 000000000000..173880150f1c --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/settings/GradleSubscriptionTest.kt @@ -0,0 +1,34 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.gradle.settings + +import com.intellij.openapi.util.Disposer +import org.junit.Test + +class GradleSubscriptionTest : GradleSubscriptionTestCase() { + + @Test + fun `test external system subscription`() { + var linkingCounter = 0 + onProjectLinked { + linkingCounter += 1 + } + linkProject() + unlinkProject() + linkProject() + assertEquals(2, linkingCounter) + } + + @Test + fun `test external system unsubscription`() { + var linkingCounter = 0 + val subscription = Disposer.newDisposable() + onProjectLinked(subscription) { + linkingCounter += 1 + Disposer.dispose(subscription) + } + linkProject() + unlinkProject() + linkProject() + assertEquals(1, linkingCounter) + } +} \ No newline at end of file diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/settings/GradleSubscriptionTestCase.kt b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/settings/GradleSubscriptionTestCase.kt new file mode 100644 index 000000000000..e395c0822bec --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/settings/GradleSubscriptionTestCase.kt @@ -0,0 +1,44 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.gradle.settings + +import com.intellij.openapi.Disposable +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil +import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter +import org.jetbrains.plugins.gradle.importing.GradleBuildScriptBuilderEx +import org.jetbrains.plugins.gradle.importing.GradleImportingTestCase +import org.junit.runners.Parameterized + +abstract class GradleSubscriptionTestCase : GradleImportingTestCase() { + + protected fun linkProject() { + importProject(GradleBuildScriptBuilderEx().withJavaPlugin().generate()) + } + + protected fun unlinkProject() { + val settings = ExternalSystemApiUtil.getSettings(myProject, externalSystemId) + settings.unlinkExternalProject(currentExternalProjectSettings.externalProjectPath) + } + + protected fun onProjectLinked(subscription: Disposable, listener: () -> Unit) { + val settingsListener = object : GradleSettingsListenerAdapter() { + override fun onProjectsLinked(settings: MutableCollection) = listener() + } + ExternalSystemApiUtil.subscribe(myProject, externalSystemId, subscription, settingsListener) + } + + protected fun onProjectLinked(listener: () -> Unit) { + val settingsListener = object : GradleSettingsListenerAdapter() { + override fun onProjectsLinked(settings: MutableCollection) = listener() + } + ExternalSystemApiUtil.subscribe(myProject, externalSystemId, settingsListener) + } + + companion object { + /** + * It's sufficient to run the test against one gradle version + */ + @Parameterized.Parameters(name = "with Gradle-{0}") + @JvmStatic + fun tests(): Collection> = arrayListOf(arrayOf(BASE_GRADLE_VERSION)) + } +} \ No newline at end of file