From b1ee6a846be4e4a48ec4cdc5841ca53886c029f9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Thu, 14 Jun 2018 16:53:47 +0200 Subject: [PATCH] SONAR-10690 Core Extension installed at level 1 2 3 and 4 --- .../container/ComputeEngineContainerImpl.java | 66 ++++++++++++++----- .../ComputeEngineContainerImplTest.java | 6 +- .../CECoreExtensionsInstallerTest.java | 7 +- .../platformlevel/PlatformLevel1.java | 22 ++++++- .../platformlevel/PlatformLevel2.java | 19 ++++-- .../platformlevel/PlatformLevel3.java | 15 +++++ .../platformlevel/PlatformLevel4.java | 6 +- .../WebCoreExtensionsInstallerTest.java | 4 +- .../extension/CoreExtensionsInstaller.java | 55 +++++++++++----- .../sonar/core/extension/PlatformLevel.java | 22 +++++++ .../extension/PlatformLevelPredicates.java | 66 ++++++++++++++++++- .../CoreExtensionsInstallerTest.java | 24 +++---- .../scanner/scan/ModuleScanContainer.java | 3 +- .../scanner/scan/ProjectScanContainer.java | 3 +- .../org/sonar/scanner/task/TaskContainer.java | 3 +- .../ScannerCoreExtensionsInstallerTest.java | 4 +- 16 files changed, 257 insertions(+), 68 deletions(-) diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index a6760848531..061785baef5 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -64,7 +64,6 @@ import org.sonar.ce.user.CeUserSession; import org.sonar.core.component.DefaultResourceTypes; import org.sonar.core.config.CorePropertyDefinitions; import org.sonar.core.extension.CoreExtensionRepositoryImpl; -import org.sonar.core.extension.CoreExtensionsInstaller; import org.sonar.core.extension.CoreExtensionsLoader; import org.sonar.core.i18n.RuleI18nManager; import org.sonar.core.platform.ComponentContainer; @@ -173,6 +172,9 @@ import org.sonar.server.webhook.WebhookModule; import org.sonarqube.ws.Rules; import static java.util.Objects.requireNonNull; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel; +import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel4OrNone; import static org.sonar.process.ProcessProperties.Property.CLUSTER_ENABLED; public class ComputeEngineContainerImpl implements ComputeEngineContainer { @@ -193,37 +195,64 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { this.level1 = new ComponentContainer(); populateLevel1(this.level1, props, requireNonNull(computeEngineStatus)); configureFromModules(this.level1); - this.level1.startComponents(); + startLevel1(this.level1); ComponentContainer level2 = this.level1.createChild(); populateLevel2(level2); configureFromModules(level2); - level2.getComponentByType(CoreExtensionsLoader.class).load(); - level2.startComponents(); + startLevel2(level2); ComponentContainer level3 = level2.createChild(); populateLevel3(level3); configureFromModules(level3); - level3.startComponents(); + startLevel3(level3); this.level4 = level3.createChild(); populateLevel4(this.level4, props); - configureFromModules(this.level4); - CoreExtensionsInstaller coreExtensionsInstaller = this.level4.getComponentByType(CECoreExtensionsInstaller.class); - coreExtensionsInstaller.install(this.level4, t -> true); - ServerExtensionInstaller extensionInstaller = this.level4.getComponentByType(ServerExtensionInstaller.class); - extensionInstaller.installExtensions(this.level4); - this.level4.startComponents(); - PlatformEditionProvider editionProvider = this.level4.getComponentByType(PlatformEditionProvider.class); - Loggers.get(ComputeEngineContainerImpl.class) - .info("Running {} edition", editionProvider.get().map(EditionProvider.Edition::getLabel).orElse("")); + startLevel4(this.level4); startupTasks(); return this; } + private static void startLevel1(ComponentContainer level1) { + level1.getComponentByType(CoreExtensionsLoader.class) + .load(); + level1.getComponentByType(CECoreExtensionsInstaller.class) + .install(level1, hasPlatformLevel(1), noAdditionalSideFilter()); + + level1.startComponents(); + } + + private static void startLevel2(ComponentContainer level2) { + level2.getComponentByType(CECoreExtensionsInstaller.class) + .install(level2, hasPlatformLevel(2), noAdditionalSideFilter()); + + level2.startComponents(); + } + + private static void startLevel3(ComponentContainer level3) { + level3.getComponentByType(CECoreExtensionsInstaller.class) + .install(level3, hasPlatformLevel(3), noAdditionalSideFilter()); + + level3.startComponents(); + } + + private static void startLevel4(ComponentContainer level4) { + level4.getComponentByType(CECoreExtensionsInstaller.class) + .install(level4, hasPlatformLevel4OrNone(), noAdditionalSideFilter()); + level4.getComponentByType(ServerExtensionInstaller.class) + .installExtensions(level4); + + level4.startComponents(); + + PlatformEditionProvider editionProvider = level4.getComponentByType(PlatformEditionProvider.class); + Loggers.get(ComputeEngineContainerImpl.class) + .info("Running {} edition", editionProvider.get().map(EditionProvider.Edition::getLabel).orElse("")); + } + private void startupTasks() { ComponentContainer startupLevel = this.level4.createChild(); startupLevel.add(startupComponents()); @@ -293,7 +322,11 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { IssueIndex.class, new OkHttpClientProvider(), - computeEngineStatus); + computeEngineStatus, + + CoreExtensionRepositoryImpl.class, + CoreExtensionsLoader.class, + CECoreExtensionsInstaller.class); container.add(toArray(CorePropertyDefinitions.all())); } @@ -318,8 +351,6 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { CePluginRepository.class, InstalledPluginReferentialFactory.class, ComputeEngineExtensionInstaller.class, - CoreExtensionRepositoryImpl.class, - CoreExtensionsLoader.class, // depends on plugins ServerI18n.class, // used by RuleI18nManager @@ -442,7 +473,6 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { PlatformEditionProvider.class, // privileged plugins - CECoreExtensionsInstaller.class, CoreExtensionBootstraper.class, CoreExtensionStopper.class, diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index 9401436c0f8..0899d7f4c2b 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -94,7 +94,7 @@ public class ComputeEngineContainerImplTest { assertThat(picoContainer.getComponentAdapters()) .hasSize( CONTAINER_ITSELF - + 85 // level 4 + + 84 // level 4 + 21 // content of QualityGateModule + 6 // content of CeConfigurationModule + 4 // content of CeQueueModule @@ -113,12 +113,12 @@ public class ComputeEngineContainerImplTest { ); assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSize( CONTAINER_ITSELF - + 16 // MigrationConfigurationModule + + 14 // MigrationConfigurationModule + 19 // level 2 ); assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION - + 27 // level 1 + + 30 // level 1 + 55 // content of DaoModule + 3 // content of EsModule + 58 // content of CorePropertyDefinitions diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/platform/CECoreExtensionsInstallerTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/platform/CECoreExtensionsInstallerTest.java index df075842c66..07938ee2cd3 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/platform/CECoreExtensionsInstallerTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/platform/CECoreExtensionsInstallerTest.java @@ -37,6 +37,8 @@ import org.sonar.core.platform.ComponentContainer; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter; public class CECoreExtensionsInstallerTest { private SonarRuntime sonarRuntime = mock(SonarRuntime.class); @@ -58,11 +60,10 @@ public class CECoreExtensionsInstallerTest { context.addExtensions(CeClass.class, ScannerClass.class, WebServerClass.class, NoAnnotationClass.class, OtherAnnotationClass.class, MultipleAnnotationClass.class); } - } - )); + })); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); assertThat(container.getPicoContainer().getComponentAdapters()) .hasSize(ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2); diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java index 6fed7e8b245..1b2276258e5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java @@ -30,6 +30,8 @@ import org.sonar.api.utils.System2; import org.sonar.api.utils.Version; import org.sonar.api.utils.internal.TempFolderCleaner; import org.sonar.core.config.CorePropertyDefinitions; +import org.sonar.core.extension.CoreExtensionRepositoryImpl; +import org.sonar.core.extension.CoreExtensionsLoader; import org.sonar.core.util.UuidFactoryImpl; import org.sonar.db.DBSessionsImpl; import org.sonar.db.DaoModule; @@ -51,6 +53,7 @@ import org.sonar.server.platform.Platform; import org.sonar.server.platform.ServerFileSystemImpl; import org.sonar.server.platform.TempFolderProvider; import org.sonar.server.platform.UrlSettings; +import org.sonar.server.platform.WebCoreExtensionsInstaller; import org.sonar.server.platform.WebServerImpl; import org.sonar.server.platform.db.EmbeddedDatabaseFactory; import org.sonar.server.rule.index.RuleIndex; @@ -59,6 +62,9 @@ import org.sonar.server.user.SystemPasscodeImpl; import org.sonar.server.user.ThreadLocalUserSession; import org.sonar.server.util.OkHttpClientProvider; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel; + public class PlatformLevel1 extends PlatformLevel { private final Platform platform; private final Properties properties; @@ -119,7 +125,11 @@ public class PlatformLevel1 extends PlatformLevel { // issues IssueIndex.class, - new OkHttpClientProvider()); + new OkHttpClientProvider(), + + CoreExtensionRepositoryImpl.class, + CoreExtensionsLoader.class, + WebCoreExtensionsInstaller.class); addAll(CorePropertyDefinitions.all()); // cluster @@ -133,4 +143,14 @@ public class PlatformLevel1 extends PlatformLevel { } } } + + @Override + public PlatformLevel start() { + get(CoreExtensionsLoader.class) + .load(); + get(WebCoreExtensionsInstaller.class) + .install(getContainer(), hasPlatformLevel(1), noAdditionalSideFilter()); + + return super.start(); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java index 75d15421ba2..f1c5a27b053 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java @@ -20,9 +20,9 @@ package org.sonar.server.platform.platformlevel; import org.sonar.api.utils.Durations; -import org.sonar.core.extension.CoreExtensionRepositoryImpl; -import org.sonar.core.extension.CoreExtensionsLoader; +import org.sonar.core.extension.CoreExtensionsInstaller; import org.sonar.core.i18n.RuleI18nManager; +import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.PluginClassloaderFactory; import org.sonar.core.platform.PluginLoader; import org.sonar.server.es.MigrationEsClientImpl; @@ -30,6 +30,7 @@ import org.sonar.server.l18n.ServerI18n; import org.sonar.server.platform.DatabaseServerCompatibility; import org.sonar.server.platform.DefaultServerUpgradeStatus; import org.sonar.server.platform.StartupMetadataProvider; +import org.sonar.server.platform.WebCoreExtensionsInstaller; import org.sonar.server.platform.db.CheckDatabaseCharsetAtStartup; import org.sonar.server.platform.db.migration.DatabaseMigrationExecutorServiceImpl; import org.sonar.server.platform.db.migration.DatabaseMigrationStateImpl; @@ -46,6 +47,9 @@ import org.sonar.server.plugins.ServerPluginRepository; import org.sonar.server.plugins.WebServerExtensionInstaller; import org.sonar.server.startup.ClusterConfigurationCheck; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel; + public class PlatformLevel2 extends PlatformLevel { public PlatformLevel2(PlatformLevel parent) { super("level2", parent); @@ -74,8 +78,6 @@ public class PlatformLevel2 extends PlatformLevel { PluginClassloaderFactory.class, InstalledPluginReferentialFactory.class, WebServerExtensionInstaller.class, - CoreExtensionRepositoryImpl.class, - CoreExtensionsLoader.class, // depends on plugins ServerI18n.class, @@ -89,8 +91,7 @@ public class PlatformLevel2 extends PlatformLevel { DatabaseMigrationExecutorServiceImpl.class); addIfCluster( - ClusterConfigurationCheck.class - ); + ClusterConfigurationCheck.class); addIfStartupLeader( DatabaseCharsetChecker.class, @@ -101,7 +102,11 @@ public class PlatformLevel2 extends PlatformLevel { public PlatformLevel start() { // ensuring the HistoryTable exists must be the first thing done when this level is started getOptional(MigrationHistoryTable.class).ifPresent(MigrationHistoryTable::start); - get(CoreExtensionsLoader.class).load(); + + ComponentContainer container = getContainer(); + CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class); + coreExtensionsInstaller.install(container, hasPlatformLevel(2), noAdditionalSideFilter()); + return super.start(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel3.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel3.java index 075f918ee02..27e8550d0a3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel3.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel3.java @@ -20,6 +20,8 @@ package org.sonar.server.platform.platformlevel; import org.sonar.api.utils.UriReader; +import org.sonar.core.extension.CoreExtensionsInstaller; +import org.sonar.core.platform.ComponentContainer; import org.sonar.core.util.DefaultHttpDownloader; import org.sonar.server.async.AsyncExecutionModule; import org.sonar.server.organization.DefaultOrganizationProviderImpl; @@ -27,10 +29,14 @@ import org.sonar.server.organization.OrganizationFlagsImpl; import org.sonar.server.platform.ServerIdManager; import org.sonar.server.platform.ServerImpl; import org.sonar.server.platform.StartupMetadataPersister; +import org.sonar.server.platform.WebCoreExtensionsInstaller; import org.sonar.server.platform.db.migration.NoopDatabaseMigrationImpl; import org.sonar.server.setting.DatabaseSettingLoader; import org.sonar.server.setting.DatabaseSettingsEnabler; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel; + public class PlatformLevel3 extends PlatformLevel { public PlatformLevel3(PlatformLevel parent) { super("level3", parent); @@ -51,4 +57,13 @@ public class PlatformLevel3 extends PlatformLevel { OrganizationFlagsImpl.class, AsyncExecutionModule.class); } + + @Override + public PlatformLevel start() { + ComponentContainer container = getContainer(); + CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class); + coreExtensionsInstaller.install(container, hasPlatformLevel(3), noAdditionalSideFilter()); + + return super.start(); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 306f7a36372..4cf3c4492d0 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -238,6 +238,9 @@ import org.sonar.server.ws.WebServiceFilter; import org.sonar.server.ws.WebServiceReroutingFilter; import org.sonar.server.ws.ws.WebServicesWsModule; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel4OrNone; + public class PlatformLevel4 extends PlatformLevel { private final List level4AddedComponents; @@ -536,7 +539,6 @@ public class PlatformLevel4 extends PlatformLevel { ProjectBadgesWsModule.class, // Core Extensions - WebCoreExtensionsInstaller.class, CoreExtensionBootstraper.class, CoreExtensionStopper.class, @@ -581,7 +583,7 @@ public class PlatformLevel4 extends PlatformLevel { public PlatformLevel start() { ComponentContainer container = getContainer(); CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class); - coreExtensionsInstaller.install(container, t -> true); + coreExtensionsInstaller.install(container, hasPlatformLevel4OrNone(), noAdditionalSideFilter()); ServerExtensionInstaller extensionInstaller = get(ServerExtensionInstaller.class); extensionInstaller.installExtensions(container); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/WebCoreExtensionsInstallerTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/WebCoreExtensionsInstallerTest.java index 60eee2cce4d..b890aa29f80 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/WebCoreExtensionsInstallerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/WebCoreExtensionsInstallerTest.java @@ -37,6 +37,8 @@ import org.sonar.core.platform.ComponentContainer; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter; public class WebCoreExtensionsInstallerTest { private SonarRuntime sonarRuntime = mock(SonarRuntime.class); @@ -61,7 +63,7 @@ public class WebCoreExtensionsInstallerTest { })); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); assertThat(container.getPicoContainer().getComponentAdapters()) .hasSize(ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2); diff --git a/sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsInstaller.java b/sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsInstaller.java index a9b175f353e..2e154769a55 100644 --- a/sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsInstaller.java +++ b/sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsInstaller.java @@ -44,6 +44,14 @@ public abstract class CoreExtensionsInstaller { private final CoreExtensionRepository coreExtensionRepository; private final Class supportedAnnotationType; + public static Predicate noExtensionFilter() { + return t -> true; + } + + public static Predicate noAdditionalSideFilter() { + return t -> true; + } + protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository, Class supportedAnnotationType) { this.sonarRuntime = sonarRuntime; @@ -51,18 +59,25 @@ public abstract class CoreExtensionsInstaller { this.supportedAnnotationType = supportedAnnotationType; } - public void install(ComponentContainer container, Predicate extensionFilter) { + /** + * @param container the container into which extensions will be installed + * @param extensionFilter filters extensions added to {@link CoreExtension.Context}. When it returns false, the + * extension is ignored as if it had never been added to the context. + * @param additionalSideFilter applied on top of filtering on {@link #supportedAnnotationType} to decide whether + * extension should be added to container as an object or only as a PropertyDefinition. + */ + public void install(ComponentContainer container, Predicate extensionFilter, Predicate additionalSideFilter) { coreExtensionRepository.loadedCoreExtensions() - .forEach(coreExtension -> install(container, extensionFilter, coreExtension)); + .forEach(coreExtension -> install(container, extensionFilter, additionalSideFilter, coreExtension)); } - private void install(ComponentContainer container, Predicate extensionFilter, CoreExtension coreExtension) { + private void install(ComponentContainer container, Predicate extensionFilter, Predicate additionalSideFilter, CoreExtension coreExtension) { String coreExtensionName = coreExtension.getName(); try { - List providerKeys = addDeclaredExtensions(container, extensionFilter, coreExtension); - addProvidedExtensions(container, extensionFilter, coreExtensionName, providerKeys); + List providerKeys = addDeclaredExtensions(container, extensionFilter, additionalSideFilter, coreExtension); + addProvidedExtensions(container, additionalSideFilter, coreExtensionName, providerKeys); - LOG.info("Installed core extension: " + coreExtensionName); + LOG.debug("Installed core extension: " + coreExtensionName); coreExtensionRepository.installed(coreExtension); } catch (Exception e) { throw new RuntimeException("Failed to load core extension " + coreExtensionName, e); @@ -70,36 +85,36 @@ public abstract class CoreExtensionsInstaller { } private List addDeclaredExtensions(ComponentContainer container, Predicate extensionFilter, - CoreExtension coreExtension) { - ContextImpl context = new ContextImpl(container, extensionFilter, coreExtension.getName()); + Predicate additionalSideFilter, CoreExtension coreExtension) { + ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName()); coreExtension.load(context); return context.getProviders(); } - private void addProvidedExtensions(ComponentContainer container, Predicate extensionFilter, + private void addProvidedExtensions(ComponentContainer container, Predicate additionalSideFilter, String extensionCategory, List providerKeys) { providerKeys.stream() .map(providerKey -> (ExtensionProvider) container.getComponentByKey(providerKey)) - .forEach(provider -> addFromProvider(container, extensionFilter, extensionCategory, provider)); + .forEach(provider -> addFromProvider(container, additionalSideFilter, extensionCategory, provider)); } - private void addFromProvider(ComponentContainer container, Predicate extensionFilter, + private void addFromProvider(ComponentContainer container, Predicate additionalSideFilter, String extensionCategory, ExtensionProvider provider) { Object obj = provider.provide(); if (obj != null) { if (obj instanceof Iterable) { for (Object ext : (Iterable) obj) { - addSupportedExtension(container, extensionFilter, extensionCategory, ext); + addSupportedExtension(container, additionalSideFilter, extensionCategory, ext); } } else { - addSupportedExtension(container, extensionFilter, extensionCategory, obj); + addSupportedExtension(container, additionalSideFilter, extensionCategory, obj); } } } - private boolean addSupportedExtension(ComponentContainer container, Predicate extensionFilter, + private boolean addSupportedExtension(ComponentContainer container, Predicate additionalSideFilter, String extensionCategory, T component) { - if (hasSupportedAnnotation(component) && extensionFilter.test(component)) { + if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) { container.addExtension(extensionCategory, component); return true; } @@ -113,12 +128,15 @@ public abstract class CoreExtensionsInstaller { private class ContextImpl implements CoreExtension.Context { private final ComponentContainer container; private final Predicate extensionFilter; + private final Predicate additionalSideFilter; private final String extensionCategory; private final List providers = new ArrayList<>(); - public ContextImpl(ComponentContainer container, Predicate extensionFilter, String extensionCategory) { + public ContextImpl(ComponentContainer container, Predicate extensionFilter, + Predicate additionalSideFilter, String extensionCategory) { this.container = container; this.extensionFilter = extensionFilter; + this.additionalSideFilter = additionalSideFilter; this.extensionCategory = extensionCategory; } @@ -136,8 +154,11 @@ public abstract class CoreExtensionsInstaller { @Override public CoreExtension.Context addExtension(Object component) { requireNonNull(component, "component can't be null"); + if (!extensionFilter.test(component)) { + return this; + } - if (!addSupportedExtension(container, extensionFilter, extensionCategory, component)) { + if (!addSupportedExtension(container, additionalSideFilter, extensionCategory, component)) { container.declareExtension(extensionCategory, component); } else if (ExtensionProviderSupport.isExtensionProvider(component)) { providers.add(component); diff --git a/sonar-core/src/main/java/org/sonar/core/extension/PlatformLevel.java b/sonar-core/src/main/java/org/sonar/core/extension/PlatformLevel.java index 6396deac9fe..60f81b16324 100644 --- a/sonar-core/src/main/java/org/sonar/core/extension/PlatformLevel.java +++ b/sonar-core/src/main/java/org/sonar/core/extension/PlatformLevel.java @@ -1,3 +1,22 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ package org.sonar.core.extension; import java.lang.annotation.Documented; @@ -10,5 +29,8 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface PlatformLevel { + /** + * Supported values are: 1, 2, 3 and 4. + */ int value() default 4; } diff --git a/sonar-core/src/main/java/org/sonar/core/extension/PlatformLevelPredicates.java b/sonar-core/src/main/java/org/sonar/core/extension/PlatformLevelPredicates.java index bda0f9cfcbc..c3f5479b17c 100644 --- a/sonar-core/src/main/java/org/sonar/core/extension/PlatformLevelPredicates.java +++ b/sonar-core/src/main/java/org/sonar/core/extension/PlatformLevelPredicates.java @@ -1,4 +1,68 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ package org.sonar.core.extension; -public class PlatformLevelPredicates { +import java.util.function.Predicate; +import javax.annotation.Nullable; +import org.sonar.api.utils.AnnotationUtils; + +public final class PlatformLevelPredicates { + private PlatformLevelPredicates() { + // prevents instantiation + } + + public static Predicate hasPlatformLevel(int i) { + checkSupportedLevel(i, null); + return o -> { + PlatformLevel platformLevel = AnnotationUtils.getAnnotation(o, PlatformLevel.class); + return platformLevel != null && checkSupportedLevel(platformLevel.value(), o) == i; + }; + } + + private static int checkSupportedLevel(int i, @Nullable Object annotatedObject) { + boolean supported = i >= 1 && i <= 4; + if (supported) { + return i; + } + + throw new IllegalArgumentException(buildErrorMsgFrom(annotatedObject)); + } + + private static String buildErrorMsgFrom(@Nullable Object annotatedObject) { + String baseErrorMsg = "Only level 1, 2, 3 and 4 are supported"; + if (annotatedObject == null) { + return baseErrorMsg; + } else if (annotatedObject instanceof Class) { + return String.format("Invalid value for annotation %s on class '%s'. %s", + PlatformLevel.class.getName(), ((Class) annotatedObject).getName(), + baseErrorMsg); + } else { + return String.format("Invalid value for annotation %s on object of type %s. %s", + PlatformLevel.class.getName(), annotatedObject.getClass().getName(), baseErrorMsg); + } + } + + public static Predicate hasPlatformLevel4OrNone() { + return o -> { + PlatformLevel platformLevel = AnnotationUtils.getAnnotation(o, PlatformLevel.class); + return platformLevel == null || checkSupportedLevel(platformLevel.value(), o) == 4; + }; + } } diff --git a/sonar-core/src/test/java/org/sonar/core/extension/CoreExtensionsInstallerTest.java b/sonar-core/src/test/java/org/sonar/core/extension/CoreExtensionsInstallerTest.java index d9d03370863..aa63f2a0d32 100644 --- a/sonar-core/src/test/java/org/sonar/core/extension/CoreExtensionsInstallerTest.java +++ b/sonar-core/src/test/java/org/sonar/core/extension/CoreExtensionsInstallerTest.java @@ -55,6 +55,8 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter; import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER; @RunWith(DataProviderRunner.class) @@ -72,7 +74,7 @@ public class CoreExtensionsInstallerTest { public void install_has_no_effect_if_CoreExtensionRepository_has_no_loaded_CoreExtension() { ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); assertAddedExtensions(container, 0); } @@ -88,7 +90,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(coreExtensions.stream()); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); inOrder.verify(coreExtension1).load(contextCaptor.capture()); inOrder.verify(coreExtension2).load(contextCaptor.capture()); @@ -106,7 +108,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension1, coreExtension2)); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); verify(coreExtension1).load(contextCaptor.capture()); verify(coreExtension2).load(contextCaptor.capture()); @@ -122,7 +124,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension1, coreExtension2)); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); verify(coreExtension1).load(contextCaptor.capture()); verify(coreExtension2).load(contextCaptor.capture()); @@ -140,7 +142,7 @@ public class CoreExtensionsInstallerTest { ComponentContainer container = new ComponentContainer(); container.add(configuration); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); verify(coreExtension1).load(contextCaptor.capture()); verify(coreExtension2).load(contextCaptor.capture()); @@ -157,7 +159,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension)); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); assertAddedExtensions(container, WestSideClass.class, Latitude.class); assertPropertyDefinitions(container); @@ -171,7 +173,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension)); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> t != Latitude.class); + underTest.install(container, noExtensionFilter(), t -> t != Latitude.class); assertAddedExtensions(container, WestSideClass.class); assertPropertyDefinitions(container); @@ -186,7 +188,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension)); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); assertAddedExtensions(container, WestSidePropertyDefinition.class, LatitudePropertyDefinition.class); assertPropertyDefinitions(container, "westKey", "eastKey", "otherKey", "latitudeKey", "blankKey"); @@ -201,7 +203,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension)); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> false); + underTest.install(container, noExtensionFilter(), t -> false); assertAddedExtensions(container, 0); assertPropertyDefinitions(container, "westKey", "eastKey", "otherKey", "latitudeKey", "blankKey"); @@ -217,7 +219,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension)); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); assertAddedExtensions(container, 0); assertPropertyDefinitions(container, coreExtension, propertyDefinitionNoCategory, propertyDefinitionWithCategory); @@ -231,7 +233,7 @@ public class CoreExtensionsInstallerTest { when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension)); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); assertAddedExtensions(container, WestSideProvider.class, WestSideProvided.class, PartiallyWestSideProvider.class); assertPropertyDefinitions(container); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java index 2d55e97cd1a..55a02047280 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java @@ -73,6 +73,7 @@ import org.sonar.scanner.source.HighlightableBuilder; import org.sonar.scanner.source.SymbolizableBuilder; import static org.sonar.api.batch.InstantiationStrategy.PER_PROJECT; +import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter; import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide; @@ -169,7 +170,7 @@ public class ModuleScanContainer extends ComponentContainer { private void addExtensions() { CoreExtensionsInstaller coreExtensionsInstaller = getComponentByType(CoreExtensionsInstaller.class); - coreExtensionsInstaller.install(this, t -> isInstantiationStrategy(t, PER_PROJECT)); + coreExtensionsInstaller.install(this, noExtensionFilter(), t -> isInstantiationStrategy(t, PER_PROJECT)); ExtensionInstaller pluginInstaller = getComponentByType(ExtensionInstaller.class); pluginInstaller.install(this, e -> isScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT)); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java index 1ed39274eba..1fc6984136c 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java @@ -102,6 +102,7 @@ import org.sonar.scanner.scm.ScmChangedFilesProvider; import org.sonar.scanner.storage.Storages; import static org.sonar.api.batch.InstantiationStrategy.PER_BATCH; +import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter; import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide; @@ -242,7 +243,7 @@ public class ProjectScanContainer extends ComponentContainer { private void addBatchExtensions() { getComponentByType(CoreExtensionsInstaller.class) - .install(this, extension -> isInstantiationStrategy(extension, PER_BATCH)); + .install(this, noExtensionFilter(), extension -> isInstantiationStrategy(extension, PER_BATCH)); getComponentByType(ExtensionInstaller.class) .install(this, getBatchPluginExtensionsFilter()); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/task/TaskContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/task/TaskContainer.java index 1d0c943aef1..3338e8e823a 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/task/TaskContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/task/TaskContainer.java @@ -31,6 +31,7 @@ import org.sonar.scanner.bootstrap.ExtensionInstaller; import org.sonar.scanner.bootstrap.GlobalProperties; import static org.sonar.api.batch.InstantiationStrategy.PER_TASK; +import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter; import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide; @@ -60,7 +61,7 @@ public class TaskContainer extends ComponentContainer { private void addTaskExtensions() { getComponentByType(CoreExtensionsInstaller.class) - .install(this, t -> isInstantiationStrategy(t, PER_TASK)); + .install(this, noExtensionFilter(), t -> isInstantiationStrategy(t, PER_TASK)); getComponentByType(ExtensionInstaller.class) .install(this, extension -> isScannerSide(extension) && isInstantiationStrategy(extension, PER_TASK)); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/extension/ScannerCoreExtensionsInstallerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/extension/ScannerCoreExtensionsInstallerTest.java index a359ba30967..ef8e27eba67 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/extension/ScannerCoreExtensionsInstallerTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/extension/ScannerCoreExtensionsInstallerTest.java @@ -37,6 +37,8 @@ import org.sonar.core.platform.ComponentContainer; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter; +import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter; public class ScannerCoreExtensionsInstallerTest { private SonarRuntime sonarRuntime = mock(SonarRuntime.class); @@ -61,7 +63,7 @@ public class ScannerCoreExtensionsInstallerTest { })); ComponentContainer container = new ComponentContainer(); - underTest.install(container, t -> true); + underTest.install(container, noExtensionFilter(), noAdditionalSideFilter()); assertThat(container.getPicoContainer().getComponentAdapters()) .hasSize(ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2); -- 2.39.5