@@ -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, | |||
@@ -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 |
@@ -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); |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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<Object> 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); | |||
@@ -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); |
@@ -44,6 +44,14 @@ public abstract class CoreExtensionsInstaller { | |||
private final CoreExtensionRepository coreExtensionRepository; | |||
private final Class<? extends Annotation> supportedAnnotationType; | |||
public static Predicate<Object> noExtensionFilter() { | |||
return t -> true; | |||
} | |||
public static Predicate<Object> noAdditionalSideFilter() { | |||
return t -> true; | |||
} | |||
protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository, | |||
Class<? extends Annotation> supportedAnnotationType) { | |||
this.sonarRuntime = sonarRuntime; | |||
@@ -51,18 +59,25 @@ public abstract class CoreExtensionsInstaller { | |||
this.supportedAnnotationType = supportedAnnotationType; | |||
} | |||
public void install(ComponentContainer container, Predicate<Object> 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<Object> extensionFilter, Predicate<Object> additionalSideFilter) { | |||
coreExtensionRepository.loadedCoreExtensions() | |||
.forEach(coreExtension -> install(container, extensionFilter, coreExtension)); | |||
.forEach(coreExtension -> install(container, extensionFilter, additionalSideFilter, coreExtension)); | |||
} | |||
private void install(ComponentContainer container, Predicate<Object> extensionFilter, CoreExtension coreExtension) { | |||
private void install(ComponentContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) { | |||
String coreExtensionName = coreExtension.getName(); | |||
try { | |||
List<Object> providerKeys = addDeclaredExtensions(container, extensionFilter, coreExtension); | |||
addProvidedExtensions(container, extensionFilter, coreExtensionName, providerKeys); | |||
List<Object> 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<Object> addDeclaredExtensions(ComponentContainer container, Predicate<Object> extensionFilter, | |||
CoreExtension coreExtension) { | |||
ContextImpl context = new ContextImpl(container, extensionFilter, coreExtension.getName()); | |||
Predicate<Object> additionalSideFilter, CoreExtension coreExtension) { | |||
ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName()); | |||
coreExtension.load(context); | |||
return context.getProviders(); | |||
} | |||
private void addProvidedExtensions(ComponentContainer container, Predicate<Object> extensionFilter, | |||
private void addProvidedExtensions(ComponentContainer container, Predicate<Object> additionalSideFilter, | |||
String extensionCategory, List<Object> 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<Object> extensionFilter, | |||
private void addFromProvider(ComponentContainer container, Predicate<Object> 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 <T> boolean addSupportedExtension(ComponentContainer container, Predicate<Object> extensionFilter, | |||
private <T> boolean addSupportedExtension(ComponentContainer container, Predicate<Object> 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<Object> extensionFilter; | |||
private final Predicate<Object> additionalSideFilter; | |||
private final String extensionCategory; | |||
private final List<Object> providers = new ArrayList<>(); | |||
public ContextImpl(ComponentContainer container, Predicate<Object> extensionFilter, String extensionCategory) { | |||
public ContextImpl(ComponentContainer container, Predicate<Object> extensionFilter, | |||
Predicate<Object> 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); |
@@ -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; | |||
} |
@@ -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<Object> 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<Object> hasPlatformLevel4OrNone() { | |||
return o -> { | |||
PlatformLevel platformLevel = AnnotationUtils.getAnnotation(o, PlatformLevel.class); | |||
return platformLevel == null || checkSupportedLevel(platformLevel.value(), o) == 4; | |||
}; | |||
} | |||
} |
@@ -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); |
@@ -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)); | |||
} |
@@ -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()); | |||
} |
@@ -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)); | |||
} |
@@ -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); |