]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-15966 Use Spring instead of Pico as dependency injection framework in the scann...
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 5 Jan 2022 22:17:09 +0000 (16:17 -0600)
committersonartech <sonartech@sonarsource.com>
Wed, 2 Feb 2022 20:02:54 +0000 (20:02 +0000)
Co-authored-by: Zipeng WU <zipeng.wu@sonarsource.com>
108 files changed:
build.gradle
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/AbstractComputationSteps.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskProcessor.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/IssueSyncTaskProcessor.java
server/sonar-ce-task/src/main/java/org/sonar/ce/task/container/TaskContainer.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationContainer.java
sonar-core/build.gradle
sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsInstaller.java
sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsLoader.java
sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java
sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java
sonar-core/src/main/java/org/sonar/core/platform/ComponentKeys.java
sonar-core/src/main/java/org/sonar/core/platform/Container.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/ContainerPopulator.java
sonar-core/src/main/java/org/sonar/core/platform/ExtensionContainer.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java
sonar-plugin-api-impl/src/main/java/org/sonar/api/impl/utils/DefaultTempFolder.java
sonar-plugin-api/src/test/java/org/sonar/api/resources/LanguagesTest.java
sonar-scanner-engine/build.gradle
sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/Batch.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectInfo.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionary.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ClassDerivedBeanDefinition.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ExtensionInstaller.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalConfigurationProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalServerSettingsProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalTempFolderProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessor.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PluginFiles.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionary.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PriorityBeanFactory.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerPluginRepository.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerWsClientProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringComponentContainer.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessor.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisObserver.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisObservers.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisResult.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/FakePluginInstaller.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/MetricsRepositoryProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesRepository.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoader.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/RulesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputModuleHierarchyProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputProjectProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/LanguagesProvider.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleConfigurationProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableModuleSettings.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableProjectReactorProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableProjectSettings.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectBuildersExecutor.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectConfigurationProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectLock.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectServerSettingsProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringModuleScanContainer.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringProjectScanContainer.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoriesInitializer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/BranchConfigurationProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/ProjectBranchesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/ProjectPullRequestsProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultModuleFileSystem.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultProjectFileSystem.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmConfiguration.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorContext.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionary.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionary.java
sonar-scanner-engine/src/main/resources/org/sonar/batch/bootstrapper/logback.xml
sonar-scanner-engine/src/main/resources/org/sonar/batch/logback.xml
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalContainerTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessorTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionaryTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PriorityBeanFactoryTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerWsClientProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringComponentContainerTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringGlobalContainerTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessorTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/NoLanguagesPluginsMediumTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/log/ExceptionHandlingMediumTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectScanContainerTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/SpringProjectScanContainerTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoriesInitializerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/branch/BranchConfigurationProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/branch/ProjectBranchesProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/branch/ProjectPullRequestsProviderTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scm/ScmChangedFilesProviderTest.java

index b34e90e9150bfdf16bd6434ef516e8ca15adc8a3..36d1474a37d141511db9e750e0782e4bb84c32c7 100644 (file)
@@ -350,6 +350,7 @@ subprojects {
       dependency 'io.netty:netty-all:4.1.70.Final'
       dependency 'com.sun.mail:javax.mail:1.5.6'
       dependency 'javax.annotation:javax.annotation-api:1.3.2'
+      dependency 'javax.inject:javax.inject:1'
       dependency 'javax.servlet:javax.servlet-api:3.1.0'
       dependency 'javax.xml.bind:jaxb-api:2.3.0'
       dependency 'junit:junit:4.13.2'
@@ -417,6 +418,9 @@ subprojects {
       dependency 'org.simpleframework:simple:4.1.21'
       dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.36.0.63'
       dependency 'org.sonarsource.update-center:sonar-update-center-common:1.23.0.723'
+      dependency('org.springframework:spring-context:5.3.14') {
+        exclude 'commons-logging:commons-logging'
+      }
       dependency 'org.subethamail:subethasmtp:3.1.7'
       dependency 'org.yaml:snakeyaml:1.26'
       dependency 'xml-apis:xml-apis:1.4.01'
index cb64a402b53a550e58c79a535e84ca4dd4a51368..ad981b68bba6038bdeaa5353ad6095b72b2dedcf 100644 (file)
@@ -22,16 +22,16 @@ package org.sonar.ce.task.projectanalysis.step;
 import com.google.common.collect.Iterables;
 import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.ce.task.step.ComputationSteps;
-import org.sonar.core.platform.ContainerPopulator;
+import org.sonar.core.platform.Container;
 
 /**
  * Abstract implementation of {@link ComputationStep} which provides the implementation of {@link ComputationSteps#instances()}
- * based on a {@link org.sonar.core.platform.ContainerPopulator.Container}.
+ * based on a {@link org.sonar.core.platform.Container}.
  */
 public abstract class AbstractComputationSteps implements ComputationSteps {
-  private final ContainerPopulator.Container container;
+  private final Container container;
 
-  protected AbstractComputationSteps(ContainerPopulator.Container container) {
+  protected AbstractComputationSteps(Container container) {
     this.container = container;
   }
 
index 60102c1f78b22fba7592d437c12032204ffe1fcb..be26b4774f47a37b47fae5f9d21d60bc6a3cc707 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.ce.task.step.ComputationStepExecutor;
 import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
 import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.Container;
 import org.sonar.core.platform.ContainerPopulator;
 
 import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE;
@@ -72,7 +73,7 @@ public class AuditPurgeTaskProcessor implements CeTaskProcessor {
 
   public static final class AuditPurgeComputationSteps extends AbstractComputationSteps {
 
-    public AuditPurgeComputationSteps(ContainerPopulator.Container container) {
+    public AuditPurgeComputationSteps(Container container) {
       super(container);
     }
 
index dcfb9781714d1b1f9c8fc2cfa8a5f38896cd299e..29879730aa93ee0fe83ce52e3c88eaeb6bcffdc9 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.ce.task.step.ComputationStepExecutor;
 import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
 import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.Container;
 import org.sonar.core.platform.ContainerPopulator;
 
 import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC;
@@ -73,7 +74,7 @@ public class IssueSyncTaskProcessor implements CeTaskProcessor {
 
   public static final class SyncComputationSteps extends AbstractComputationSteps {
 
-    public SyncComputationSteps(ContainerPopulator.Container container) {
+    public SyncComputationSteps(Container container) {
       super(container);
     }
 
index 7c3086ef4b452a4868b01da445bdee573b54a1c3..2a3979f1c7f8f74d39dedff6be93ad588c5053d1 100644 (file)
@@ -22,12 +22,12 @@ package org.sonar.ce.task.container;
 import org.picocontainer.PicoContainer;
 import org.sonar.ce.task.CeTask;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.core.platform.ContainerPopulator;
+import org.sonar.core.platform.Container;
 
 /**
  * The Compute Engine task container. Created for a specific parent {@link ComponentContainer} and a specific {@link CeTask}.
  */
-public interface TaskContainer extends ContainerPopulator.Container, AutoCloseable {
+public interface TaskContainer extends Container, AutoCloseable {
 
   ComponentContainer getParent();
 
index f8bd5ac6084d6599237553da250b07e98d6f954c..c21a6cdf7942e6f16694256337f9a27fd5d83cd1 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.platform.db.migration.engine;
 
-import org.sonar.core.platform.ContainerPopulator;
+import org.sonar.core.platform.Container;
 
 /**
  * A dedicated container used to run DB migrations where all components are lazily instantiated.
@@ -32,7 +32,7 @@ import org.sonar.core.platform.ContainerPopulator;
  *   classes only they really are to be executed.
  * </p>
  */
-public interface MigrationContainer extends ContainerPopulator.Container {
+public interface MigrationContainer extends Container {
 
   /**
    * Cleans up resources after migration has run.
index 3b658b278c9a426bfa90bd0137f3db5d1d81956e..3141d504391a47ea3c3a24cb1c9130386c8e095d 100644 (file)
@@ -16,10 +16,12 @@ dependencies {
   compile 'commons-codec:commons-codec'
   compile 'commons-io:commons-io'
   compile 'commons-lang:commons-lang'
+  compile 'javax.inject:javax.inject'
   compile 'org.codehaus.sonar:sonar-classloader'
   compile 'org.picocontainer:picocontainer'
   compile 'org.slf4j:slf4j-api'
   compile 'org.sonarsource.update-center:sonar-update-center-common'
+  compile 'org.springframework:spring-context'
   compile project(path: ':sonar-plugin-api', configuration: 'shadow')
   compile project(':sonar-plugin-api-impl')
 
index f921ac2abc60bfddcd034f5e107ad035db6f9a38..bae7811e1601168e670f04517913d060e2387370 100644 (file)
@@ -30,7 +30,7 @@ import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.utils.AnnotationUtils;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 
 import static java.util.Objects.requireNonNull;
 
@@ -41,8 +41,7 @@ public abstract class CoreExtensionsInstaller {
   private final CoreExtensionRepository coreExtensionRepository;
   private final Class<? extends Annotation> supportedAnnotationType;
 
-  protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository,
-    Class<? extends Annotation> supportedAnnotationType) {
+  protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository, Class<? extends Annotation> supportedAnnotationType) {
     this.sonarRuntime = sonarRuntime;
     this.coreExtensionRepository = coreExtensionRepository;
     this.supportedAnnotationType = supportedAnnotationType;
@@ -63,12 +62,12 @@ public abstract class CoreExtensionsInstaller {
    * @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) {
+  public void install(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter) {
     coreExtensionRepository.loadedCoreExtensions()
       .forEach(coreExtension -> install(container, extensionFilter, additionalSideFilter, coreExtension));
   }
 
-  private void install(ComponentContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
+  private void install(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
     String coreExtensionName = coreExtension.getName();
     try {
       addDeclaredExtensions(container, extensionFilter, additionalSideFilter, coreExtension);
@@ -80,33 +79,23 @@ public abstract class CoreExtensionsInstaller {
     }
   }
 
-  private void addDeclaredExtensions(ComponentContainer container, Predicate<Object> extensionFilter,
+  private void addDeclaredExtensions(ExtensionContainer container, Predicate<Object> extensionFilter,
     Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
     ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName());
     coreExtension.load(context);
   }
 
-  private <T> boolean addSupportedExtension(ComponentContainer container, Predicate<Object> additionalSideFilter,
-    String extensionCategory, T component) {
-    if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) {
-      container.addExtension(extensionCategory, component);
-      return true;
-    }
-    return false;
-  }
-
   private <T> boolean hasSupportedAnnotation(T component) {
     return AnnotationUtils.getAnnotation(component, supportedAnnotationType) != null;
   }
 
   private class ContextImpl implements CoreExtension.Context {
-    private final ComponentContainer container;
+    private final ExtensionContainer container;
     private final Predicate<Object> extensionFilter;
     private final Predicate<Object> additionalSideFilter;
     private final String extensionCategory;
 
-    public ContextImpl(ComponentContainer container, Predicate<Object> extensionFilter,
-      Predicate<Object> additionalSideFilter, String extensionCategory) {
+    public ContextImpl(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, String extensionCategory) {
       this.container = container;
       this.extensionFilter = extensionFilter;
       this.additionalSideFilter = additionalSideFilter;
@@ -150,5 +139,14 @@ public abstract class CoreExtensionsInstaller {
       components.forEach(this::addExtension);
       return this;
     }
+
+    private <T> boolean addSupportedExtension(ExtensionContainer container, Predicate<Object> additionalSideFilter,
+      String extensionCategory, T component) {
+      if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) {
+        container.addExtension(extensionCategory, component);
+        return true;
+      }
+      return false;
+    }
   }
 }
index 0109f30d3571485188ce2c2431e4aac10c7afc2b..3791f99664047270917862b438f0f7fc77579fc9 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.core.extension;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
+import javax.inject.Inject;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.util.stream.MoreCollectors;
@@ -37,6 +38,7 @@ public class CoreExtensionsLoader {
   private final CoreExtensionRepository coreExtensionRepository;
   private final ServiceLoaderWrapper serviceLoaderWrapper;
 
+  @Inject
   public CoreExtensionsLoader(CoreExtensionRepository coreExtensionRepository) {
     this(coreExtensionRepository, new ServiceLoaderWrapper());
   }
index 4ca313de25c44a258a59a9ae8394b2f2e6c4844a..4057b9ad1d5a851d5a04a0fdc2715c494305b689 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.measures.Metrics;
 import org.sonar.api.scanner.ScannerSide;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static org.sonar.api.measures.CoreMetrics.CLASSES;
 import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY;
@@ -96,10 +97,12 @@ public class ScannerMetrics {
 
   private final Set<Metric> metrics;
 
+  @Autowired(required = false)
   public ScannerMetrics() {
     this.metrics = ALLOWED_CORE_METRICS;
   }
 
+  @Autowired(required = false)
   public ScannerMetrics(Metrics[] metricsRepositories) {
     this.metrics = Stream.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS.stream()).collect(toSet());
   }
index 269ac851746bd4c7e5ca664e33defc2674945ff4..b8d7c56b31064e6a2931c8059fcb3f6812e35cc9 100644 (file)
@@ -49,7 +49,7 @@ import static java.util.Optional.ofNullable;
 @ScannerSide
 @ServerSide
 @ComputeEngineSide
-public class ComponentContainer implements ContainerPopulator.Container {
+public class ComponentContainer implements ExtensionContainer {
   public static final int COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER = 2;
 
   private static final class ExtendedDefaultPicoContainer extends DefaultPicoContainer {
@@ -235,6 +235,7 @@ public class ComponentContainer implements ContainerPopulator.Container {
     return this;
   }
 
+  @Override
   public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) {
     Object key = componentKeys.of(extension);
     try {
@@ -246,6 +247,7 @@ public class ComponentContainer implements ContainerPopulator.Container {
     return this;
   }
 
+  @Override
   public ComponentContainer addExtension(@Nullable String defaultCategory, Object extension) {
     Object key = componentKeys.of(extension);
     try {
@@ -264,12 +266,16 @@ public class ComponentContainer implements ContainerPopulator.Container {
     return getName(extension.getClass());
   }
 
-  public void declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+  @Override
+  public ComponentContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
     declareExtension(pluginInfo != null ? pluginInfo.getName() : "", extension);
+    return this;
   }
 
-  public void declareExtension(@Nullable String defaultCategory, Object extension) {
+  @Override
+  public ComponentContainer declareExtension(@Nullable String defaultCategory, Object extension) {
     propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse(""));
+    return this;
   }
 
   public ComponentContainer addPicoAdapter(ComponentAdapter<?> adapter) {
index 7cb156b91bd32b6e16dc876a4cf66772e5f0e61e..81a1b822b9da14bcc84d9b986ff564f069ff97e8 100644 (file)
@@ -26,19 +26,27 @@ import org.sonar.core.util.Uuids;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 
-class ComponentKeys {
-
+public class ComponentKeys {
+  private static final Logger LOG = Loggers.get(ComponentKeys.class);
   private static final Pattern IDENTITY_HASH_PATTERN = Pattern.compile(".+@[a-f0-9]+");
   private final Set<Class> objectsWithoutToString = new HashSet<>();
 
   Object of(Object component) {
-    return of(component, Loggers.get(ComponentKeys.class));
+    return of(component, LOG);
   }
 
   Object of(Object component, Logger log) {
     if (component instanceof Class) {
       return component;
     }
+    return ofInstance(component, log);
+  }
+
+  public String ofInstance(Object component) {
+    return ofInstance(component, LOG);
+  }
+
+  String ofInstance(Object component, Logger log) {
     String key = component.toString();
     if (IDENTITY_HASH_PATTERN.matcher(key).matches()) {
       if (!objectsWithoutToString.add(component.getClass())) {
@@ -46,6 +54,6 @@ class ComponentKeys {
       }
       key += Uuids.create();
     }
-    return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(key).toString();
+    return component.getClass().getCanonicalName() + "-" + key;
   }
 }
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/Container.java b/sonar-core/src/main/java/org/sonar/core/platform/Container.java
new file mode 100644 (file)
index 0000000..e7a9963
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.platform;
+
+import java.util.List;
+
+public interface Container {
+  Container add(Object... objects);
+
+  Container addSingletons(Iterable<?> components);
+
+  <T> T getComponentByType(Class<T> type);
+
+  <T> List<T> getComponentsByType(Class<T> type);
+
+  Container getParent();
+}
index c582cfead3f84cf6d44d45741ef40d7b01924d51..f5a6fe46be5122e53f2deb35538e4cfe2d819347 100644 (file)
  */
 package org.sonar.core.platform;
 
-import java.util.List;
-
 @FunctionalInterface
-public interface ContainerPopulator<T extends ContainerPopulator.Container> {
+public interface ContainerPopulator<T extends Container> {
   void populateContainer(T container);
-
-  interface Container {
-    Container add(Object... objects);
-
-    Container addSingletons(Iterable<?> components);
-
-    <T> T getComponentByType(Class<T> type);
-
-    <T> List<T> getComponentsByType(Class<T> type);
-  }
 }
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/ExtensionContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/ExtensionContainer.java
new file mode 100644 (file)
index 0000000..0bf9457
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.platform;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public interface ExtensionContainer extends Container {
+  ExtensionContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension);
+
+  ExtensionContainer addExtension(@Nullable String defaultCategory, Object extension);
+
+  ExtensionContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension);
+
+  ExtensionContainer declareExtension(@Nullable String defaultCategory, Object extension);
+
+  @CheckForNull
+  ExtensionContainer getParent();
+}
index 9fea2f6f74b64dd076709df2d2aed7400707f64f..93f12376c929f6805d928230db413a0d50e1af8e 100644 (file)
@@ -39,6 +39,7 @@ import java.util.List;
 import java.util.Optional;
 import java.util.zip.GZIPInputStream;
 import javax.annotation.Nullable;
+import javax.inject.Inject;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
 import org.sonar.api.CoreProperties;
@@ -62,6 +63,7 @@ public class DefaultHttpDownloader extends HttpDownloader {
   private final Integer readTimeout;
   private final Integer connectTimeout;
 
+  @Inject
   public DefaultHttpDownloader(Server server, Configuration config) {
     this(server, config, null);
   }
index dad6280f08e4114f33146a37165b3ea5f7e67e3e..15cba78e2e100e8506f18c2cf7ae7752707b9857 100644 (file)
@@ -23,6 +23,7 @@ import java.nio.file.FileVisitResult;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import org.apache.commons.io.FileUtils;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.TempFolder;
 
 import javax.annotation.Nullable;
@@ -34,7 +35,7 @@ import java.nio.file.Path;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 
-public class DefaultTempFolder implements TempFolder {
+public class DefaultTempFolder implements TempFolder, Startable {
   private static final Logger LOG = Loggers.get(DefaultTempFolder.class);
 
   private final File tempDir;
@@ -101,6 +102,12 @@ public class DefaultTempFolder implements TempFolder {
     }
   }
 
+  @Override
+  public void start() {
+    // nothing to do
+  }
+
+  @Override
   public void stop() {
     if (deleteOnExit) {
       clean();
index 7df44279de2facc025f0520772a3b6076eed3ee1..5b8fb2a8f495c13f34496ae805cd5d68a1e2ff8f 100644 (file)
@@ -29,8 +29,8 @@ public class LanguagesTest {
   @Test
   public void should_add_several_times_the_same_language() {
     Languages languages = new Languages(
-        language("fake"),
-        language("fake"));
+      language("fake"),
+      language("fake"));
 
     assertThat(languages.get("fake").getKey()).isEqualTo("fake");
   }
@@ -38,8 +38,8 @@ public class LanguagesTest {
   @Test
   public void should_get_suffixes() {
     Languages languages = new Languages(
-        language("java", "java"),
-        language("php", "php4", "php5"));
+      language("java", "java"),
+      language("php", "php4", "php5"));
 
     assertThat(languages.getSuffixes()).containsOnly("java", "php4", "php5");
     assertThat(languages.getSuffixes("java")).containsOnly("java");
index 5afaba8d774ecc5966864db3f14c689dde47b43b..f3fa9ffdad96c3448ce26dadfe3a6c6fa705532f 100644 (file)
@@ -26,6 +26,7 @@ dependencies {
   compile 'com.google.protobuf:protobuf-java'
   compile 'com.squareup.okhttp3:okhttp'
   compile 'com.fasterxml.staxmate:staxmate'
+  compile 'javax.annotation:javax.annotation-api'
   compile 'org.eclipse.jgit:org.eclipse.jgit'
   compile 'org.tmatesoft.svnkit:svnkit'
   compile 'org.picocontainer:picocontainer'
@@ -34,6 +35,8 @@ dependencies {
   compile 'org.slf4j:log4j-over-slf4j'
   compile 'org.slf4j:slf4j-api'
   compile 'org.sonarsource.update-center:sonar-update-center-common'
+  compile 'org.springframework:spring-context'
+
 
   compile project(':sonar-core')
   compile project(':sonar-scanner-protocol')
index c1a672ce590ef2b6ec6411007fe526864e7cc6ef..5d616b9e035e1e99394b5e5cb3a0e03a69c76f6b 100644 (file)
@@ -27,7 +27,7 @@ import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
 import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.bootstrap.GlobalContainer;
+import org.sonar.scanner.bootstrap.SpringGlobalContainer;
 
 /**
  * Entry point for SonarQube Scanner API 2.1+.
@@ -69,7 +69,7 @@ public final class Batch {
   public synchronized Batch doExecute(Map<String, String> scannerProperties, List<Object> components) {
     configureLogging();
     try {
-      GlobalContainer.create(scannerProperties, components).execute();
+      SpringGlobalContainer.create(scannerProperties, components).execute();
     } catch (RuntimeException e) {
       throw handleException(e);
     }
index cf130f161f2616c92c9213c889a06c2307f15640..8c7a8309fa534568ab062e5303858e2099908fe2 100644 (file)
@@ -24,8 +24,8 @@ import java.util.Date;
 import java.util.Optional;
 import java.util.function.Predicate;
 import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
 import org.sonar.api.CoreProperties;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.MessageException;
@@ -41,7 +41,7 @@ import static org.sonar.api.CoreProperties.PROJECT_VERSION_PROPERTY;
  */
 public class ProjectInfo implements Startable {
   private final Clock clock;
-  private Configuration settings;
+  private final Configuration settings;
 
   private Date analysisDate;
   private String projectVersion;
index da406611440d07bc2ff744b38e9d5fccd17213e6..753a6f3b711cd6d30a45ddf2030553bd9ce41ff8 100644 (file)
@@ -22,58 +22,25 @@ package org.sonar.scanner.analysis;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import org.picocontainer.ComponentLifecycle;
-import org.picocontainer.PicoContainer;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.impl.utils.DefaultTempFolder;
 import org.sonar.api.utils.TempFolder;
+import org.springframework.context.annotation.Bean;
 
-public class AnalysisTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
+public class AnalysisTempFolderProvider {
   static final String TMP_NAME = ".sonartmp";
-  private DefaultTempFolder projectTempFolder;
-  private boolean started = false;
 
+  @Bean("TempFolder")
   public TempFolder provide(DefaultInputProject project) {
-    if (projectTempFolder == null) {
-      Path workingDir = project.getWorkDir();
-      Path tempDir = workingDir.normalize().resolve(TMP_NAME);
-      try {
-        Files.deleteIfExists(tempDir);
-        Files.createDirectories(tempDir);
-      } catch (IOException e) {
-        throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
-      }
-
-      projectTempFolder = new DefaultTempFolder(tempDir.toFile(), true);
-    }
-    return projectTempFolder;
-  }
-
-  @Override
-  public void start(PicoContainer container) {
-    started = true;
-  }
-
-  @Override
-  public void stop(PicoContainer container) {
-    if (projectTempFolder != null) {
-      projectTempFolder.stop();
+    Path workingDir = project.getWorkDir();
+    Path tempDir = workingDir.normalize().resolve(TMP_NAME);
+    try {
+      Files.deleteIfExists(tempDir);
+      Files.createDirectories(tempDir);
+    } catch (IOException e) {
+      throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
     }
-  }
-
-  @Override
-  public void dispose(PicoContainer container) {
-    // nothing to do
-  }
-
-  @Override
-  public boolean componentHasLifecycle() {
-    return true;
-  }
 
-  @Override
-  public boolean isStarted() {
-    return started;
+    return new DefaultTempFolder(tempDir.toFile(), true);
   }
 }
index 46b79847d06f2dd7149a3999dff699854b82dd10..6a8c5071466337b8c9197952fbcbed95adf37095 100644 (file)
@@ -35,13 +35,13 @@ import org.sonar.api.batch.DependsUpon;
 import org.sonar.api.batch.Phase;
 import org.sonar.api.utils.AnnotationUtils;
 import org.sonar.api.utils.dag.DirectAcyclicGraph;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 
 public abstract class AbstractExtensionDictionary {
 
-  private final ComponentContainer componentContainer;
+  private final ExtensionContainer componentContainer;
 
-  public AbstractExtensionDictionary(ComponentContainer componentContainer) {
+  protected AbstractExtensionDictionary(ExtensionContainer componentContainer) {
     this.componentContainer = componentContainer;
   }
 
@@ -78,9 +78,9 @@ public abstract class AbstractExtensionDictionary {
     return extensions;
   }
 
-  private static <T> void completeScannerExtensions(ComponentContainer container, List<T> extensions, Class<T> type) {
+  private static <T> void completeScannerExtensions(ExtensionContainer container, List<T> extensions, Class<T> type) {
     extensions.addAll(container.getComponentsByType(type));
-    ComponentContainer parentContainer = container.getParent();
+    ExtensionContainer parentContainer = container.getParent();
     if (parentContainer != null) {
       completeScannerExtensions(parentContainer, extensions, type);
     }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ClassDerivedBeanDefinition.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ClassDerivedBeanDefinition.java
new file mode 100644 (file)
index 0000000..0743b81
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import java.lang.reflect.Constructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.lang.Nullable;
+
+/**
+ * Taken from Spring's GenericApplicationContext.ClassDerivedBeanDefinition.
+ */
+public class ClassDerivedBeanDefinition extends RootBeanDefinition {
+  public ClassDerivedBeanDefinition(Class<?> beanClass) {
+    super(beanClass);
+  }
+
+  public ClassDerivedBeanDefinition(ClassDerivedBeanDefinition original) {
+    super(original);
+  }
+
+  /**
+   * This method gets called from AbstractAutowireCapableBeanFactory#createBeanInstance when a bean is instantiated.
+   * It first tries to look at annotations or any other methods provided by bean post processors. If a constructor can't be determined, it will fallback to this method.
+   */
+  @Override
+  @Nullable
+  public Constructor<?>[] getPreferredConstructors() {
+    Class<?> clazz = getBeanClass();
+    Constructor<?> primaryCtor = BeanUtils.findPrimaryConstructor(clazz);
+    if (primaryCtor != null) {
+      return new Constructor<?>[] {primaryCtor};
+    }
+    Constructor<?>[] publicCtors = clazz.getConstructors();
+    if (publicCtors.length > 0) {
+      return publicCtors;
+    }
+    return null;
+  }
+
+  @Override
+  public RootBeanDefinition cloneBeanDefinition() {
+    return new ClassDerivedBeanDefinition(this);
+  }
+}
index ee037f90c4650803ec5f5014a97beef1e12ef353..a749bf13b84d1e22f5beb67771a523d868214e3c 100644 (file)
@@ -24,7 +24,7 @@ import org.sonar.api.Plugin;
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.internal.PluginContextImpl;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 import org.sonar.core.platform.PluginInfo;
 import org.sonar.core.platform.PluginRepository;
 
@@ -40,8 +40,7 @@ public class ExtensionInstaller {
     this.bootConfiguration = bootConfiguration;
   }
 
-  public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) {
-
+  public ExtensionInstaller install(ExtensionContainer container, ExtensionMatcher matcher) {
     // core components
     for (Object o : BatchComponents.all()) {
       doInstall(container, matcher, null, o);
@@ -64,7 +63,7 @@ public class ExtensionInstaller {
     return this;
   }
 
-  private static void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) {
+  private static void doInstall(ExtensionContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) {
     if (matcher.accept(extension)) {
       container.addExtension(pluginInfo, extension);
     } else {
index f0fb379f5b6f85855c10cfbfbbcc871b953c12c9..19070c283609471a2b8821c0d714a0231c59fe45 100644 (file)
@@ -21,15 +21,13 @@ package org.sonar.scanner.bootstrap;
 
 import java.util.Map;
 import javax.annotation.concurrent.Immutable;
-import org.sonar.api.config.internal.Encryption;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
 import org.sonar.scanner.config.DefaultConfiguration;
 
 @Immutable
 public class GlobalConfiguration extends DefaultConfiguration {
-
   public GlobalConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> settings) {
     super(propertyDefinitions, encryption, settings);
   }
-
 }
index cad8c08c36758f94f3b5e2e8c3051930eed0bba8..af1323367eed1c9ccd345d6f9c0be632fb6f97f2 100644 (file)
@@ -21,22 +21,15 @@ package org.sonar.scanner.bootstrap;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.config.PropertyDefinitions;
+import org.springframework.context.annotation.Bean;
 
-public class GlobalConfigurationProvider extends ProviderAdapter {
-
-  private GlobalConfiguration globalConfig;
-
-  public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps,
-    PropertyDefinitions propertyDefinitions) {
-    if (globalConfig == null) {
-      Map<String, String> mergedSettings = new LinkedHashMap<>();
-      mergedSettings.putAll(globalServerSettings.properties());
-      mergedSettings.putAll(scannerProps.properties());
-
-      globalConfig = new GlobalConfiguration(propertyDefinitions, scannerProps.getEncryption(), mergedSettings);
-    }
-    return globalConfig;
+public class GlobalConfigurationProvider {
+  @Bean("GlobalConfiguration")
+  public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps, PropertyDefinitions propertyDefinitions) {
+    Map<String, String> mergedSettings = new LinkedHashMap<>();
+    mergedSettings.putAll(globalServerSettings.properties());
+    mergedSettings.putAll(scannerProps.properties());
+    return new GlobalConfiguration(propertyDefinitions, scannerProps.getEncryption(), mergedSettings);
   }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java
deleted file mode 100644 (file)
index 84e3f95..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.scanner.bootstrap;
-
-import java.time.Clock;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.Plugin;
-import org.sonar.api.SonarEdition;
-import org.sonar.api.SonarQubeSide;
-import org.sonar.api.SonarQubeVersion;
-import org.sonar.api.SonarRuntime;
-import org.sonar.api.internal.MetadataLoader;
-import org.sonar.api.internal.SonarRuntimeImpl;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.UriReader;
-import org.sonar.api.utils.Version;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.extension.CoreExtensionRepositoryImpl;
-import org.sonar.core.extension.CoreExtensionsLoader;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.core.platform.PluginClassLoader;
-import org.sonar.core.platform.PluginClassloaderFactory;
-import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
-import org.sonar.core.util.DefaultHttpDownloader;
-import org.sonar.core.util.UuidFactoryImpl;
-import org.sonar.scanner.extension.ScannerCoreExtensionsInstaller;
-import org.sonar.scanner.notifications.DefaultAnalysisWarnings;
-import org.sonar.scanner.platform.DefaultServer;
-import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader;
-import org.sonar.scanner.repository.DefaultNewCodePeriodLoader;
-import org.sonar.scanner.repository.MetricsRepositoryLoader;
-import org.sonar.scanner.repository.MetricsRepositoryProvider;
-import org.sonar.scanner.repository.NewCodePeriodLoader;
-import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader;
-import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
-import org.sonar.scanner.scan.ProjectScanContainer;
-
-public class GlobalContainer extends ComponentContainer {
-  private static final Logger LOG = Loggers.get(GlobalContainer.class);
-  private final Map<String, String> scannerProperties;
-
-  private GlobalContainer(Map<String, String> scannerProperties) {
-    super();
-    this.scannerProperties = scannerProperties;
-  }
-
-  public static GlobalContainer create(Map<String, String> scannerProperties, List<?> extensions) {
-    GlobalContainer container = new GlobalContainer(scannerProperties);
-    container.add(extensions);
-    return container;
-  }
-
-  @Override
-  protected void doBeforeStart() {
-    ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties);
-    GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties);
-    add(rawScannerProperties);
-    add(globalMode);
-    addBootstrapComponents();
-  }
-
-  private void addBootstrapComponents() {
-    Version apiVersion = MetadataLoader.loadVersion(System2.INSTANCE);
-    SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE);
-    DefaultAnalysisWarnings analysisWarnings = new DefaultAnalysisWarnings(System2.INSTANCE);
-    LOG.debug("{} {}", edition.getLabel(), apiVersion);
-    add(
-      // plugins
-      ScannerPluginRepository.class,
-      PluginClassLoader.class,
-      PluginClassloaderFactory.class,
-      ScannerPluginJarExploder.class,
-      ExtensionInstaller.class,
-      new SonarQubeVersion(apiVersion),
-      new GlobalServerSettingsProvider(),
-      new GlobalConfigurationProvider(),
-      new ScannerWsClientProvider(),
-      DefaultServer.class,
-      new GlobalTempFolderProvider(),
-      DefaultHttpDownloader.class,
-      analysisWarnings,
-      UriReader.class,
-      PluginFiles.class,
-      System2.INSTANCE,
-      Clock.systemDefaultZone(),
-      new MetricsRepositoryProvider(),
-      UuidFactoryImpl.INSTANCE);
-    addIfMissing(SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition), SonarRuntime.class);
-    addIfMissing(ScannerPluginInstaller.class, PluginInstaller.class);
-    add(CoreExtensionRepositoryImpl.class, CoreExtensionsLoader.class, ScannerCoreExtensionsInstaller.class);
-    addIfMissing(DefaultGlobalSettingsLoader.class, GlobalSettingsLoader.class);
-    addIfMissing(DefaultNewCodePeriodLoader.class, NewCodePeriodLoader.class);
-    addIfMissing(DefaultMetricsRepositoryLoader.class, MetricsRepositoryLoader.class);
-  }
-
-  @Override
-  protected void doAfterStart() {
-    installPlugins();
-    loadCoreExtensions();
-
-    long startTime = System.currentTimeMillis();
-    String taskKey = StringUtils.defaultIfEmpty(scannerProperties.get(CoreProperties.TASK), CoreProperties.SCAN_TASK);
-    if (taskKey.equals("views")) {
-      throw MessageException.of("The task 'views' was removed with SonarQube 7.1. " +
-        "You can safely remove this call since portfolios and applications are automatically re-calculated.");
-    } else if (!taskKey.equals(CoreProperties.SCAN_TASK)) {
-      throw MessageException.of("Tasks support was removed in SonarQube 7.6.");
-    }
-    String analysisMode = StringUtils.defaultIfEmpty(scannerProperties.get("sonar.analysis.mode"), "publish");
-    if (!analysisMode.equals("publish")) {
-      throw MessageException.of("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
-    }
-    new ProjectScanContainer(this).execute();
-
-    LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime));
-  }
-
-  private void installPlugins() {
-    PluginRepository pluginRepository = getComponentByType(PluginRepository.class);
-    for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
-      Plugin instance = pluginRepository.getPluginInstance(pluginInfo.getKey());
-      addExtension(pluginInfo, instance);
-    }
-  }
-
-  private void loadCoreExtensions() {
-    CoreExtensionsLoader loader = getComponentByType(CoreExtensionsLoader.class);
-    loader.load();
-  }
-
-  static String formatTime(long time) {
-    long h = time / (60 * 60 * 1000);
-    long m = (time - h * 60 * 60 * 1000) / (60 * 1000);
-    long s = (time - h * 60 * 60 * 1000 - m * 60 * 1000) / 1000;
-    long ms = time % 1000;
-    final String format;
-    if (h > 0) {
-      format = "%1$d:%2$02d:%3$02d.%4$03d s";
-    } else if (m > 0) {
-      format = "%2$d:%3$02d.%4$03d s";
-    } else {
-      format = "%3$d.%4$03d s";
-    }
-    return String.format(format, h, m, s, ms);
-  }
-
-}
index 9a373193f7fad1396bb60fb119b9d355673ae441..8f8bca6dea6afc8d98e5e9fbfc5da29a000f6543 100644 (file)
@@ -21,24 +21,19 @@ package org.sonar.scanner.bootstrap;
 
 import java.util.Map;
 import java.util.Optional;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
+import org.springframework.context.annotation.Bean;
 
-public class GlobalServerSettingsProvider extends ProviderAdapter {
-
+public class GlobalServerSettingsProvider {
   private static final Logger LOG = Loggers.get(GlobalServerSettingsProvider.class);
 
-  private GlobalServerSettings singleton;
-
+  @Bean("GlobalServerSettings")
   public GlobalServerSettings provide(GlobalSettingsLoader loader) {
-    if (singleton == null) {
-      Map<String, String> serverSideSettings = loader.loadGlobalSettings();
-      singleton = new GlobalServerSettings(serverSideSettings);
-      Optional.ofNullable(serverSideSettings.get(CoreProperties.SERVER_ID)).ifPresent(v -> LOG.info("Server id: {}", v));
-    }
-    return singleton;
+    Map<String, String> serverSideSettings = loader.loadGlobalSettings();
+    Optional.ofNullable(serverSideSettings.get(CoreProperties.SERVER_ID)).ifPresent(v -> LOG.info("Server id: {}", v));
+    return new GlobalServerSettings(serverSideSettings);
   }
 }
index 0fdf444b7c990768141931943c139b0afa0426b3..4cc825c19300a37ea9e0ec30dca4456800401e3a 100644 (file)
@@ -27,23 +27,21 @@ import java.nio.file.Paths;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.concurrent.TimeUnit;
 import org.apache.commons.lang.StringUtils;
-import org.picocontainer.ComponentLifecycle;
-import org.picocontainer.PicoContainer;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.CoreProperties;
+import org.sonar.api.Startable;
 import org.sonar.api.impl.utils.DefaultTempFolder;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.TempFolder;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
+import org.springframework.context.annotation.Bean;
 
 import static org.sonar.core.util.FileUtils.deleteQuietly;
 
-public class GlobalTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
+public class GlobalTempFolderProvider implements Startable {
   private static final Logger LOG = Loggers.get(GlobalTempFolderProvider.class);
   private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21);
   static final String TMP_NAME_PREFIX = ".sonartmp_";
-  private boolean started = false;
 
   private System2 system;
   private DefaultTempFolder tempFolder;
@@ -56,6 +54,7 @@ public class GlobalTempFolderProvider extends ProviderAdapter implements Compone
     this.system = system;
   }
 
+  @Bean("TempFolder")
   public TempFolder provide(ScannerProperties scannerProps) {
     if (tempFolder == null) {
 
@@ -150,29 +149,14 @@ public class GlobalTempFolderProvider extends ProviderAdapter implements Compone
   }
 
   @Override
-  public void start(PicoContainer container) {
-    started = true;
+  public void start() {
+    // nothing to do
   }
 
   @Override
-  public void stop(PicoContainer container) {
+  public void stop() {
     if (tempFolder != null) {
       tempFolder.stop();
     }
   }
-
-  @Override
-  public void dispose(PicoContainer container) {
-    // nothing to do
-  }
-
-  @Override
-  public boolean componentHasLifecycle() {
-    return true;
-  }
-
-  @Override
-  public boolean isStarted() {
-    return started;
-  }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessor.java
new file mode 100644 (file)
index 0000000..61fcb41
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+
+public class LazyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
+  @Override
+  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+    for (String beanName : beanFactory.getBeanDefinitionNames()) {
+      BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+      beanDefinition.setLazyInit(true);
+    }
+  }
+}
index 371df48fab5924f6361ab01e1ae50cf1132de899..8e31b44d4ad46dc3736da89446cfe8fe3a18d5e5 100644 (file)
@@ -181,7 +181,7 @@ public class PluginFiles {
     LOGGER.debug("Unpacking plugin {}", pluginKey);
     File jar = newTempFile();
     try (InputStream input = new GZIPInputStream(new BufferedInputStream(FileUtils.openInputStream(compressedFile)));
-         JarOutputStream output = new JarOutputStream(new BufferedOutputStream(FileUtils.openOutputStream(jar)))) {
+      JarOutputStream output = new JarOutputStream(new BufferedOutputStream(FileUtils.openOutputStream(jar)))) {
       Pack200.newUnpacker().unpack(input, output);
     } catch (IOException e) {
       throw new IllegalStateException(format("Fail to download plugin [%s]. Pack200 error.", pluginKey), e);
index 171376a5fcb00d2b86ba9a0a6253b12b52d94bad..9f94b6fe43bba6691529b03ed4860cb4c2c50fff 100644 (file)
@@ -23,7 +23,7 @@ import java.util.Collection;
 import java.util.stream.Collectors;
 import org.sonar.api.batch.postjob.PostJob;
 import org.sonar.api.batch.postjob.PostJobContext;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 import org.sonar.scanner.postjob.PostJobOptimizer;
 import org.sonar.scanner.postjob.PostJobWrapper;
 
@@ -32,8 +32,8 @@ public class PostJobExtensionDictionary extends AbstractExtensionDictionary {
   private final PostJobContext postJobContext;
   private final PostJobOptimizer postJobOptimizer;
 
-  public PostJobExtensionDictionary(ComponentContainer componentContainer, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
-    super(componentContainer);
+  public PostJobExtensionDictionary(ExtensionContainer container, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
+    super(container);
     this.postJobOptimizer = postJobOptimizer;
     this.postJobContext = postJobContext;
   }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PriorityBeanFactory.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PriorityBeanFactory.java
new file mode 100644 (file)
index 0000000..6d5a73b
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+
+public class PriorityBeanFactory extends DefaultListableBeanFactory {
+  /**
+   * Determines highest priority of the bean candidates.
+   * Does not take into account the @Primary annotations.
+   * This gets called from {@link DefaultListableBeanFactory#determineAutowireCandidate} when the bean factory is finding the beans to autowire. That method
+   * checks for @Primary before calling this method.
+   *
+   * The strategy is to look at the @Priority annotations. If there are ties, we give priority to components that were added to child containers over their parents.
+   * If there are still ties, null is returned, which will ultimately cause Spring to throw a NoUniqueBeanDefinitionException.
+   */
+  @Override
+  @Nullable
+  protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
+    List<Bean> candidateBeans = candidates.entrySet().stream()
+      .filter(e -> e.getValue() != null)
+      .map(e -> new Bean(e.getKey(), e.getValue()))
+      .collect(Collectors.toUnmodifiableList());
+
+    List<Bean> beansAfterPriority = highestPriority(candidateBeans, b -> getPriority(b.getInstance()));
+    if (beansAfterPriority.isEmpty()) {
+      return null;
+    } else if (beansAfterPriority.size() == 1) {
+      return beansAfterPriority.get(0).getName();
+    }
+
+    List<Bean> beansAfterHierarchy = highestPriority(beansAfterPriority, b -> getHierarchyPriority(b.getName()));
+    if (beansAfterHierarchy.size() == 1) {
+      return beansAfterHierarchy.get(0).getName();
+    }
+
+    return null;
+  }
+
+  private static List<Bean> highestPriority(List<Bean> candidates, PriorityFunction function) {
+    List<Bean> highestPriorityBeans = new ArrayList<>();
+    Integer highestPriority = null;
+
+    for (Bean candidate : candidates) {
+      Integer candidatePriority = function.classify(candidate);
+      if (candidatePriority == null) {
+        candidatePriority = Integer.MAX_VALUE;
+      }
+      if (highestPriority == null) {
+        highestPriority = candidatePriority;
+        highestPriorityBeans.add(candidate);
+      } else if (candidatePriority < highestPriority) {
+        highestPriorityBeans.clear();
+        highestPriority = candidatePriority;
+        highestPriorityBeans.add(candidate);
+      } else if (candidatePriority.equals(highestPriority)) {
+        highestPriorityBeans.add(candidate);
+      }
+    }
+    return highestPriorityBeans;
+  }
+
+  @CheckForNull
+  private Integer getHierarchyPriority(String beanName) {
+    DefaultListableBeanFactory factory = this;
+    int i = 1;
+    while (factory != null) {
+      if (factory.containsBeanDefinition(beanName)) {
+        return i;
+      }
+      factory = (DefaultListableBeanFactory) factory.getParentBeanFactory();
+      i++;
+    }
+    return null;
+  }
+
+  private static class Bean {
+    private final String name;
+    private final Object instance;
+
+    public Bean(String name, Object instance) {
+      this.name = name;
+      this.instance = instance;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public Object getInstance() {
+      return instance;
+    }
+  }
+
+  @FunctionalInterface
+  private interface PriorityFunction {
+    @Nullable
+    Integer classify(Bean candidate);
+  }
+}
index c62fc09908ac6388b107454ca7acb00929ab84d8..fcf68cc3a04434b48e071b7804d79584be0b5112 100644 (file)
@@ -24,8 +24,8 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.stream.Collectors;
 import javax.annotation.CheckForNull;
-import org.picocontainer.Startable;
 import org.sonar.api.Plugin;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.platform.ExplodedPlugin;
index db3abc561b19721f68de8f0ebc1545d285d6c2ef..678b26f17fd66cde1ea4661704d97c8bb6c2cd00 100644 (file)
  */
 package org.sonar.scanner.bootstrap;
 
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.utils.System2;
 import org.sonar.batch.bootstrapper.EnvironmentInformation;
 import org.sonarqube.ws.client.HttpConnector;
 import org.sonarqube.ws.client.WsClientFactories;
+import org.springframework.context.annotation.Bean;
 
 import static java.lang.Integer.parseInt;
 import static java.lang.String.valueOf;
 import static org.apache.commons.lang.StringUtils.defaultIfBlank;
 
-public class ScannerWsClientProvider extends ProviderAdapter {
-
+public class ScannerWsClientProvider {
   static final int CONNECT_TIMEOUT_MS = 5_000;
   static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout";
   static final int DEFAULT_READ_TIMEOUT_SEC = 60;
 
-  private DefaultScannerWsClient wsClient;
-
-  public synchronized DefaultScannerWsClient provide(final ScannerProperties scannerProps,
-    final EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) {
-    if (wsClient == null) {
-      String url = defaultIfBlank(scannerProps.property("sonar.host.url"), "http://localhost:9000");
-      HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder();
-
-      String timeoutSec = defaultIfBlank(scannerProps.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC));
-      String token = defaultIfBlank(system.envVariable("SONAR_TOKEN"), null);
-      String login = defaultIfBlank(scannerProps.property(CoreProperties.LOGIN), token);
-      connectorBuilder
-        .readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000)
-        .connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS)
-        .userAgent(env.toString())
-        .url(url)
-        .credentials(login, scannerProps.property(CoreProperties.PASSWORD));
-
-      // OkHttp detect 'http.proxyHost' java property, but credentials should be filled
-      final String proxyUser = System.getProperty("http.proxyUser", "");
-      if (!proxyUser.isEmpty()) {
-        connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword"));
-      }
-
-      wsClient = new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode);
+  @Bean("DefaultScannerWsClient")
+  public DefaultScannerWsClient provide(ScannerProperties scannerProps, EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) {
+    String url = defaultIfBlank(scannerProps.property("sonar.host.url"), "http://localhost:9000");
+    HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder();
+
+    String timeoutSec = defaultIfBlank(scannerProps.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC));
+    String token = defaultIfBlank(system.envVariable("SONAR_TOKEN"), null);
+    String login = defaultIfBlank(scannerProps.property(CoreProperties.LOGIN), token);
+    connectorBuilder
+      .readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000)
+      .connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS)
+      .userAgent(env.toString())
+      .url(url)
+      .credentials(login, scannerProps.property(CoreProperties.PASSWORD));
+
+    // OkHttp detect 'http.proxyHost' java property, but credentials should be filled
+    final String proxyUser = System.getProperty("http.proxyUser", "");
+    if (!proxyUser.isEmpty()) {
+      connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword"));
     }
-    return wsClient;
+
+    return new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode);
   }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringComponentContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringComponentContainer.java
new file mode 100644 (file)
index 0000000..0e1a3ad
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+import javax.annotation.CheckForNull;
+import org.jetbrains.annotations.Nullable;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.System2;
+import org.sonar.core.platform.ComponentKeys;
+import org.sonar.core.platform.Container;
+import org.sonar.core.platform.ExtensionContainer;
+import org.sonar.core.platform.PluginInfo;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator;
+
+import static java.util.Collections.emptyList;
+import static java.util.Optional.ofNullable;
+
+public class SpringComponentContainer implements ExtensionContainer {
+  protected final AnnotationConfigApplicationContext context;
+  @Nullable
+  protected final SpringComponentContainer parent;
+
+  private final PropertyDefinitions propertyDefinitions;
+  private final ComponentKeys componentKeys = new ComponentKeys();
+
+  protected SpringComponentContainer() {
+    this(null, new PropertyDefinitions(System2.INSTANCE), emptyList());
+  }
+
+  protected SpringComponentContainer(List<?> externalExtensions) {
+    this(null, new PropertyDefinitions(System2.INSTANCE), externalExtensions);
+  }
+
+  protected SpringComponentContainer(SpringComponentContainer parent) {
+    this(parent, parent.propertyDefinitions, emptyList());
+  }
+
+  private SpringComponentContainer(@Nullable SpringComponentContainer parent, PropertyDefinitions propertyDefinitions, List<?> externalExtensions) {
+    this.parent = parent;
+    this.propertyDefinitions = propertyDefinitions;
+    this.context = new AnnotationConfigApplicationContext(new PriorityBeanFactory());
+    // it won't set the name of beans created with @Bean annotated methods
+    this.context.setBeanNameGenerator(new FullyQualifiedAnnotationBeanNameGenerator());
+    if (parent != null) {
+      context.setParent(parent.context);
+    }
+    add(this);
+    add(new StartableBeanPostProcessor());
+    add(externalExtensions);
+    add(propertyDefinitions);
+  }
+
+  /**
+   * Beans need to have a unique name, otherwise they'll override each other.
+   * The strategy is:
+   * - For classes, use the fully qualified class name as the name of the bean
+   * - For instances, use the FQCN + toString()
+   * - If the object is a collection, iterate through the elements and apply the same strategy for each of them
+   */
+  @Override
+  public Container add(Object... objects) {
+    for (Object o : objects) {
+      if (o instanceof Class) {
+        Class<?> clazz = (Class<?>) o;
+        context.registerBean(clazz);
+      } else if (o instanceof Iterable) {
+        add(Iterables.toArray((Iterable<?>) o, Object.class));
+      } else {
+        registerInstance(o);
+      }
+    }
+    return this;
+  }
+
+  private <T> void registerInstance(T instance) {
+    Supplier<T> supplier = () -> instance;
+    Class<T> clazz = (Class<T>) instance.getClass();
+    context.registerBean(componentKeys.ofInstance(instance), clazz, supplier);
+    declareExtension("", instance);
+  }
+
+  /**
+   * Extensions are usually added by plugins and we assume they don't support any injection-related annotations.
+   * Spring contexts supporting annotations will fail if multiple constructors are present without any annotations indicating which one to use for injection.
+   * For that reason, we need to create the beans ourselves, using ClassDerivedBeanDefinition, which will declare that all constructors can be used for injection.
+   */
+  private Container addExtension(Object o) {
+    if (o instanceof Class) {
+      Class<?> clazz = (Class<?>) o;
+      ClassDerivedBeanDefinition bd = new ClassDerivedBeanDefinition(clazz);
+      context.registerBeanDefinition(clazz.getName(), bd);
+    } else if (o instanceof Iterable) {
+      ((Iterable<?>) o).forEach(this::addExtension);
+    } else {
+      ClassDerivedBeanDefinition bd = new ClassDerivedBeanDefinition(o.getClass());
+      bd.setInstanceSupplier(() -> o);
+      context.registerBeanDefinition(componentKeys.ofInstance(o), bd);
+    }
+    return this;
+  }
+
+  @Override
+  public Container addSingletons(Iterable<?> components) {
+    return add(components);
+  }
+
+  @Override
+  public <T> T getComponentByType(Class<T> type) {
+    try {
+      return context.getBean(type);
+    } catch (Exception t) {
+      throw new IllegalStateException("Unable to load component " + type, t);
+    }
+  }
+
+  @Override
+  public <T> List<T> getComponentsByType(Class<T> type) {
+    try {
+      return new ArrayList<>(context.getBeansOfType(type).values());
+    } catch (Exception t) {
+      throw new IllegalStateException("Unable to load components " + type, t);
+    }
+  }
+
+  public void execute() {
+    RuntimeException r = null;
+    try {
+      startComponents();
+    } catch (RuntimeException e) {
+      r = e;
+    } finally {
+      try {
+        stopComponents();
+      } catch (RuntimeException e) {
+        if (r == null) {
+          r = e;
+        }
+      }
+    }
+    if (r != null) {
+      throw r;
+    }
+  }
+
+  public SpringComponentContainer startComponents() {
+    doBeforeStart();
+    context.refresh();
+    doAfterStart();
+    return this;
+  }
+
+  public SpringComponentContainer stopComponents() {
+    if (context.isActive()) {
+      context.close();
+    }
+    return this;
+  }
+
+  public SpringComponentContainer createChild() {
+    return new SpringComponentContainer(this);
+  }
+
+  @Override
+  @CheckForNull
+  public SpringComponentContainer getParent() {
+    return parent;
+  }
+
+  @Override
+  public SpringComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+    addExtension(extension);
+    declareExtension(pluginInfo, extension);
+    return this;
+  }
+
+  @Override
+  public SpringComponentContainer addExtension(@Nullable String defaultCategory, Object extension) {
+    addExtension(extension);
+    declareExtension(defaultCategory, extension);
+    return this;
+  }
+
+  @Override
+  public SpringComponentContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+    declareExtension(pluginInfo != null ? pluginInfo.getName() : "", extension);
+    return this;
+  }
+
+  @Override
+  public SpringComponentContainer declareExtension(@Nullable String defaultCategory, Object extension) {
+    this.propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse(""));
+    return this;
+  }
+
+  /**
+   * This method aims to be overridden
+   */
+  protected void doBeforeStart() {
+    // nothing
+  }
+
+  /**
+   * This method aims to be overridden
+   */
+  protected void doAfterStart() {
+    // nothing
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java
new file mode 100644 (file)
index 0000000..fb0f25e
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import java.time.Clock;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Priority;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.Plugin;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.SonarQubeVersion;
+import org.sonar.api.internal.MetadataLoader;
+import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.UriReader;
+import org.sonar.api.utils.Version;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.extension.CoreExtensionRepositoryImpl;
+import org.sonar.core.extension.CoreExtensionsLoader;
+import org.sonar.core.platform.PluginClassLoader;
+import org.sonar.core.platform.PluginClassloaderFactory;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.core.util.DefaultHttpDownloader;
+import org.sonar.core.util.UuidFactoryImpl;
+import org.sonar.scanner.extension.ScannerCoreExtensionsInstaller;
+import org.sonar.scanner.notifications.DefaultAnalysisWarnings;
+import org.sonar.scanner.platform.DefaultServer;
+import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader;
+import org.sonar.scanner.repository.DefaultNewCodePeriodLoader;
+import org.sonar.scanner.repository.MetricsRepositoryProvider;
+import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader;
+import org.sonar.scanner.scan.SpringProjectScanContainer;
+
+@Priority(3)
+public class SpringGlobalContainer extends SpringComponentContainer {
+  private static final Logger LOG = Loggers.get(SpringGlobalContainer.class);
+  private final Map<String, String> scannerProperties;
+
+  private SpringGlobalContainer(Map<String, String> scannerProperties, List<?> addedExternally) {
+    super(addedExternally);
+    this.scannerProperties = scannerProperties;
+  }
+
+  public static SpringGlobalContainer create(Map<String, String> scannerProperties, List<?> extensions) {
+    return new SpringGlobalContainer(scannerProperties, extensions);
+  }
+
+  @Override
+  public void doBeforeStart() {
+    ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties);
+    GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties);
+    add(rawScannerProperties);
+    add(globalMode);
+    addBootstrapComponents();
+  }
+
+  private void addBootstrapComponents() {
+    Version apiVersion = MetadataLoader.loadVersion(System2.INSTANCE);
+    SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE);
+    DefaultAnalysisWarnings analysisWarnings = new DefaultAnalysisWarnings(System2.INSTANCE);
+    LOG.debug("{} {}", edition.getLabel(), apiVersion);
+    add(
+      // plugins
+      ScannerPluginRepository.class,
+      PluginClassLoader.class,
+      PluginClassloaderFactory.class,
+      ScannerPluginJarExploder.class,
+      ExtensionInstaller.class,
+      new SonarQubeVersion(apiVersion),
+      new GlobalServerSettingsProvider(),
+      new GlobalConfigurationProvider(),
+      new ScannerWsClientProvider(),
+      DefaultServer.class,
+      new GlobalTempFolderProvider(),
+      analysisWarnings,
+      UriReader.class,
+      PluginFiles.class,
+      System2.INSTANCE,
+      Clock.systemDefaultZone(),
+      new MetricsRepositoryProvider(),
+      UuidFactoryImpl.INSTANCE,
+      DefaultHttpDownloader.class,
+      SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition),
+      ScannerPluginInstaller.class,
+      CoreExtensionRepositoryImpl.class,
+      CoreExtensionsLoader.class,
+      ScannerCoreExtensionsInstaller.class,
+      DefaultGlobalSettingsLoader.class,
+      DefaultNewCodePeriodLoader.class,
+      DefaultMetricsRepositoryLoader.class);
+  }
+
+  @Override
+  protected void doAfterStart() {
+    installPlugins();
+    loadCoreExtensions();
+
+    long startTime = System.currentTimeMillis();
+    String taskKey = StringUtils.defaultIfEmpty(scannerProperties.get(CoreProperties.TASK), CoreProperties.SCAN_TASK);
+    if (taskKey.equals("views")) {
+      throw MessageException.of("The task 'views' was removed with SonarQube 7.1. " +
+        "You can safely remove this call since portfolios and applications are automatically re-calculated.");
+    } else if (!taskKey.equals(CoreProperties.SCAN_TASK)) {
+      throw MessageException.of("Tasks support was removed in SonarQube 7.6.");
+    }
+    String analysisMode = StringUtils.defaultIfEmpty(scannerProperties.get("sonar.analysis.mode"), "publish");
+    if (!analysisMode.equals("publish")) {
+      throw MessageException.of("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
+    }
+    new SpringProjectScanContainer(this).execute();
+
+    LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime));
+  }
+
+  private void installPlugins() {
+    PluginRepository pluginRepository = getComponentByType(PluginRepository.class);
+    for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
+      Plugin instance = pluginRepository.getPluginInstance(pluginInfo.getKey());
+      addExtension(pluginInfo, instance);
+    }
+  }
+
+  private void loadCoreExtensions() {
+    getComponentByType(CoreExtensionsLoader.class).load();
+  }
+
+  static String formatTime(long time) {
+    long h = time / (60 * 60 * 1000);
+    long m = (time - h * 60 * 60 * 1000) / (60 * 1000);
+    long s = (time - h * 60 * 60 * 1000 - m * 60 * 1000) / 1000;
+    long ms = time % 1000;
+    final String format;
+    if (h > 0) {
+      format = "%1$d:%2$02d:%3$02d.%4$03d s";
+    } else if (m > 0) {
+      format = "%2$d:%3$02d.%4$03d s";
+    } else {
+      format = "%3$d.%4$03d s";
+    }
+    return String.format(format, h, m, s, ms);
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessor.java
new file mode 100644 (file)
index 0000000..3bb4cb5
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import org.sonar.api.Startable;
+import org.sonar.api.utils.log.Loggers;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
+import org.springframework.lang.Nullable;
+
+public class StartableBeanPostProcessor implements DestructionAwareBeanPostProcessor {
+  @Override
+  @Nullable
+  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+    if (bean instanceof Startable) {
+      ((Startable) bean).start();
+    } else if (bean instanceof org.picocontainer.Startable) {
+      ((org.picocontainer.Startable) bean).start();
+    }
+    return bean;
+  }
+
+  @Override
+  public boolean requiresDestruction(Object bean) {
+    return (bean instanceof Startable) || (bean instanceof org.picocontainer.Startable) || (bean instanceof AutoCloseable);
+  }
+
+  @Override
+  public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
+    try {
+      if (bean instanceof Startable) {
+        ((Startable) bean).stop();
+      } else if (bean instanceof org.picocontainer.Startable) {
+        ((org.picocontainer.Startable) bean).stop();
+      } else if (bean instanceof AutoCloseable) {
+        ((AutoCloseable) bean).close();
+      }
+    } catch (Exception e) {
+      Loggers.get(StartableBeanPostProcessor.class)
+        .warn("Dispose of component {} failed", bean.getClass().getCanonicalName(), e);
+    }
+  }
+}
index 12cb331a39802b3e0d3f6ea5e3d06dd6cb57fe28..ebb55b9910c6587fd3a039fe35ae6e2b91dc3b3d 100644 (file)
@@ -23,17 +23,18 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
 import java.util.stream.Collectors;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
+import org.springframework.context.annotation.Bean;
 
-public class CiConfigurationProvider extends ProviderAdapter {
+public class CiConfigurationProvider {
 
   private static final Logger LOG = Loggers.get(CiConfigurationProvider.class);
   private static final String PROP_DISABLED = "sonar.ci.autoconfig.disabled";
 
+  @Bean("CiConfiguration")
   public CiConfiguration provide(Configuration configuration, CiVendor[] ciVendors) {
     boolean disabled = configuration.getBoolean(PROP_DISABLED).orElse(false);
     if (disabled) {
index 017051f4118f15318850bd92e3aee6b8595b1302..41c6ec4102ba39153787f72cc205f1de69096b64 100644 (file)
@@ -32,6 +32,7 @@ import java.util.concurrent.TimeoutException;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import javax.inject.Inject;
 import org.sonar.api.batch.fs.InputComponent;
 import org.sonar.api.batch.fs.internal.DefaultInputComponent;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
@@ -71,12 +72,12 @@ public class CpdExecutor {
   private int count = 0;
   private int total;
 
+  @Inject
   public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) {
     this(settings, index, publisher, inputComponentCache, Executors.newSingleThreadExecutor());
   }
 
-  public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache,
-                     ExecutorService executorService) {
+  public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache, ExecutorService executorService) {
     this.settings = settings;
     this.index = index;
     this.publisher = publisher;
index ecaaa7d8f1bc8c6f5caccaf9e365fbb8c89323c2..1d850c39a4dee713611923c5456537c99c60b613 100644 (file)
@@ -25,6 +25,7 @@ import org.sonar.api.scan.issue.filter.FilterableIssue;
 import org.sonar.api.scan.issue.filter.IssueFilter;
 import org.sonar.api.scan.issue.filter.IssueFilterChain;
 import org.sonar.scanner.protocol.output.ScannerReport;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * @deprecated since 7.6, {@link IssueFilter} is deprecated
@@ -34,11 +35,13 @@ public class IssueFilters {
   private final IssueFilterChain filterChain;
   private final DefaultInputProject project;
 
+  @Autowired(required = false)
   public IssueFilters(DefaultInputProject project, IssueFilter[] exclusionFilters) {
     this.project = project;
     this.filterChain = new DefaultIssueFilterChain(exclusionFilters);
   }
 
+  @Autowired(required = false)
   public IssueFilters(DefaultInputProject project) {
     this(project, new IssueFilter[0]);
   }
index 3fe40990f849223e8778c8e1a2050e0933ba8c37..77fac1555cc8a9443eecf72452a6f387304a13b1 100644 (file)
@@ -21,13 +21,13 @@ package org.sonar.scanner.mediumtest;
 
 import org.sonar.api.ExtensionPoint;
 import org.sonar.api.scanner.ScannerSide;
-import org.sonar.scanner.scan.ProjectScanContainer;
+import org.sonar.scanner.scan.SpringProjectScanContainer;
 
 @ScannerSide
 @ExtensionPoint
 @FunctionalInterface
 public interface AnalysisObserver {
 
-  void analysisCompleted(ProjectScanContainer container);
+  void analysisCompleted(SpringProjectScanContainer container);
 
 }
index 088c15e175b2356a4767b54eb60ac1e86f868bd5..9fe59b99499ad86db27e517e9b06e3ec2ecbe9f3 100644 (file)
  */
 package org.sonar.scanner.mediumtest;
 
-import org.sonar.scanner.scan.ProjectScanContainer;
+import org.sonar.scanner.scan.SpringProjectScanContainer;
 
 public class AnalysisObservers {
 
-  private AnalysisObserver[] observers;
-  private ProjectScanContainer projectScanContainer;
+  private final AnalysisObserver[] observers;
+  private final SpringProjectScanContainer projectScanContainer;
 
-  public AnalysisObservers(ProjectScanContainer projectScanContainer, AnalysisObserver... observers) {
+  public AnalysisObservers(SpringProjectScanContainer projectScanContainer, AnalysisObserver... observers) {
     this.projectScanContainer = projectScanContainer;
     this.observers = observers;
   }
 
-  public AnalysisObservers(ProjectScanContainer projectScanContainer) {
-    this(projectScanContainer, new AnalysisObserver[0]);
-  }
-
   public void notifyEndOfScanTask() {
     for (AnalysisObserver analysisObserver : observers) {
       analysisObserver.analysisCompleted(projectScanContainer);
index e9eaaf6c84bde84a8291834bd7841ec9f4a42b8c..1f002bf75bda1d98f4236d5ff0e78d7c1a033182 100644 (file)
@@ -43,7 +43,7 @@ import org.sonar.scanner.protocol.output.ScannerReport.Symbol;
 import org.sonar.scanner.protocol.output.ScannerReportReader;
 import org.sonar.scanner.report.ReportPublisher;
 import org.sonar.scanner.report.ScannerReportUtils;
-import org.sonar.scanner.scan.ProjectScanContainer;
+import org.sonar.scanner.scan.SpringProjectScanContainer;
 import org.sonar.scanner.scan.filesystem.InputComponentStore;
 
 public class AnalysisResult implements AnalysisObserver {
@@ -55,7 +55,7 @@ public class AnalysisResult implements AnalysisObserver {
   private ScannerReportReader reader;
 
   @Override
-  public void analysisCompleted(ProjectScanContainer container) {
+  public void analysisCompleted(SpringProjectScanContainer container) {
     LOG.info("Store analysis results in memory for later assertions in medium test");
     ReportPublisher reportPublisher = container.getComponentByType(ReportPublisher.class);
     reader = new ScannerReportReader(reportPublisher.getReportDir().toFile());
@@ -69,7 +69,7 @@ public class AnalysisResult implements AnalysisObserver {
     return reader;
   }
 
-  private void storeFs(ProjectScanContainer container) {
+  private void storeFs(SpringProjectScanContainer container) {
     InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class);
     for (InputFile inputPath : inputFileCache.inputFiles()) {
       inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath);
index ea08a9ae8d53eb6bed07f1c0397b9adce4e27819..5800b912a7b4234f91ebde9b9b59ba0316e63bcb 100644 (file)
@@ -24,11 +24,13 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.Priority;
 import org.sonar.api.Plugin;
 import org.sonar.core.platform.PluginInfo;
 import org.sonar.scanner.bootstrap.PluginInstaller;
 import org.sonar.scanner.bootstrap.ScannerPlugin;
 
+@Priority(1)
 public class FakePluginInstaller implements PluginInstaller {
 
   private final Map<String, ScannerPlugin> pluginsByKeys = new HashMap<>();
index a18b95b06d5e387a581ca21fab8225b93db7cae7..4ec321fd5e0b918e26f6d8707ed6cc54e17c9017 100644 (file)
@@ -23,7 +23,7 @@ import java.io.InputStream;
 import java.time.Duration;
 import java.time.temporal.ChronoUnit;
 import java.util.EnumSet;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
index 2bf6e97729733ef8e82a83a3c50207eacd4e2891..e5abefb3a4f4df8fd16e2f2d5cb917c8997a104c 100644 (file)
@@ -42,8 +42,7 @@ public class ContextPropertiesPublisher implements ReportPublisherStep {
   private final ScmConfiguration scmConfiguration;
   private final CiConfiguration ciConfiguration;
 
-  public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration,
-                                    CiConfiguration ciConfiguration) {
+  public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration, CiConfiguration ciConfiguration) {
     this.cache = cache;
     this.config = config;
     this.scmConfiguration = scmConfiguration;
index 5c2bbb19e49e3f2d04e795ed2dfbaf68b1bd7b85..abf89bae8e5d127ea65a1ae7f25112b5d03efbb8 100644 (file)
@@ -33,7 +33,7 @@ import java.util.Map;
 import javax.annotation.Nullable;
 import okhttp3.HttpUrl;
 import org.apache.commons.io.FileUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.platform.Server;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.TempFolder;
@@ -97,13 +97,13 @@ public class ReportPublisher implements Startable {
     this.branchConfiguration = branchConfiguration;
     this.properties = properties;
     this.ceTaskReportDataHolder = ceTaskReportDataHolder;
+    this.reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report");
+    this.writer = new ScannerReportWriter(reportDir.toFile());
+    this.reader = new ScannerReportReader(reportDir.toFile());
   }
 
   @Override
   public void start() {
-    reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report");
-    writer = new ScannerReportWriter(reportDir.toFile());
-    reader = new ScannerReportReader(reportDir.toFile());
     contextPublisher.init(writer);
 
     if (!analysisMode.isMediumTest()) {
index d5685073e5e4f5e742065aa715b6fafda88e9b2a..54ba26c6f4ff69363f4b82d12138038c2f7a9a7e 100644 (file)
  */
 package org.sonar.scanner.repository;
 
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
+import org.springframework.context.annotation.Bean;
 
-public class MetricsRepositoryProvider extends ProviderAdapter {
+public class MetricsRepositoryProvider {
 
   private static final Logger LOG = Loggers.get(MetricsRepositoryProvider.class);
   private static final String LOG_MSG = "Load metrics repository";
-  private MetricsRepository metricsRepository;
 
+  @Bean("MetricsRepository")
   public MetricsRepository provide(MetricsRepositoryLoader loader) {
-    if (metricsRepository == null) {
-      Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-      metricsRepository = loader.load();
-      profiler.stopInfo();
-    }
+    Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+    MetricsRepository metricsRepository = loader.load();
+    profiler.stopInfo();
     return metricsRepository;
   }
 }
index 37bb0d1c04e133b7c02f4fdbcd32b69418d22390..374d4ae0934bdf402d37e266b6d10a53097f375b 100644 (file)
  */
 package org.sonar.scanner.repository;
 
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.scanner.bootstrap.ScannerProperties;
 import org.sonar.scanner.rule.QualityProfiles;
+import org.springframework.context.annotation.Bean;
 
-public class QualityProfilesProvider extends ProviderAdapter {
+public class QualityProfilesProvider {
   private static final Logger LOG = Loggers.get(QualityProfilesProvider.class);
   private static final String LOG_MSG = "Load quality profiles";
-  private QualityProfiles profiles = null;
 
+  @Bean("QualityProfiles")
   public QualityProfiles provide(QualityProfileLoader loader, ScannerProperties props) {
-    if (this.profiles == null) {
-      Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-      profiles = new QualityProfiles(loader.load(props.getProjectKey()));
-      profiler.stopInfo();
-    }
-
+    Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+    QualityProfiles profiles = new QualityProfiles(loader.load(props.getProjectKey()));
+    profiler.stopInfo();
     return profiles;
   }
 
index 9a5f8fdffdf029702abdb92ba5d84737ef8533fc..acfd8a0a455b6748212384223608629b880a7084 100644 (file)
@@ -24,7 +24,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import javax.annotation.CheckForNull;
 import javax.annotation.concurrent.Immutable;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.resources.Languages;
 
 /**
index b0bc48869868897a7fdf107a336496af43ff6221..07f3a3c1aa207377888ba2e65e56588cff4163dd 100644 (file)
 package org.sonar.scanner.repository.settings;
 
 import java.util.Map;
+import javax.inject.Inject;
 import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
 
 public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader {
 
-  public DefaultGlobalSettingsLoader(final DefaultScannerWsClient wsClient) {
+  @Inject
+  public DefaultGlobalSettingsLoader(DefaultScannerWsClient wsClient) {
     super(wsClient);
   }
 
index e6731d5df870b95f603520fa7305ad797ff51797..71ecf104b9b38bff699a282b3050f781d2f94137 100644 (file)
@@ -25,7 +25,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.rule.LoadedActiveRule;
 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
 import org.sonar.api.batch.rule.internal.DefaultActiveRules;
@@ -34,23 +33,22 @@ import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
+import org.springframework.context.annotation.Bean;
 
 /**
  * Loads the rules that are activated on the Quality profiles
  * used by the current project and builds {@link org.sonar.api.batch.rule.ActiveRules}.
  */
-public class ActiveRulesProvider extends ProviderAdapter {
+public class ActiveRulesProvider {
   private static final Logger LOG = Loggers.get(ActiveRulesProvider.class);
   private static final String LOG_MSG = "Load active rules";
-  private DefaultActiveRules singleton = null;
 
+  @Bean("ActiveRules")
   public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) {
-    if (singleton == null) {
-      Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-      singleton = load(loader, qProfiles);
-      profiler.stopInfo();
-    }
-    return singleton;
+    Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+    DefaultActiveRules activeRules = load(loader, qProfiles);
+    profiler.stopInfo();
+    return activeRules;
   }
 
   private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) {
index e2f82b3d165a9afc69acfc914414c183e4c7e249..9c05e4fece3547a9597455c94593b0386bc2a8f2 100644 (file)
 package org.sonar.scanner.rule;
 
 import java.util.List;
-import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.batch.rule.internal.NewRule;
 import org.sonar.api.batch.rule.Rules;
+import org.sonar.api.batch.rule.internal.NewRule;
 import org.sonar.api.batch.rule.internal.RulesBuilder;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonarqube.ws.Rules.ListResponse.Rule;
+import org.springframework.context.annotation.Bean;
 
-public class RulesProvider extends ProviderAdapter {
+public class RulesProvider {
   private static final Logger LOG = Loggers.get(RulesProvider.class);
   private static final String LOG_MSG = "Load server rules";
-  private Rules singleton = null;
 
+  @Bean("Rules")
   public Rules provide(RulesLoader ref) {
-    if (singleton == null) {
-      singleton = load(ref);
-    }
-    return singleton;
-  }
-
-  private static Rules load(RulesLoader ref) {
     Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
     List<Rule> loadedRules = ref.load();
     RulesBuilder builder = new RulesBuilder();
@@ -54,7 +47,6 @@ public class RulesProvider extends ProviderAdapter {
     }
 
     profiler.stopInfo();
-
     return builder.build();
   }
 }
index 940e0ac9dd8d7e8fa39ae74b1d52cb353b733feb..8915a7ab6729c2c87db1d574bb05f73bce115f5b 100644 (file)
@@ -22,32 +22,31 @@ package org.sonar.scanner.scan;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
 import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
+import org.springframework.context.annotation.Bean;
 
-public class InputModuleHierarchyProvider extends ProviderAdapter {
+public class InputModuleHierarchyProvider {
 
   private static final Logger LOG = Loggers.get(InputModuleHierarchyProvider.class);
 
-  private DefaultInputModuleHierarchy hierarchy = null;
-
-  public DefaultInputModuleHierarchy provide(ScannerComponentIdGenerator scannerComponentIdGenerator, DefaultInputProject project) {
-    if (hierarchy == null) {
-      LOG.debug("Creating module hierarchy");
-      DefaultInputModule root = createModule(project.definition(), project.scannerId());
-      Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, scannerComponentIdGenerator, new HashMap<>());
-      if (parents.isEmpty()) {
-        hierarchy = new DefaultInputModuleHierarchy(root);
-      } else {
-        hierarchy = new DefaultInputModuleHierarchy(root, parents);
-      }
+  @Bean("DefaultInputModuleHierarchy")
+  public DefaultInputModuleHierarchy provide(ScannerComponentIdGenerator scannerComponentIdGenerator, WorkDirectoriesInitializer workDirectoriesInit, DefaultInputProject project) {
+    LOG.debug("Creating module hierarchy");
+    DefaultInputModule root = createModule(project.definition(), project.scannerId());
+    Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, scannerComponentIdGenerator, new HashMap<>());
+    DefaultInputModuleHierarchy inputModuleHierarchy;
+    if (parents.isEmpty()) {
+      inputModuleHierarchy = new DefaultInputModuleHierarchy(root);
+    } else {
+      inputModuleHierarchy = new DefaultInputModuleHierarchy(root, parents);
     }
-    return hierarchy;
+    workDirectoriesInit.execute(inputModuleHierarchy);
+    return inputModuleHierarchy;
   }
 
   private static Map<DefaultInputModule, DefaultInputModule> createChildren(DefaultInputModule parent, ScannerComponentIdGenerator scannerComponentIdGenerator,
index 8bcb781e23f411b88f00269aaaba4d7809348d0e..b5629ce69ef8b29531e8c910a028548a9c671dff 100644 (file)
 package org.sonar.scanner.scan;
 
 import java.util.Locale;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
+import org.springframework.context.annotation.Bean;
 
-public class InputProjectProvider extends ProviderAdapter {
-
+public class InputProjectProvider {
   private static final Logger LOG = Loggers.get(InputProjectProvider.class);
 
-  private DefaultInputProject project = null;
-
+  @Bean("DefaultInputProject")
   public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator,
     ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) {
-    if (project == null) {
-      // 1 Apply project builders
-      projectBuildersExecutor.execute(projectReactor);
+    // 1 Apply project builders
+    projectBuildersExecutor.execute(projectReactor);
 
-      // 2 Validate final reactor
-      validator.validate(projectReactor);
+    // 2 Validate final reactor
+    validator.validate(projectReactor);
 
-      // 3 Create project
-      project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt());
+    // 3 Create project
+    DefaultInputProject project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt());
 
-      LOG.info("Project key: {}", project.key());
-      LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString());
-      LOG.info("Working dir: {}", project.getWorkDir().toAbsolutePath().toString());
-      LOG.debug("Project global encoding: {}, default locale: {}", project.getEncoding().displayName(), Locale.getDefault());
-    }
+    LOG.info("Project key: {}", project.key());
+    LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString());
+    LOG.info("Working dir: {}", project.getWorkDir().toAbsolutePath().toString());
+    LOG.debug("Project global encoding: {}, default locale: {}", project.getEncoding().displayName(), Locale.getDefault());
     return project;
   }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/LanguagesProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/LanguagesProvider.java
new file mode 100644 (file)
index 0000000..d1c3d97
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.scan;
+
+import java.util.List;
+import java.util.Optional;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.springframework.context.annotation.Bean;
+
+public class LanguagesProvider {
+  @Bean("Languages")
+  public Languages provide(Optional<List<Language>> languages) {
+    if (languages.isEmpty()) {
+      return new Languages();
+    }
+    return new Languages(languages.get().toArray(new Language[0]));
+  }
+}
index 65b4a945f918ac4a4dbaf20de01a135e2f190be5..3abef362efb97f780a7fbd5d76291cc892fb97c6 100644 (file)
 package org.sonar.scanner.scan;
 
 import java.util.Map;
-import org.sonar.api.config.internal.Encryption;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
 import org.sonar.scanner.config.DefaultConfiguration;
 
 public class ModuleConfiguration extends DefaultConfiguration {
-
   public ModuleConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) {
     super(propertyDefinitions, encryption, props);
   }
-
 }
index 1728d29537b57b590148e4a0c0382832801858b7..5cb88b0e7b35847f0239792bc2c3b8cbec8b8a1e 100644 (file)
@@ -23,28 +23,22 @@ import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.scanner.bootstrap.GlobalConfiguration;
 import org.sonar.scanner.bootstrap.GlobalServerSettings;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-
-public class ModuleConfigurationProvider extends ProviderAdapter {
-
-  private ModuleConfiguration moduleConfiguration;
+import org.springframework.context.annotation.Bean;
 
+public class ModuleConfigurationProvider {
+  @Bean("ModuleConfiguration")
   public ModuleConfiguration provide(GlobalConfiguration globalConfig, DefaultInputModule module, GlobalServerSettings globalServerSettings,
     ProjectServerSettings projectServerSettings) {
-    if (moduleConfiguration == null) {
-
-      Map<String, String> settings = new LinkedHashMap<>();
-      settings.putAll(globalServerSettings.properties());
-      settings.putAll(projectServerSettings.properties());
-      addScannerSideProperties(settings, module.definition());
+    Map<String, String> settings = new LinkedHashMap<>();
+    settings.putAll(globalServerSettings.properties());
+    settings.putAll(projectServerSettings.properties());
+    addScannerSideProperties(settings, module.definition());
 
-      moduleConfiguration = new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
-    }
-    return moduleConfiguration;
+    return new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
   }
 
   private static void addScannerSideProperties(Map<String, String> settings, ProjectDefinition project) {
index 69974fccd0609d9fae73bdc89746083a47f873f7..517e995af4f5a35a95d21edd1d4cd473cc4bf10f 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.scanner.scan;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.scanner.fs.InputModuleHierarchy;
 import org.sonar.scanner.scan.filesystem.InputComponentStore;
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
deleted file mode 100644 (file)
index c7c17c7..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.scanner.scan;
-
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.scan.filesystem.FileExclusions;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.bootstrap.ExtensionInstaller;
-import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
-import org.sonar.scanner.sensor.ModuleSensorContext;
-import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary;
-import org.sonar.scanner.sensor.ModuleSensorOptimizer;
-import org.sonar.scanner.sensor.ModuleSensorsExecutor;
-
-import static org.sonar.api.batch.InstantiationStrategy.PER_PROJECT;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
-
-public class ModuleScanContainer extends ComponentContainer {
-  private final DefaultInputModule module;
-
-  public ModuleScanContainer(ProjectScanContainer parent, DefaultInputModule module) {
-    super(parent);
-    this.module = module;
-  }
-
-  @Override
-  protected void doBeforeStart() {
-    addCoreComponents();
-    addExtensions();
-  }
-
-  private void addCoreComponents() {
-    add(
-      module.definition(),
-      module,
-      MutableModuleSettings.class,
-      new ModuleConfigurationProvider(),
-
-      ModuleSensorsExecutor.class,
-
-      // file system
-      ModuleInputComponentStore.class,
-      FileExclusions.class,
-      DefaultModuleFileSystem.class,
-
-      ModuleSensorOptimizer.class,
-
-      ModuleSensorContext.class,
-      ModuleSensorExtensionDictionary.class
-    );
-  }
-
-  private void addExtensions() {
-    ExtensionInstaller pluginInstaller = getComponentByType(ExtensionInstaller.class);
-    pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT));
-  }
-
-  @Override
-  protected void doAfterStart() {
-    getComponentByType(ModuleSensorsExecutor.class).execute();
-  }
-
-}
index c4d50aa3959d2200e5137b4b4460271767a0b073..a6cdc6b853f3fd811ed6e04d5f32a666885abbcd 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.scanner.scan;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
+import javax.annotation.Priority;
 import org.sonar.api.config.internal.Settings;
 
 import static java.util.Objects.requireNonNull;
@@ -30,6 +31,7 @@ import static java.util.Objects.requireNonNull;
  * @deprecated since 6.5 {@link ModuleConfiguration} used to be mutable, so keep a mutable copy for backward compatibility.
  */
 @Deprecated
+@Priority(1)
 public class MutableModuleSettings extends Settings {
 
   private final Map<String, String> properties = new HashMap<>();
index 242eec3bd58fefc055f405b79276ad56c9f60a4f..7bdc9a2bd4d91b34901550be124a41d28d8d6926 100644 (file)
  */
 package org.sonar.scanner.scan;
 
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.springframework.context.annotation.Bean;
 
-public class MutableProjectReactorProvider extends ProviderAdapter {
-  private ProjectReactor reactor = null;
-
+public class MutableProjectReactorProvider {
+  @Bean("ProjectReactor")
   public ProjectReactor provide(ProjectReactorBuilder builder) {
-    if (reactor == null) {
-      reactor = builder.execute();
-    }
-    return reactor;
+    return builder.execute();
   }
 }
index cccd0a1c1d618bb2f15f0aa8f48c71ae9ea1542f..a521aa96a4501c6edce0dd167e2423f66aef8892 100644 (file)
@@ -25,12 +25,15 @@ import java.util.Optional;
 import org.sonar.api.config.internal.Settings;
 import org.sonar.scanner.bootstrap.GlobalConfiguration;
 
+import javax.annotation.Priority;
+
 import static java.util.Objects.requireNonNull;
 
 /**
  * @deprecated since 6.5 {@link ProjectConfiguration} used to be mutable, so keep a mutable copy for backward compatibility.
  */
 @Deprecated
+@Priority(2)
 public class MutableProjectSettings extends Settings {
 
   private final Map<String, String> properties = new HashMap<>();
index b45e9f5cfa8509f5319cd85093e72a40f1212238..2d214650ce73c92a1c4b5dd147118892f41e19a3 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.scanner.bootstrap.GlobalConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class ProjectBuildersExecutor {
 
@@ -36,11 +37,13 @@ public class ProjectBuildersExecutor {
   private final GlobalConfiguration globalConfig;
   private final ProjectBuilder[] projectBuilders;
 
+  @Autowired(required = false)
   public ProjectBuildersExecutor(GlobalConfiguration globalConfig, ProjectBuilder... projectBuilders) {
     this.globalConfig = globalConfig;
     this.projectBuilders = projectBuilders;
   }
 
+  @Autowired(required = false)
   public ProjectBuildersExecutor(GlobalConfiguration globalConfig) {
     this(globalConfig, new ProjectBuilder[0]);
   }
index 390ee96e80f21b5b2ab305a6b678e141fc75a7de..80a1e1fad78c1efa3c5a634556ee335a75304579 100644 (file)
 package org.sonar.scanner.scan;
 
 import java.util.Map;
-import org.sonar.api.config.internal.Encryption;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
 import org.sonar.scanner.config.DefaultConfiguration;
 
 public class ProjectConfiguration extends DefaultConfiguration {
-
   public ProjectConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) {
     super(propertyDefinitions, encryption, props);
   }
-
 }
index 8c79c3965e2162bbd8fc738e6fc2c6b7d8151745..d20ff578439d8c54798de0edbfbc5a904d88bb61 100644 (file)
@@ -21,27 +21,22 @@ package org.sonar.scanner.scan;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
-import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.scanner.bootstrap.GlobalConfiguration;
 import org.sonar.scanner.bootstrap.GlobalServerSettings;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
-
-public class ProjectConfigurationProvider extends ProviderAdapter {
-
-  private ProjectConfiguration projectConfig;
+import org.springframework.context.annotation.Bean;
 
+public class ProjectConfigurationProvider {
+  @Bean("ProjectConfiguration")
   public ProjectConfiguration provide(DefaultInputProject project, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings,
     ProjectServerSettings projectServerSettings, MutableProjectSettings projectSettings) {
-    if (projectConfig == null) {
-
-      Map<String, String> settings = new LinkedHashMap<>();
-      settings.putAll(globalServerSettings.properties());
-      settings.putAll(projectServerSettings.properties());
-      settings.putAll(project.properties());
+    Map<String, String> settings = new LinkedHashMap<>();
+    settings.putAll(globalServerSettings.properties());
+    settings.putAll(projectServerSettings.properties());
+    settings.putAll(project.properties());
 
-      projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
-      projectSettings.complete(projectConfig);
-    }
+    ProjectConfiguration projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
+    projectSettings.complete(projectConfig);
     return projectConfig;
   }
 }
index 1e9776e92d0dae4f111f94c13ad3e6980f614ce4..8463396f4f8668d451b1adccbdf2834c32cebfd7 100644 (file)
@@ -23,7 +23,7 @@ import java.io.IOException;
 import java.nio.channels.OverlappingFileLockException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
 
 public class ProjectLock implements Startable {
index f32a52cb7bf1748742661d764412da04bb557fe2..6b4f05f9d25903accd2f8c9980919b043777c67d 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.api.utils.MessageException;
 import org.sonar.core.component.ComponentKeys;
 import org.sonar.scanner.bootstrap.GlobalConfiguration;
 import org.sonar.scanner.scan.branch.BranchParamsValidator;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static java.lang.String.format;
 import static java.util.Objects.nonNull;
@@ -52,11 +53,13 @@ public class ProjectReactorValidator {
   @Nullable
   private final BranchParamsValidator branchParamsValidator;
 
+  @Autowired(required = false)
   public ProjectReactorValidator(GlobalConfiguration settings, @Nullable BranchParamsValidator branchParamsValidator) {
     this.settings = settings;
     this.branchParamsValidator = branchParamsValidator;
   }
 
+  @Autowired(required = false)
   public ProjectReactorValidator(GlobalConfiguration settings) {
     this(settings, null);
   }
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
deleted file mode 100644 (file)
index 954a80a..0000000
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.scanner.scan;
-
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.FileMetadata;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.api.batch.rule.CheckFactory;
-import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.resources.ResourceTypes;
-import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.config.ScannerProperties;
-import org.sonar.core.extension.CoreExtensionsInstaller;
-import org.sonar.core.metric.ScannerMetrics;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.DefaultFileLinesContextFactory;
-import org.sonar.scanner.ProjectInfo;
-import org.sonar.scanner.analysis.AnalysisTempFolderProvider;
-import org.sonar.scanner.bootstrap.ExtensionInstaller;
-import org.sonar.scanner.bootstrap.ExtensionMatcher;
-import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.PostJobExtensionDictionary;
-import org.sonar.scanner.ci.CiConfigurationProvider;
-import org.sonar.scanner.ci.vendors.AppVeyor;
-import org.sonar.scanner.ci.vendors.AwsCodeBuild;
-import org.sonar.scanner.ci.vendors.AzureDevops;
-import org.sonar.scanner.ci.vendors.Bamboo;
-import org.sonar.scanner.ci.vendors.BitbucketPipelines;
-import org.sonar.scanner.ci.vendors.Bitrise;
-import org.sonar.scanner.ci.vendors.Buildkite;
-import org.sonar.scanner.ci.vendors.CircleCi;
-import org.sonar.scanner.ci.vendors.CirrusCi;
-import org.sonar.scanner.ci.vendors.CodeMagic;
-import org.sonar.scanner.ci.vendors.DroneCi;
-import org.sonar.scanner.ci.vendors.GithubActions;
-import org.sonar.scanner.ci.vendors.GitlabCi;
-import org.sonar.scanner.ci.vendors.Jenkins;
-import org.sonar.scanner.ci.vendors.SemaphoreCi;
-import org.sonar.scanner.ci.vendors.TravisCi;
-import org.sonar.scanner.cpd.CpdExecutor;
-import org.sonar.scanner.cpd.CpdSettings;
-import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.fs.InputModuleHierarchy;
-import org.sonar.scanner.issue.IssueFilters;
-import org.sonar.scanner.issue.IssuePublisher;
-import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
-import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
-import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.mediumtest.AnalysisObservers;
-import org.sonar.scanner.postjob.DefaultPostJobContext;
-import org.sonar.scanner.postjob.PostJobOptimizer;
-import org.sonar.scanner.postjob.PostJobsExecutor;
-import org.sonar.scanner.qualitygate.QualityGateCheck;
-import org.sonar.scanner.report.ActiveRulesPublisher;
-import org.sonar.scanner.report.AnalysisContextReportPublisher;
-import org.sonar.scanner.report.AnalysisWarningsPublisher;
-import org.sonar.scanner.report.CeTaskReportDataHolder;
-import org.sonar.scanner.report.ChangedLinesPublisher;
-import org.sonar.scanner.report.ComponentsPublisher;
-import org.sonar.scanner.report.ContextPropertiesPublisher;
-import org.sonar.scanner.report.MetadataPublisher;
-import org.sonar.scanner.report.ReportPublisher;
-import org.sonar.scanner.report.SourcePublisher;
-import org.sonar.scanner.report.TestExecutionPublisher;
-import org.sonar.scanner.repository.ContextPropertiesCache;
-import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader;
-import org.sonar.scanner.repository.DefaultQualityProfileLoader;
-import org.sonar.scanner.repository.ReferenceBranchSupplier;
-import org.sonar.scanner.repository.ProjectRepositoriesLoader;
-import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
-import org.sonar.scanner.repository.QualityProfileLoader;
-import org.sonar.scanner.repository.QualityProfilesProvider;
-import org.sonar.scanner.repository.language.DefaultLanguagesRepository;
-import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader;
-import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
-import org.sonar.scanner.rule.ActiveRulesLoader;
-import org.sonar.scanner.rule.ActiveRulesProvider;
-import org.sonar.scanner.rule.DefaultActiveRulesLoader;
-import org.sonar.scanner.rule.DefaultRulesLoader;
-import org.sonar.scanner.rule.QProfileVerifier;
-import org.sonar.scanner.rule.RulesLoader;
-import org.sonar.scanner.rule.RulesProvider;
-import org.sonar.scanner.scan.branch.BranchConfiguration;
-import org.sonar.scanner.scan.branch.BranchConfigurationProvider;
-import org.sonar.scanner.scan.branch.BranchType;
-import org.sonar.scanner.scan.branch.ProjectBranchesProvider;
-import org.sonar.scanner.scan.branch.ProjectPullRequestsProvider;
-import org.sonar.scanner.scan.filesystem.DefaultProjectFileSystem;
-import org.sonar.scanner.scan.filesystem.FileIndexer;
-import org.sonar.scanner.scan.filesystem.InputComponentStore;
-import org.sonar.scanner.scan.filesystem.LanguageDetection;
-import org.sonar.scanner.scan.filesystem.MetadataGenerator;
-import org.sonar.scanner.scan.filesystem.ProjectCoverageAndDuplicationExclusions;
-import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
-import org.sonar.scanner.scan.filesystem.ProjectFileIndexer;
-import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
-import org.sonar.scanner.scan.filesystem.StatusDetection;
-import org.sonar.scanner.scan.measure.DefaultMetricFinder;
-import org.sonar.scanner.scm.ScmChangedFilesProvider;
-import org.sonar.scanner.scm.ScmConfiguration;
-import org.sonar.scanner.scm.ScmPublisher;
-import org.sonar.scanner.scm.ScmRevisionImpl;
-import org.sonar.scanner.sensor.DefaultSensorStorage;
-import org.sonar.scanner.sensor.ProjectSensorContext;
-import org.sonar.scanner.sensor.ProjectSensorExtensionDictionary;
-import org.sonar.scanner.sensor.ProjectSensorOptimizer;
-import org.sonar.scanner.sensor.ProjectSensorsExecutor;
-import org.sonar.scm.git.GitScmSupport;
-import org.sonar.scm.svn.SvnScmSupport;
-
-import static org.sonar.api.batch.InstantiationStrategy.PER_BATCH;
-import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide;
-
-public class ProjectScanContainer extends ComponentContainer {
-
-  private static final Logger LOG = Loggers.get(ProjectScanContainer.class);
-
-  public ProjectScanContainer(ComponentContainer globalContainer) {
-    super(globalContainer);
-  }
-
-  @Override
-  protected void doBeforeStart() {
-    addScannerExtensions();
-    addScannerComponents();
-    ProjectLock lock = getComponentByType(ProjectLock.class);
-    lock.tryLock();
-    getComponentByType(WorkDirectoriesInitializer.class).execute();
-  }
-
-  private void addScannerComponents() {
-    add(
-      ScanProperties.class,
-      ProjectReactorBuilder.class,
-      WorkDirectoriesInitializer.class,
-      new MutableProjectReactorProvider(),
-      ProjectBuildersExecutor.class,
-      ProjectLock.class,
-      ResourceTypes.class,
-      ProjectReactorValidator.class,
-      ProjectInfo.class,
-      new RulesProvider(),
-      new BranchConfigurationProvider(),
-      new ProjectBranchesProvider(),
-      new ProjectPullRequestsProvider(),
-      ProjectRepositoriesSupplier.class,
-      new ProjectServerSettingsProvider(),
-
-      // temp
-      new AnalysisTempFolderProvider(),
-
-      // file system
-      ModuleIndexer.class,
-      InputComponentStore.class,
-      PathResolver.class,
-      new InputProjectProvider(),
-      new InputModuleHierarchyProvider(),
-      ScannerComponentIdGenerator.class,
-      new ScmChangedFilesProvider(),
-      StatusDetection.class,
-      LanguageDetection.class,
-      MetadataGenerator.class,
-      FileMetadata.class,
-      FileIndexer.class,
-      ProjectFileIndexer.class,
-      ProjectExclusionFilters.class,
-
-      // rules
-      new ActiveRulesProvider(),
-      new QualityProfilesProvider(),
-      CheckFactory.class,
-      QProfileVerifier.class,
-
-      // issues
-      DefaultNoSonarFilter.class,
-      IssueFilters.class,
-      IssuePublisher.class,
-
-      // metrics
-      DefaultMetricFinder.class,
-
-      // lang
-      Languages.class,
-      DefaultLanguagesRepository.class,
-
-      // issue exclusions
-      IssueInclusionPatternInitializer.class,
-      IssueExclusionPatternInitializer.class,
-      IssueExclusionsLoader.class,
-      EnforceIssuesFilter.class,
-      IgnoreIssuesFilter.class,
-
-      // context
-      ContextPropertiesCache.class,
-      ContextPropertiesPublisher.class,
-
-      SensorStrategy.class,
-
-      MutableProjectSettings.class,
-      ScannerProperties.class,
-      new ProjectConfigurationProvider(),
-
-      ProjectCoverageAndDuplicationExclusions.class,
-
-      // Report
-      ReferenceBranchSupplier.class,
-      ScannerMetrics.class,
-      ReportPublisher.class,
-      AnalysisContextReportPublisher.class,
-      MetadataPublisher.class,
-      ActiveRulesPublisher.class,
-      AnalysisWarningsPublisher.class,
-      ComponentsPublisher.class,
-      TestExecutionPublisher.class,
-      SourcePublisher.class,
-      ChangedLinesPublisher.class,
-
-      CeTaskReportDataHolder.class,
-
-      // QualityGate check
-      QualityGateCheck.class,
-
-      // Cpd
-      CpdExecutor.class,
-      CpdSettings.class,
-      SonarCpdBlockIndex.class,
-
-      // PostJobs
-      PostJobsExecutor.class,
-      PostJobOptimizer.class,
-      DefaultPostJobContext.class,
-      PostJobExtensionDictionary.class,
-
-      // SCM
-      ScmConfiguration.class,
-      ScmPublisher.class,
-      ScmRevisionImpl.class,
-
-      // Sensors
-      DefaultSensorStorage.class,
-      DefaultFileLinesContextFactory.class,
-      ProjectSensorContext.class,
-      ProjectSensorOptimizer.class,
-      ProjectSensorsExecutor.class,
-      ProjectSensorExtensionDictionary.class,
-
-      // Filesystem
-      DefaultProjectFileSystem.class,
-
-      // CI
-      new CiConfigurationProvider(),
-      AppVeyor.class,
-      AwsCodeBuild.class,
-      AzureDevops.class,
-      Bamboo.class,
-      BitbucketPipelines.class,
-      Bitrise.class,
-      Buildkite.class,
-      CircleCi.class,
-      CirrusCi.class,
-      DroneCi.class,
-      GithubActions.class,
-      CodeMagic.class,
-      GitlabCi.class,
-      Jenkins.class,
-      SemaphoreCi.class,
-      TravisCi.class,
-
-      AnalysisObservers.class);
-
-    add(GitScmSupport.getObjects());
-    add(SvnScmSupport.getObjects());
-
-    addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class);
-    addIfMissing(DefaultRulesLoader.class, RulesLoader.class);
-    addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class);
-    addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class);
-    addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class);
-  }
-
-  private void addScannerExtensions() {
-    getComponentByType(CoreExtensionsInstaller.class)
-      .install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension));
-    getComponentByType(ExtensionInstaller.class)
-      .install(this, getScannerProjectExtensionsFilter());
-  }
-
-  static ExtensionMatcher getScannerProjectExtensionsFilter() {
-    return extension -> {
-      if (isDeprecatedScannerSide(extension)) {
-        return isInstantiationStrategy(extension, PER_BATCH);
-      }
-      return isScannerSide(extension);
-    };
-  }
-
-  @Override
-  protected void doAfterStart() {
-    GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class);
-    InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class);
-    ScanProperties properties = getComponentByType(ScanProperties.class);
-    properties.validate();
-
-    properties.get("sonar.branch").ifPresent(deprecatedBranch -> {
-      throw MessageException.of("The 'sonar.branch' parameter is no longer supported. You should stop using it. " +
-        "Branch analysis is available in Developer Edition and above. See https://redirect.sonarsource.com/editions/developer.html for more information.");
-    });
-
-    BranchConfiguration branchConfig = getComponentByType(BranchConfiguration.class);
-    if (branchConfig.branchType() == BranchType.PULL_REQUEST) {
-      LOG.info("Pull request {} for merge into {} from {}", branchConfig.pullRequestKey(), pullRequestBaseToDisplayName(branchConfig.targetBranchName()),
-        branchConfig.branchName());
-    } else if (branchConfig.branchName() != null) {
-      LOG.info("Branch name: {}", branchConfig.branchName());
-    }
-
-    getComponentByType(ProjectFileIndexer.class).index();
-
-    // Log detected languages and their profiles after FS is indexed and languages detected
-    getComponentByType(QProfileVerifier.class).execute();
-
-    scanRecursively(tree, tree.root());
-
-    LOG.info("------------- Run sensors on project");
-    getComponentByType(ProjectSensorsExecutor.class).execute();
-
-    getComponentByType(ScmPublisher.class).publish();
-
-    getComponentByType(CpdExecutor.class).execute();
-    getComponentByType(ReportPublisher.class).execute();
-
-    if (properties.shouldWaitForQualityGate()) {
-      LOG.info("------------- Check Quality Gate status");
-      getComponentByType(QualityGateCheck.class).await();
-    }
-
-    getComponentByType(PostJobsExecutor.class).execute();
-
-    if (analysisMode.isMediumTest()) {
-      getComponentByType(AnalysisObservers.class).notifyEndOfScanTask();
-    }
-  }
-
-  private static String pullRequestBaseToDisplayName(@Nullable String pullRequestBase) {
-    return pullRequestBase != null ? pullRequestBase : "default branch";
-  }
-
-  private void scanRecursively(InputModuleHierarchy tree, DefaultInputModule module) {
-    for (DefaultInputModule child : tree.children(module)) {
-      scanRecursively(tree, child);
-    }
-    LOG.info("------------- Run sensors on module {}", module.definition().getName());
-    scan(module);
-  }
-
-  void scan(DefaultInputModule module) {
-    new ModuleScanContainer(this, module).execute();
-  }
-
-}
index cc58757301036f4c32c258d80f569b5500af988e..55516177aa946c7384be7964d5be4b62f283e422 100644 (file)
@@ -21,14 +21,14 @@ package org.sonar.scanner.scan;
 
 import java.util.Map;
 import org.apache.commons.lang.StringUtils;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.notifications.AnalysisWarnings;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
+import org.springframework.context.annotation.Bean;
 
-public class ProjectServerSettingsProvider extends ProviderAdapter {
+public class ProjectServerSettingsProvider {
 
   private static final Logger LOG = Loggers.get(ProjectConfigurationProvider.class);
 
@@ -37,17 +37,13 @@ public class ProjectServerSettingsProvider extends ProviderAdapter {
     "Archived Sub-Projects Settings' at project level, and clear the property to prevent the analysis from " +
     "displaying this warning.";
 
-  private ProjectServerSettings singleton = null;
-
+  @Bean("ProjectServerSettings")
   public ProjectServerSettings provide(ProjectSettingsLoader loader, AnalysisWarnings analysisWarnings) {
-    if (singleton == null) {
-      Map<String, String> serverSideSettings = loader.loadProjectSettings();
-      if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) {
-        LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
-        analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
-      }
-      singleton = new ProjectServerSettings(serverSideSettings);
+    Map<String, String> serverSideSettings = loader.loadProjectSettings();
+    if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) {
+      LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
+      analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
     }
-    return singleton;
+    return new ProjectServerSettings(serverSideSettings);
   }
 }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringModuleScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringModuleScanContainer.java
new file mode 100644 (file)
index 0000000..79a0917
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.scan;
+
+import javax.annotation.Priority;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.scan.filesystem.FileExclusions;
+import org.sonar.scanner.bootstrap.ExtensionInstaller;
+import org.sonar.scanner.bootstrap.SpringComponentContainer;
+import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
+import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
+import org.sonar.scanner.sensor.ModuleSensorContext;
+import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary;
+import org.sonar.scanner.sensor.ModuleSensorOptimizer;
+import org.sonar.scanner.sensor.ModuleSensorsExecutor;
+
+import static org.sonar.api.batch.InstantiationStrategy.PER_PROJECT;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
+
+@Priority(1)
+public class SpringModuleScanContainer extends SpringComponentContainer {
+  private final DefaultInputModule module;
+
+  public SpringModuleScanContainer(SpringComponentContainer parent, DefaultInputModule module) {
+    super(parent);
+    this.module = module;
+  }
+
+  @Override
+  protected void doBeforeStart() {
+    addCoreComponents();
+    addExtensions();
+  }
+
+  private void addCoreComponents() {
+    add(
+      module.definition(),
+      module,
+      MutableModuleSettings.class,
+      new ModuleConfigurationProvider(),
+
+      ModuleSensorsExecutor.class,
+
+      // file system
+      ModuleInputComponentStore.class,
+      FileExclusions.class,
+      DefaultModuleFileSystem.class,
+
+      ModuleSensorOptimizer.class,
+
+      ModuleSensorContext.class,
+      ModuleSensorExtensionDictionary.class
+    );
+  }
+
+  private void addExtensions() {
+    ExtensionInstaller pluginInstaller = parent.getComponentByType(ExtensionInstaller.class);
+    pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT));
+  }
+
+  @Override
+  protected void doAfterStart() {
+    getComponentByType(ModuleSensorsExecutor.class).execute();
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringProjectScanContainer.java
new file mode 100644 (file)
index 0000000..d1d605f
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.scan;
+
+import javax.annotation.Nullable;
+import javax.annotation.Priority;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.FileMetadata;
+import org.sonar.api.batch.fs.internal.SensorStrategy;
+import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter;
+import org.sonar.api.resources.ResourceTypes;
+import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.config.ScannerProperties;
+import org.sonar.core.extension.CoreExtensionsInstaller;
+import org.sonar.core.metric.ScannerMetrics;
+import org.sonar.scanner.DefaultFileLinesContextFactory;
+import org.sonar.scanner.ProjectInfo;
+import org.sonar.scanner.analysis.AnalysisTempFolderProvider;
+import org.sonar.scanner.bootstrap.ExtensionInstaller;
+import org.sonar.scanner.bootstrap.ExtensionMatcher;
+import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
+import org.sonar.scanner.bootstrap.PostJobExtensionDictionary;
+import org.sonar.scanner.bootstrap.SpringComponentContainer;
+import org.sonar.scanner.ci.CiConfigurationProvider;
+import org.sonar.scanner.ci.vendors.AppVeyor;
+import org.sonar.scanner.ci.vendors.AwsCodeBuild;
+import org.sonar.scanner.ci.vendors.AzureDevops;
+import org.sonar.scanner.ci.vendors.Bamboo;
+import org.sonar.scanner.ci.vendors.BitbucketPipelines;
+import org.sonar.scanner.ci.vendors.Bitrise;
+import org.sonar.scanner.ci.vendors.Buildkite;
+import org.sonar.scanner.ci.vendors.CircleCi;
+import org.sonar.scanner.ci.vendors.CirrusCi;
+import org.sonar.scanner.ci.vendors.CodeMagic;
+import org.sonar.scanner.ci.vendors.DroneCi;
+import org.sonar.scanner.ci.vendors.GithubActions;
+import org.sonar.scanner.ci.vendors.GitlabCi;
+import org.sonar.scanner.ci.vendors.Jenkins;
+import org.sonar.scanner.ci.vendors.SemaphoreCi;
+import org.sonar.scanner.ci.vendors.TravisCi;
+import org.sonar.scanner.cpd.CpdExecutor;
+import org.sonar.scanner.cpd.CpdSettings;
+import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
+import org.sonar.scanner.fs.InputModuleHierarchy;
+import org.sonar.scanner.issue.IssueFilters;
+import org.sonar.scanner.issue.IssuePublisher;
+import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
+import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
+import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
+import org.sonar.scanner.mediumtest.AnalysisObservers;
+import org.sonar.scanner.postjob.DefaultPostJobContext;
+import org.sonar.scanner.postjob.PostJobOptimizer;
+import org.sonar.scanner.postjob.PostJobsExecutor;
+import org.sonar.scanner.qualitygate.QualityGateCheck;
+import org.sonar.scanner.report.ActiveRulesPublisher;
+import org.sonar.scanner.report.AnalysisContextReportPublisher;
+import org.sonar.scanner.report.AnalysisWarningsPublisher;
+import org.sonar.scanner.report.CeTaskReportDataHolder;
+import org.sonar.scanner.report.ChangedLinesPublisher;
+import org.sonar.scanner.report.ComponentsPublisher;
+import org.sonar.scanner.report.ContextPropertiesPublisher;
+import org.sonar.scanner.report.MetadataPublisher;
+import org.sonar.scanner.report.ReportPublisher;
+import org.sonar.scanner.report.SourcePublisher;
+import org.sonar.scanner.report.TestExecutionPublisher;
+import org.sonar.scanner.repository.ContextPropertiesCache;
+import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader;
+import org.sonar.scanner.repository.DefaultQualityProfileLoader;
+import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
+import org.sonar.scanner.repository.QualityProfilesProvider;
+import org.sonar.scanner.repository.ReferenceBranchSupplier;
+import org.sonar.scanner.repository.language.DefaultLanguagesRepository;
+import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader;
+import org.sonar.scanner.rule.ActiveRulesProvider;
+import org.sonar.scanner.rule.DefaultActiveRulesLoader;
+import org.sonar.scanner.rule.DefaultRulesLoader;
+import org.sonar.scanner.rule.QProfileVerifier;
+import org.sonar.scanner.rule.RulesProvider;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.branch.BranchConfigurationProvider;
+import org.sonar.scanner.scan.branch.BranchType;
+import org.sonar.scanner.scan.branch.ProjectBranchesProvider;
+import org.sonar.scanner.scan.branch.ProjectPullRequestsProvider;
+import org.sonar.scanner.scan.filesystem.DefaultProjectFileSystem;
+import org.sonar.scanner.scan.filesystem.FileIndexer;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
+import org.sonar.scanner.scan.filesystem.LanguageDetection;
+import org.sonar.scanner.scan.filesystem.MetadataGenerator;
+import org.sonar.scanner.scan.filesystem.ProjectCoverageAndDuplicationExclusions;
+import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
+import org.sonar.scanner.scan.filesystem.ProjectFileIndexer;
+import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
+import org.sonar.scanner.scan.filesystem.StatusDetection;
+import org.sonar.scanner.scan.measure.DefaultMetricFinder;
+import org.sonar.scanner.scm.ScmChangedFilesProvider;
+import org.sonar.scanner.scm.ScmConfiguration;
+import org.sonar.scanner.scm.ScmPublisher;
+import org.sonar.scanner.scm.ScmRevisionImpl;
+import org.sonar.scanner.sensor.DefaultSensorStorage;
+import org.sonar.scanner.sensor.ProjectSensorContext;
+import org.sonar.scanner.sensor.ProjectSensorExtensionDictionary;
+import org.sonar.scanner.sensor.ProjectSensorOptimizer;
+import org.sonar.scanner.sensor.ProjectSensorsExecutor;
+import org.sonar.scm.git.GitScmSupport;
+import org.sonar.scm.svn.SvnScmSupport;
+
+import static org.sonar.api.batch.InstantiationStrategy.PER_BATCH;
+import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide;
+
+@Priority(2)
+public class SpringProjectScanContainer extends SpringComponentContainer {
+  private static final Logger LOG = Loggers.get(SpringProjectScanContainer.class);
+
+  public SpringProjectScanContainer(SpringComponentContainer globalContainer) {
+    super(globalContainer);
+  }
+
+  @Override
+  protected void doBeforeStart() {
+    addScannerExtensions();
+    addScannerComponents();
+  }
+
+  private void addScannerComponents() {
+    add(
+      ScanProperties.class,
+      ProjectReactorBuilder.class,
+      WorkDirectoriesInitializer.class,
+      new MutableProjectReactorProvider(),
+      ProjectBuildersExecutor.class,
+      ProjectLock.class,
+      ResourceTypes.class,
+      ProjectReactorValidator.class,
+      ProjectInfo.class,
+      new RulesProvider(),
+      new BranchConfigurationProvider(),
+      new ProjectBranchesProvider(),
+      new ProjectPullRequestsProvider(),
+      ProjectRepositoriesSupplier.class,
+      new ProjectServerSettingsProvider(),
+
+      // temp
+      new AnalysisTempFolderProvider(),
+
+      // file system
+      ModuleIndexer.class,
+      InputComponentStore.class,
+      PathResolver.class,
+      new InputProjectProvider(),
+      new InputModuleHierarchyProvider(),
+      ScannerComponentIdGenerator.class,
+      new ScmChangedFilesProvider(),
+      StatusDetection.class,
+      LanguageDetection.class,
+      MetadataGenerator.class,
+      FileMetadata.class,
+      FileIndexer.class,
+      ProjectFileIndexer.class,
+      ProjectExclusionFilters.class,
+
+      // rules
+      new ActiveRulesProvider(),
+      new QualityProfilesProvider(),
+      CheckFactory.class,
+      QProfileVerifier.class,
+
+      // issues
+      DefaultNoSonarFilter.class,
+      IssueFilters.class,
+      IssuePublisher.class,
+
+      // metrics
+      DefaultMetricFinder.class,
+
+      // lang
+      LanguagesProvider.class,
+      DefaultLanguagesRepository.class,
+
+      // issue exclusions
+      IssueInclusionPatternInitializer.class,
+      IssueExclusionPatternInitializer.class,
+      IssueExclusionsLoader.class,
+      EnforceIssuesFilter.class,
+      IgnoreIssuesFilter.class,
+
+      // context
+      ContextPropertiesCache.class,
+      ContextPropertiesPublisher.class,
+
+      SensorStrategy.class,
+
+      MutableProjectSettings.class,
+      ScannerProperties.class,
+      new ProjectConfigurationProvider(),
+
+      ProjectCoverageAndDuplicationExclusions.class,
+
+      // Report
+      ReferenceBranchSupplier.class,
+      ScannerMetrics.class,
+      ReportPublisher.class,
+      AnalysisContextReportPublisher.class,
+      MetadataPublisher.class,
+      ActiveRulesPublisher.class,
+      AnalysisWarningsPublisher.class,
+      ComponentsPublisher.class,
+      TestExecutionPublisher.class,
+      SourcePublisher.class,
+      ChangedLinesPublisher.class,
+
+      CeTaskReportDataHolder.class,
+
+      // QualityGate check
+      QualityGateCheck.class,
+
+      // Cpd
+      CpdExecutor.class,
+      CpdSettings.class,
+      SonarCpdBlockIndex.class,
+
+      // PostJobs
+      PostJobsExecutor.class,
+      PostJobOptimizer.class,
+      DefaultPostJobContext.class,
+      PostJobExtensionDictionary.class,
+
+      // SCM
+      ScmConfiguration.class,
+      ScmPublisher.class,
+      ScmRevisionImpl.class,
+
+      // Sensors
+      DefaultSensorStorage.class,
+      DefaultFileLinesContextFactory.class,
+      ProjectSensorContext.class,
+      ProjectSensorOptimizer.class,
+      ProjectSensorsExecutor.class,
+      ProjectSensorExtensionDictionary.class,
+
+      // Filesystem
+      DefaultProjectFileSystem.class,
+
+      // CI
+      new CiConfigurationProvider(),
+      AppVeyor.class,
+      AwsCodeBuild.class,
+      AzureDevops.class,
+      Bamboo.class,
+      BitbucketPipelines.class,
+      Bitrise.class,
+      Buildkite.class,
+      CircleCi.class,
+      CirrusCi.class,
+      DroneCi.class,
+      GithubActions.class,
+      CodeMagic.class,
+      GitlabCi.class,
+      Jenkins.class,
+      SemaphoreCi.class,
+      TravisCi.class,
+
+      AnalysisObservers.class);
+
+    add(GitScmSupport.getObjects());
+    add(SvnScmSupport.getObjects());
+
+    add(DefaultProjectSettingsLoader.class,
+      DefaultRulesLoader.class,
+      DefaultActiveRulesLoader.class,
+      DefaultQualityProfileLoader.class,
+      DefaultProjectRepositoriesLoader.class);
+  }
+
+  private void addScannerExtensions() {
+    getParent().getComponentByType(CoreExtensionsInstaller.class)
+      .install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension));
+    getParent().getComponentByType(ExtensionInstaller.class)
+      .install(this, getScannerProjectExtensionsFilter());
+  }
+
+  static ExtensionMatcher getScannerProjectExtensionsFilter() {
+    return extension -> {
+      if (isDeprecatedScannerSide(extension)) {
+        return isInstantiationStrategy(extension, PER_BATCH);
+      }
+      return isScannerSide(extension);
+    };
+  }
+
+  @Override
+  protected void doAfterStart() {
+    getComponentByType(ProjectLock.class).tryLock();
+    GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class);
+    InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class);
+    ScanProperties properties = getComponentByType(ScanProperties.class);
+    properties.validate();
+
+    properties.get("sonar.branch").ifPresent(deprecatedBranch -> {
+      throw MessageException.of("The 'sonar.branch' parameter is no longer supported. You should stop using it. " +
+        "Branch analysis is available in Developer Edition and above. See https://redirect.sonarsource.com/editions/developer.html for more information.");
+    });
+
+    BranchConfiguration branchConfig = getComponentByType(BranchConfiguration.class);
+    if (branchConfig.branchType() == BranchType.PULL_REQUEST) {
+      LOG.info("Pull request {} for merge into {} from {}", branchConfig.pullRequestKey(), pullRequestBaseToDisplayName(branchConfig.targetBranchName()),
+        branchConfig.branchName());
+    } else if (branchConfig.branchName() != null) {
+      LOG.info("Branch name: {}", branchConfig.branchName());
+    }
+
+    getComponentByType(ProjectFileIndexer.class).index();
+
+    // Log detected languages and their profiles after FS is indexed and languages detected
+    getComponentByType(QProfileVerifier.class).execute();
+
+    scanRecursively(tree, tree.root());
+
+    LOG.info("------------- Run sensors on project");
+    getComponentByType(ProjectSensorsExecutor.class).execute();
+
+    getComponentByType(ScmPublisher.class).publish();
+
+    getComponentByType(CpdExecutor.class).execute();
+    getComponentByType(ReportPublisher.class).execute();
+
+    if (properties.shouldWaitForQualityGate()) {
+      LOG.info("------------- Check Quality Gate status");
+      getComponentByType(QualityGateCheck.class).await();
+    }
+
+    getComponentByType(PostJobsExecutor.class).execute();
+
+    if (analysisMode.isMediumTest()) {
+      getComponentByType(AnalysisObservers.class).notifyEndOfScanTask();
+    }
+  }
+
+  private static String pullRequestBaseToDisplayName(@Nullable String pullRequestBase) {
+    return pullRequestBase != null ? pullRequestBase : "default branch";
+  }
+
+  private void scanRecursively(InputModuleHierarchy tree, DefaultInputModule module) {
+    for (DefaultInputModule child : tree.children(module)) {
+      scanRecursively(tree, child);
+    }
+    LOG.info("------------- Run sensors on module {}", module.definition().getName());
+    scan(module);
+  }
+
+  void scan(DefaultInputModule module) {
+    new SpringModuleScanContainer(this, module).execute();
+  }
+
+}
index ae662ef8e5e51ab1dab63a52c9dbde2a756bb94e..b118a870ff727cf55aee7fbe9a09ad37be88944c 100644 (file)
@@ -33,30 +33,23 @@ import org.sonar.scanner.fs.InputModuleHierarchy;
  * Be careful that sub module work dir might be nested in parent working directory.
  */
 public class WorkDirectoriesInitializer {
-
-  private InputModuleHierarchy moduleHierarchy;
-
-  public WorkDirectoriesInitializer(InputModuleHierarchy moduleHierarchy) {
-    this.moduleHierarchy = moduleHierarchy;
-  }
-
-  public void execute() {
-    cleanAllWorkingDirs(moduleHierarchy.root());
-    mkdirsAllWorkingDirs(moduleHierarchy.root());
+  public void execute(InputModuleHierarchy moduleHierarchy) {
+    cleanAllWorkingDirs(moduleHierarchy, moduleHierarchy.root());
+    mkdirsAllWorkingDirs(moduleHierarchy, moduleHierarchy.root());
   }
 
-  private void cleanAllWorkingDirs(DefaultInputModule module) {
+  private static void cleanAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) {
     for (DefaultInputModule sub : moduleHierarchy.children(module)) {
-      cleanAllWorkingDirs(sub);
+      cleanAllWorkingDirs(moduleHierarchy, sub);
     }
     if (Files.exists(module.getWorkDir())) {
       deleteAllRecursivelyExceptLockFile(module.getWorkDir());
     }
   }
 
-  private void mkdirsAllWorkingDirs(DefaultInputModule module) {
+  private static void mkdirsAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) {
     for (DefaultInputModule sub : moduleHierarchy.children(module)) {
-      mkdirsAllWorkingDirs(sub);
+      mkdirsAllWorkingDirs(moduleHierarchy, sub);
     }
     try {
       Files.createDirectories(module.getWorkDir());
index 41085f8db9a053e70dff2adf9092f84511b89d7e..87287fadd29482544e044fdbff1d442ff6e1216a 100644 (file)
  */
 package org.sonar.scanner.scan.branch;
 
-import org.picocontainer.annotations.Nullable;
-import org.picocontainer.injectors.ProviderAdapter;
+import javax.annotation.Nullable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.scanner.scan.ProjectConfiguration;
+import org.springframework.context.annotation.Bean;
 
-public class BranchConfigurationProvider extends ProviderAdapter {
+public class BranchConfigurationProvider {
 
   private static final Logger LOG = Loggers.get(BranchConfigurationProvider.class);
   private static final String LOG_MSG = "Load branch configuration";
 
-  private BranchConfiguration branchConfiguration = null;
-
+  @Bean("BranchConfiguration")
   public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectConfiguration projectConfiguration,
     ProjectBranches branches, ProjectPullRequests pullRequests) {
-    if (branchConfiguration == null) {
-      if (loader == null) {
-        branchConfiguration = new DefaultBranchConfiguration();
-      } else {
-        Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-        branchConfiguration = loader.load(projectConfiguration.getProperties(), branches, pullRequests);
-        profiler.stopInfo();
-      }
+    if (loader == null) {
+      return new DefaultBranchConfiguration();
+    } else {
+      Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+      BranchConfiguration branchConfiguration = loader.load(projectConfiguration.getProperties(), branches, pullRequests);
+      profiler.stopInfo();
+      return branchConfiguration;
     }
-    return branchConfiguration;
   }
 }
index d0f8c5f0b350199702aad20c8db677cc2eaf0497..9e3ad167f27dd54f31635930a1458827f9092a2e 100644 (file)
 package org.sonar.scanner.scan.branch;
 
 import java.util.Collections;
-import org.picocontainer.annotations.Nullable;
-import org.picocontainer.injectors.ProviderAdapter;
+import javax.annotation.Nullable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.springframework.context.annotation.Bean;
 
-public class ProjectBranchesProvider extends ProviderAdapter {
+public class ProjectBranchesProvider {
 
   private static final Logger LOG = Loggers.get(ProjectBranchesProvider.class);
   private static final String LOG_MSG = "Load project branches";
 
-  private ProjectBranches branches = null;
-
+  @Bean("ProjectBranches")
   public ProjectBranches provide(@Nullable ProjectBranchesLoader loader, ScannerProperties scannerProperties) {
-    if (this.branches != null) {
-      return this.branches;
-    }
-
     if (loader == null) {
-      this.branches = new ProjectBranches(Collections.emptyList());
-      return this.branches;
+      return new ProjectBranches(Collections.emptyList());
     }
 
     Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-    this.branches = loader.load(scannerProperties.getProjectKey());
+    ProjectBranches branches = loader.load(scannerProperties.getProjectKey());
     profiler.stopInfo();
-    return this.branches;
+    return branches;
   }
 }
index b1bc7c85f9794d9d6bf2f921719a84791a49aec0..0b2ebde0fa5def1c5a3dd4f7384fd563e955fc5e 100644 (file)
 package org.sonar.scanner.scan.branch;
 
 import java.util.Collections;
-import org.picocontainer.injectors.ProviderAdapter;
+import javax.annotation.Nullable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
 import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.springframework.context.annotation.Bean;
 
-public class ProjectPullRequestsProvider extends ProviderAdapter {
+public class ProjectPullRequestsProvider {
 
   private static final Logger LOG = Loggers.get(ProjectPullRequestsProvider.class);
   private static final String LOG_MSG = "Load project pull requests";
 
-  private ProjectPullRequests pullRequests = null;
-
-  public ProjectPullRequests provide(@org.picocontainer.annotations.Nullable ProjectPullRequestsLoader loader, ScannerProperties scannerProperties) {
-    if (pullRequests != null) {
-      return pullRequests;
-    }
-
+  @Bean("ProjectPullRequests")
+  public ProjectPullRequests provide(@Nullable ProjectPullRequestsLoader loader, ScannerProperties scannerProperties) {
     if (loader == null) {
-      pullRequests = new ProjectPullRequests(Collections.emptyList());
-      return pullRequests;
+      return new ProjectPullRequests(Collections.emptyList());
     }
 
     Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
-    pullRequests = loader.load(scannerProperties.getProjectKey());
+    ProjectPullRequests pullRequests = loader.load(scannerProperties.getProjectKey());
     profiler.stopInfo();
     return pullRequests;
   }
index d949f49ad7e3d956697b0c5494a26e38dcf8cff9..65e321006a43552746123f04d812ec94d432280b 100644 (file)
@@ -22,8 +22,13 @@ package org.sonar.scanner.scan.filesystem;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates;
 
+import javax.annotation.Priority;
+import javax.inject.Inject;
+
+@Priority(1)
 public class DefaultModuleFileSystem extends MutableFileSystem {
 
+  @Inject
   public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) {
     super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir()));
     initFields(module);
index 57946189e3f1807657e20583f9af2e4a385c1420..1311ff59214efd1ea344e6b108ac4b1ac3002754 100644 (file)
@@ -22,8 +22,13 @@ package org.sonar.scanner.scan.filesystem;
 import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates;
 
+import javax.annotation.Priority;
+import javax.inject.Inject;
+
+@Priority(2)
 public class DefaultProjectFileSystem extends MutableFileSystem {
 
+  @Inject
   public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) {
     super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir()));
     setFields(project);
index 96b0974c98ed13e7564dac0c513e25ade65f0960..7ea8799c855ae0588c46a42eb079419626590fd3 100644 (file)
@@ -90,14 +90,6 @@ public class FileIndexer {
     this.projectExclusionFilters = projectExclusionFilters;
   }
 
-  public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore,
-    ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions,
-    IssueExclusionsLoader issueExclusionsLoader, MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy,
-    LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
-    this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader,
-      metadataGenerator, sensorStrategy, languageDetection, analysisWarnings, properties, new InputFileFilter[0]);
-  }
-
   void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions,
     Path sourceFile, Type type, ProgressReport progressReport, ProjectFileIndexer.ExclusionCounter exclusionCounter, @Nullable IgnoreCommand ignoreCommand)
     throws IOException {
index 071864ac29b6505fd8c842727bd05189ee7dd39a..1a7acc611894f26b3d53046d4754efb9a31e2854 100644 (file)
@@ -22,29 +22,25 @@ package org.sonar.scanner.scm;
 import java.nio.file.Path;
 import java.util.Collection;
 import javax.annotation.CheckForNull;
-import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.batch.scm.ScmProvider;
+import org.sonar.api.impl.utils.ScannerUtils;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
-import org.sonar.api.impl.utils.ScannerUtils;
+import org.springframework.context.annotation.Bean;
 
-public class ScmChangedFilesProvider extends ProviderAdapter {
+public class ScmChangedFilesProvider {
   private static final Logger LOG = Loggers.get(ScmChangedFilesProvider.class);
   private static final String LOG_MSG = "SCM collecting changed files in the branch";
 
-  private ScmChangedFiles scmBranchChangedFiles;
-
+  @Bean("ScmChangedFiles")
   public ScmChangedFiles provide(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) {
-    if (scmBranchChangedFiles == null) {
       Path rootBaseDir = project.getBaseDir();
       Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir);
       validatePaths(changedFiles);
-      scmBranchChangedFiles = new ScmChangedFiles(changedFiles);
-    }
-    return scmBranchChangedFiles;
+      return new ScmChangedFiles(changedFiles);
   }
 
   private static void validatePaths(@javax.annotation.Nullable Collection<Path> paths) {
index 05be6c2595ac12bebdb2a0550c8e192c6b2f3970..25d91d49d317c0fdab961e14342132357d6a615a 100644 (file)
@@ -24,11 +24,11 @@ import java.util.Map;
 import java.util.stream.Collectors;
 import javax.annotation.CheckForNull;
 import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.Properties;
 import org.sonar.api.Property;
 import org.sonar.api.PropertyType;
+import org.sonar.api.Startable;
 import org.sonar.api.batch.scm.ScmProvider;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.notifications.AnalysisWarnings;
@@ -67,7 +67,8 @@ public class ScmConfiguration implements Startable {
 
   private ScmProvider provider;
 
-  public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings, ScmProvider... providers) {
+  public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings,
+    ScmProvider... providers) {
     this.moduleHierarchy = moduleHierarchy;
     this.settings = settings;
     this.analysisWarnings = analysisWarnings;
@@ -76,10 +77,6 @@ public class ScmConfiguration implements Startable {
     }
   }
 
-  public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings) {
-    this(moduleHierarchy, settings, analysisWarnings, new ScmProvider[0]);
-  }
-
   @Override
   public void start() {
     if (isDisabled()) {
index 4874b528357c51fdae5e5da104efbe91bada5aaa..a33a00961f45dede454c3d38c37fa4ef9f084eb9 100644 (file)
@@ -34,9 +34,9 @@ public class ModuleSensorContext extends ProjectSensorContext {
 
   private final InputModule module;
 
-  public ModuleSensorContext(DefaultInputProject project, InputModule module, Configuration config, Settings mutableSettings, FileSystem fs, ActiveRules activeRules,
+  public ModuleSensorContext(DefaultInputProject project, InputModule module, Configuration config, Settings mutableModuleSettings, FileSystem fs, ActiveRules activeRules,
     SensorStorage sensorStorage, SonarRuntime sonarRuntime) {
-    super(project, config, mutableSettings, fs, activeRules, sensorStorage, sonarRuntime);
+    super(project, config, mutableModuleSettings, fs, activeRules, sensorStorage, sonarRuntime);
     this.module = module;
   }
 
index 34366b17d9e9c5058c948fb844e558fd8851ac15..d723bb2ebf36d7ad2697375e8e09eda65e2672ae 100644 (file)
@@ -24,6 +24,7 @@ import java.util.stream.Collectors;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.core.platform.ComponentContainer;
 import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
+import org.sonar.scanner.bootstrap.SpringComponentContainer;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.filesystem.MutableFileSystem;
 
@@ -34,7 +35,7 @@ public class ModuleSensorExtensionDictionary extends AbstractExtensionDictionary
   private final MutableFileSystem fileSystem;
   private final BranchConfiguration branchConfiguration;
 
-  public ModuleSensorExtensionDictionary(ComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
+  public ModuleSensorExtensionDictionary(SpringComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
     MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
     super(componentContainer);
     this.sensorContext = sensorContext;
index 2352db54cba88a5ea625bf5454d148e7ad404cda..60b31745d19472f3d3a1018f6e8b35a854410501 100644 (file)
@@ -23,8 +23,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.sonar.api.scanner.sensor.ProjectSensor;
-import org.sonar.core.platform.ComponentContainer;
 import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
+import org.sonar.scanner.bootstrap.SpringComponentContainer;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.filesystem.MutableFileSystem;
 
@@ -35,7 +35,7 @@ public class ProjectSensorExtensionDictionary extends AbstractExtensionDictionar
   private final MutableFileSystem fileSystem;
   private final BranchConfiguration branchConfiguration;
 
-  public ProjectSensorExtensionDictionary(ComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer,
+  public ProjectSensorExtensionDictionary(SpringComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer,
     MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
     super(componentContainer);
     this.sensorContext = sensorContext;
index 286c20903dcc13116d5471c6bad4b93be3f30111..b61685130a10d05f555ee71a6f304a429554db5e 100644 (file)
     <level value="INFO"/>
   </logger>
 
+  <!-- Spring generates too many DEBUG logs when sonar.verbose is set -->
+  <logger name="org.springframework">
+    <level value="INFO"/>
+  </logger>
+
+  <logger name="org.sonar.scanner.bootstrap.PriorityBeanFactory">
+    <level value="INFO"/>
+  </logger>
+
   <!-- sonar.showSql -->
   <!-- see also org.sonar.db.MyBatis#configureLogback() -->
   <logger name="org.mybatis">
@@ -42,9 +51,6 @@
   <logger name="java.sql.ResultSet">
     <level value="WARN"/>
   </logger>
-  <logger name="PERSISTIT">
-    <level value="WARN"/>
-  </logger>
 
   <root>
     <!-- sonar.verbose -->
index 6771813bfcd2ffb70aab194837b2cf4dec375a6d..4763605d094534d81ba0f190f3e6aa56a234a076 100644 (file)
     <level value="WARN"/>
   </logger>
 
-  <logger name="PERSISTIT">
-    <level value="WARN"/>
-  </logger>
-
   <root>
     <!-- sonar.verbose -->
     <level value="${ROOT_LOGGER_LEVEL}"/>
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalContainerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalContainerTest.java
deleted file mode 100644 (file)
index 0191ac4..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.scanner.bootstrap;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.utils.TempFolder;
-import org.sonar.batch.bootstrapper.EnvironmentInformation;
-import org.sonar.core.util.UuidFactory;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class GlobalContainerTest {
-  @Rule
-  public TemporaryFolder temp = new TemporaryFolder();
-
-  private GlobalContainer createContainer(List<Object> extensions) {
-    Map<String, String> props = ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, temp.getRoot().getAbsolutePath(),
-      CoreProperties.GLOBAL_WORKING_DIRECTORY, temp.getRoot().getAbsolutePath());
-
-    GlobalContainer container = GlobalContainer.create(props, extensions);
-    container.doBeforeStart();
-    return container;
-  }
-
-  @Test
-  public void should_add_components() {
-    GlobalContainer container = createContainer(Collections.singletonList(new EnvironmentInformation("maven", "3.1.0")));
-
-    assertThat(container.getComponentByType(UuidFactory.class)).isNotNull();
-    assertThat(container.getComponentByType(TempFolder.class)).isNotNull();
-  }
-
-  @Test
-  public void should_add_bootstrap_extensions() {
-    GlobalContainer container = createContainer(Lists.newArrayList(Foo.class, new Bar()));
-
-    assertThat(container.getComponentByType(Foo.class)).isNotNull();
-    assertThat(container.getComponentByType(Bar.class)).isNotNull();
-  }
-
-  @Test
-  public void shouldFormatTime() {
-    assertThat(GlobalContainer.formatTime(1 * 60 * 60 * 1000 + 2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("1:02:03.400 s");
-    assertThat(GlobalContainer.formatTime(2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("2:03.400 s");
-    assertThat(GlobalContainer.formatTime(3 * 1000 + 400)).isEqualTo("3.400 s");
-    assertThat(GlobalContainer.formatTime(400)).isEqualTo("0.400 s");
-  }
-
-  @ScannerSide
-  public static class Foo {
-
-  }
-
-  @ScannerSide
-  public static class Bar {
-
-  }
-
-}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessorTest.java
new file mode 100644 (file)
index 0000000..04327d5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import org.junit.Test;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class LazyBeanFactoryPostProcessorTest {
+  private final LazyBeanFactoryPostProcessor postProcessor = new LazyBeanFactoryPostProcessor();
+
+  @Test
+  public void sets_all_beans_lazy() {
+    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
+    beanFactory.registerBeanDefinition("bean1", new RootBeanDefinition());
+    assertThat(beanFactory.getBeanDefinition("bean1").isLazyInit()).isFalse();
+
+    postProcessor.postProcessBeanFactory(beanFactory);
+    assertThat(beanFactory.getBeanDefinition("bean1").isLazyInit()).isTrue();
+  }
+
+}
index 3c673ce262951e628932ca2e1943b0d5d1353c89..b2625033efc7d3eddc8cf7a745330c7c48934b9b 100644 (file)
@@ -20,9 +20,6 @@
 package org.sonar.scanner.bootstrap;
 
 import com.google.common.collect.Lists;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
 import org.picocontainer.behaviors.FieldDecorated;
@@ -30,11 +27,13 @@ import org.sonar.api.batch.DependedUpon;
 import org.sonar.api.batch.DependsUpon;
 import org.sonar.api.batch.Phase;
 import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.SensorDescriptor;
 import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.scanner.scan.SpringModuleScanContainer;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.filesystem.MutableFileSystem;
 import org.sonar.scanner.sensor.ModuleSensorContext;
@@ -42,6 +41,10 @@ import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary;
 import org.sonar.scanner.sensor.ModuleSensorOptimizer;
 import org.sonar.scanner.sensor.ModuleSensorWrapper;
 
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
@@ -59,10 +62,16 @@ public class ModuleSensorExtensionDictionaryTest {
   }
 
   private ModuleSensorExtensionDictionary newSelector(Object... extensions) {
-    ComponentContainer iocContainer = new ComponentContainer();
-    for (Object extension : extensions) {
-      iocContainer.addSingleton(extension);
-    }
+    DefaultInputModule inputModule = mock(DefaultInputModule.class);
+    when(inputModule.definition()).thenReturn(mock(ProjectDefinition.class));
+
+    SpringComponentContainer parent = new SpringComponentContainer();
+    parent.context.refresh();
+
+    SpringComponentContainer iocContainer = new SpringModuleScanContainer(parent, inputModule);
+    iocContainer.add(Arrays.asList(extensions));
+    iocContainer.context.refresh();
+
     return new ModuleSensorExtensionDictionary(iocContainer, mock(ModuleSensorContext.class), sensorOptimizer, fileSystem, branchConfiguration);
   }
 
@@ -95,14 +104,17 @@ public class ModuleSensorExtensionDictionaryTest {
     Sensor b = new FakeSensor();
     Sensor c = new FakeSensor();
 
-    ComponentContainer grandParent = new ComponentContainer();
-    grandParent.addSingleton(a);
+    SpringComponentContainer grandParent = new SpringComponentContainer();
+    grandParent.add(a);
+    grandParent.context.refresh();
 
-    ComponentContainer parent = grandParent.createChild();
-    parent.addSingleton(b);
+    SpringComponentContainer parent = grandParent.createChild();
+    parent.add(b);
+    parent.context.refresh();
 
-    ComponentContainer child = parent.createChild();
-    child.addSingleton(c);
+    SpringComponentContainer child = parent.createChild();
+    child.add(c);
+    child.context.refresh();
 
     ModuleSensorExtensionDictionary dictionnary = new ModuleSensorExtensionDictionary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class),
       fileSystem, branchConfiguration);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PriorityBeanFactoryTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PriorityBeanFactoryTest.java
new file mode 100644 (file)
index 0000000..b20e87e
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import javax.annotation.Priority;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
+import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.core.annotation.AnnotationAwareOrderComparator;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class PriorityBeanFactoryTest {
+  private final DefaultListableBeanFactory parentBeanFactory = new PriorityBeanFactory();
+  private final DefaultListableBeanFactory beanFactory = new PriorityBeanFactory();
+
+  @Before
+  public void setUp() {
+    // needed to support autowiring with @Inject
+    beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
+    //needed to read @Priority
+    beanFactory.setDependencyComparator(new AnnotationAwareOrderComparator());
+    beanFactory.setParentBeanFactory(parentBeanFactory);
+  }
+
+  @Test
+  public void give_priority_to_child_container() {
+    parentBeanFactory.registerBeanDefinition("A1", new RootBeanDefinition(A1.class));
+
+    beanFactory.registerBeanDefinition("A2", new RootBeanDefinition(A2.class));
+    beanFactory.registerBeanDefinition("B", new RootBeanDefinition(B.class));
+
+    assertThat(beanFactory.getBean(B.class).dep.getClass()).isEqualTo(A2.class);
+  }
+
+  @Test
+  public void follow_priority_annotations() {
+    parentBeanFactory.registerBeanDefinition("A3", new RootBeanDefinition(A3.class));
+
+    beanFactory.registerBeanDefinition("A1", new RootBeanDefinition(A1.class));
+    beanFactory.registerBeanDefinition("A2", new RootBeanDefinition(A2.class));
+    beanFactory.registerBeanDefinition("B", new RootBeanDefinition(B.class));
+
+    assertThat(beanFactory.getBean(B.class).dep.getClass()).isEqualTo(A3.class);
+  }
+
+  @Test
+  public void throw_NoUniqueBeanDefinitionException_if_cant_find_single_bean_with_higher_priority() {
+    beanFactory.registerBeanDefinition("A1", new RootBeanDefinition(A1.class));
+    beanFactory.registerBeanDefinition("A2", new RootBeanDefinition(A2.class));
+    beanFactory.registerBeanDefinition("B", new RootBeanDefinition(B.class));
+
+    assertThatThrownBy(() -> beanFactory.getBean(B.class))
+      .hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class);
+  }
+
+  private static class B {
+    private final A dep;
+
+    public B(A dep) {
+      this.dep = dep;
+    }
+  }
+
+  private interface A {
+
+  }
+
+  private static class A1 implements A {
+
+  }
+
+  private static class A2 implements A {
+
+  }
+
+  @Priority(1)
+  private static class A3 implements A {
+
+  }
+
+}
index 3acd5700c7307de84fb3634c8263ac9eafd8ca72..4fe6fd6dad8bde91374e2ac4cdfc67b31932cb37 100644 (file)
@@ -66,14 +66,4 @@ public class ScannerWsClientProviderTest {
     assertThat(httpConnector.baseUrl()).isEqualTo("https://here/sonarqube/");
     assertThat(httpConnector.okHttpClient().proxy()).isNull();
   }
-
-  @Test
-  public void build_singleton() {
-    System2 system = mock(System2.class);
-
-    ScannerProperties settings = new ScannerProperties(new HashMap<>());
-    DefaultScannerWsClient first = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system);
-    DefaultScannerWsClient second = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system);
-    assertThat(first).isSameAs(second);
-  }
 }
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringComponentContainerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringComponentContainerTest.java
new file mode 100644 (file)
index 0000000..bbc00cf
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import org.junit.Test;
+import org.sonar.api.Startable;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertThrows;
+
+public class SpringComponentContainerTest {
+
+  @Test
+  public void should_stop_after_failing() {
+    ApiStartable startStop = new ApiStartable();
+    SpringComponentContainer container = new SpringComponentContainer() {
+      @Override
+      public void doBeforeStart() {
+        add(startStop);
+      }
+
+      @Override
+      public void doAfterStart() {
+        getComponentByType(ApiStartable.class);
+        throw new IllegalStateException("doBeforeStart");
+      }
+    };
+
+    assertThrows("doBeforeStart", IllegalStateException.class, container::execute);
+    assertThat(startStop.start).isTrue();
+    assertThat(startStop.stop).isTrue();
+  }
+
+  @Test
+  public void register_instance_with_toString() {
+    SpringComponentContainer container = new SimpleContainer(new ToString("a"), new ToString("b"));
+    container.startComponents();
+    assertThat(container.context.getBeanDefinitionNames())
+      .contains("org.sonar.scanner.bootstrap.SpringComponentContainerTest.ToString-a", "org.sonar.scanner.bootstrap.SpringComponentContainerTest.ToString-b");
+    assertThat(container.getComponentsByType(ToString.class)).hasSize(2);
+  }
+
+  @Test
+  public void register_class_with_fqcn() {
+    SpringComponentContainer container = new SimpleContainer(A.class, B.class);
+    container.startComponents();
+    assertThat(container.context.getBeanDefinitionNames())
+      .contains("org.sonar.scanner.bootstrap.SpringComponentContainerTest$A", "org.sonar.scanner.bootstrap.SpringComponentContainerTest$B");
+    assertThat(container.getComponentByType(A.class)).isNotNull();
+    assertThat(container.getComponentByType(B.class)).isNotNull();
+  }
+
+  @Test
+  public void should_throw_start_exception_if_stop_also_throws_exception() {
+    ErrorStopClass errorStopClass = new ErrorStopClass();
+    SpringComponentContainer container = new SpringComponentContainer() {
+      @Override
+      public void doBeforeStart() {
+        add(errorStopClass);
+      }
+
+      @Override
+      public void doAfterStart() {
+        getComponentByType(ErrorStopClass.class);
+        throw new IllegalStateException("doBeforeStart");
+      }
+    };
+    assertThrows("doBeforeStart", IllegalStateException.class, container::execute);
+    assertThat(errorStopClass.stopped).isTrue();
+  }
+
+  @Test
+  public void should_support_extensions_without_annotations() {
+    SpringComponentContainer container = new SimpleContainer(A.class, B.class);
+    container.addExtension("", ExtensionWithMultipleConstructorsAndNoAnnotations.class);
+    container.startComponents();
+    assertThat(container.getComponentByType(ExtensionWithMultipleConstructorsAndNoAnnotations.class).gotBothArgs).isTrue();
+  }
+
+  @Test
+  public void support_start_stop_callbacks() {
+    JsrLifecycleCallbacks jsr = new JsrLifecycleCallbacks();
+    ApiStartable api = new ApiStartable();
+    PicoStartable pico = new PicoStartable();
+
+    SpringComponentContainer container = new SimpleContainer(jsr, api, pico) {
+      @Override
+      public void doAfterStart() {
+        // force lazy instantiation
+        getComponentByType(JsrLifecycleCallbacks.class);
+        getComponentByType(ApiStartable.class);
+        getComponentByType(PicoStartable.class);
+      }
+    };
+    container.execute();
+
+    assertThat(jsr.postConstruct).isTrue();
+    assertThat(jsr.preDestroy).isTrue();
+    assertThat(api.start).isTrue();
+    assertThat(api.stop).isTrue();
+    assertThat(pico.start).isTrue();
+    assertThat(pico.stop).isTrue();
+  }
+
+  private static class JsrLifecycleCallbacks {
+    private boolean postConstruct = false;
+    private boolean preDestroy = false;
+
+    @PostConstruct
+    public void postConstruct() {
+      postConstruct = true;
+    }
+
+    @PreDestroy
+    public void preDestroy() {
+      preDestroy = true;
+    }
+  }
+
+  private static class ApiStartable implements Startable {
+    private boolean start = false;
+    private boolean stop = false;
+
+    public void start() {
+      start = true;
+    }
+
+    public void stop() {
+      stop = true;
+    }
+  }
+
+  private static class PicoStartable implements org.picocontainer.Startable {
+    private boolean start = false;
+    private boolean stop = false;
+
+    public void start() {
+      start = true;
+    }
+
+    public void stop() {
+      stop = true;
+    }
+  }
+
+  private static class ToString {
+    private final String toString;
+
+    public ToString(String toString) {
+      this.toString = toString;
+    }
+
+    @Override
+    public String toString() {
+      return toString;
+    }
+  }
+
+  private static class A {
+  }
+
+  private static class B {
+  }
+
+  private static class ExtensionWithMultipleConstructorsAndNoAnnotations {
+    private boolean gotBothArgs = false;
+    public ExtensionWithMultipleConstructorsAndNoAnnotations(A a) {
+    }
+
+    public ExtensionWithMultipleConstructorsAndNoAnnotations(A a, B b) {
+      gotBothArgs = true;
+    }
+  }
+
+  private static class ErrorStopClass implements Startable {
+    private boolean stopped = false;
+
+    @Override
+    public void start() {
+    }
+
+    @Override
+    public void stop() {
+      stopped = true;
+      throw new IllegalStateException("stop");
+    }
+  }
+
+  private static class SimpleContainer extends SpringComponentContainer {
+    public SimpleContainer(Object... objects) {
+      add(objects);
+    }
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringGlobalContainerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringGlobalContainerTest.java
new file mode 100644 (file)
index 0000000..16a18dc
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SpringGlobalContainerTest {
+  @Test
+  public void shouldFormatTime() {
+    assertThat(SpringGlobalContainer.formatTime(1 * 60 * 60 * 1000 + 2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("1:02:03.400 s");
+    assertThat(SpringGlobalContainer.formatTime(2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("2:03.400 s");
+    assertThat(SpringGlobalContainer.formatTime(3 * 1000 + 400)).isEqualTo("3.400 s");
+    assertThat(SpringGlobalContainer.formatTime(400)).isEqualTo("0.400 s");
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessorTest.java
new file mode 100644 (file)
index 0000000..ecdb616
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.bootstrap;
+
+import org.junit.Test;
+import org.picocontainer.Startable;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+public class StartableBeanPostProcessorTest {
+  private final StartableBeanPostProcessor underTest = new StartableBeanPostProcessor();
+
+  @Test
+  public void starts_pico_startable() {
+    Startable startable = mock(Startable.class);
+    underTest.postProcessBeforeInitialization(startable, "startable");
+    verify(startable).start();
+    verifyNoMoreInteractions(startable);
+  }
+
+  @Test
+  public void starts_api_startable() {
+    org.sonar.api.Startable startable = mock(org.sonar.api.Startable.class);
+    underTest.postProcessBeforeInitialization(startable, "startable");
+    verify(startable).start();
+    verifyNoMoreInteractions(startable);
+  }
+
+  @Test
+  public void stops_pico_startable() {
+    Startable startable = mock(Startable.class);
+    underTest.postProcessBeforeDestruction(startable, "startable");
+    verify(startable).stop();
+    verifyNoMoreInteractions(startable);
+  }
+
+  @Test
+  public void stops_api_startable() {
+    org.sonar.api.Startable startable = mock(org.sonar.api.Startable.class);
+    underTest.postProcessBeforeDestruction(startable, "startable");
+    verify(startable).stop();
+    verifyNoMoreInteractions(startable);
+  }
+
+}
index 75d9bb5388ec5f8428dfb440bdae272551bb08c7..d560991ad50260aac3603f5674933e05a8f59290 100644 (file)
@@ -36,6 +36,7 @@ import java.util.Map;
 import java.util.Properties;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+import javax.annotation.Priority;
 import org.apache.commons.io.FileUtils;
 import org.junit.rules.ExternalResource;
 import org.sonar.api.Plugin;
@@ -100,7 +101,7 @@ public class ScannerMediumTester extends ExternalResource {
   private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader();
   private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader();
   private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime();
-  private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolder();
+  private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolderExt();
   private LogOutput logOutput = null;
 
   private static void createWorkingDirs() throws IOException {
@@ -280,7 +281,7 @@ public class ScannerMediumTester extends ExternalResource {
 
   public static class AnalysisBuilder {
     private final Map<String, String> taskProperties = new HashMap<>();
-    private ScannerMediumTester tester;
+    private final ScannerMediumTester tester;
 
     public AnalysisBuilder(ScannerMediumTester tester) {
       this.tester = tester;
@@ -327,6 +328,7 @@ public class ScannerMediumTester extends ExternalResource {
 
   }
 
+  @Priority(1)
   private static class FakeRulesLoader implements RulesLoader {
     private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>();
 
@@ -341,6 +343,7 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
+  @Priority(1)
   private static class FakeActiveRulesLoader implements ActiveRulesLoader {
     private List<LoadedActiveRule> activeRules = new LinkedList<>();
 
@@ -354,6 +357,7 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
+  @Priority(1)
   private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader {
 
     private int metricId = 1;
@@ -374,6 +378,7 @@ public class ScannerMediumTester extends ExternalResource {
 
   }
 
+  @Priority(1)
   private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader {
     private Map<String, FileData> fileDataMap = new HashMap<>();
 
@@ -389,6 +394,7 @@ public class ScannerMediumTester extends ExternalResource {
 
   }
 
+  @Priority(1)
   private static class FakeBranchConfiguration implements BranchConfiguration {
 
     private BranchType branchType = BranchType.BRANCH;
@@ -425,6 +431,7 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
+  @Priority(1)
   private static class FakeSonarRuntime implements SonarRuntime {
 
     private SonarEdition edition;
@@ -483,6 +490,7 @@ public class ScannerMediumTester extends ExternalResource {
     return this;
   }
 
+  @Priority(1)
   private class FakeBranchConfigurationLoader implements BranchConfigurationLoader {
     @Override
     public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches, ProjectPullRequests pullRequests) {
@@ -490,6 +498,7 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
+  @Priority(1)
   private static class FakeQualityProfileLoader implements QualityProfileLoader {
 
     private List<QualityProfile> qualityProfiles = new LinkedList<>();
@@ -509,6 +518,7 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
+  @Priority(1)
   private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader {
 
     private Map<String, String> globalSettings = new HashMap<>();
@@ -523,6 +533,7 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
+  @Priority(1)
   private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader {
     private NewCodePeriods.ShowWSResponse response;
 
@@ -536,6 +547,7 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
+  @Priority(1)
   private static class FakeProjectSettingsLoader implements ProjectSettingsLoader {
 
     private Map<String, String> projectSettings = new HashMap<>();
@@ -550,4 +562,9 @@ public class ScannerMediumTester extends ExternalResource {
     }
   }
 
+  @Priority(1)
+  private static class CeTaskReportDataHolderExt extends CeTaskReportDataHolder {
+
+  }
+
 }
index e19a3d67453b47f75df92e8a1667f356e5286ec3..3f969ca4963f2cc5d2f12766bec6a7548cd13a72 100644 (file)
@@ -26,6 +26,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.springframework.beans.factory.UnsatisfiedDependencyException;
 
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
@@ -43,8 +44,8 @@ public class NoLanguagesPluginsMediumTest {
     assertThatThrownBy(() -> tester
       .newAnalysis(new File(projectDir, "sonar-project.properties"))
       .execute())
-      .isInstanceOf(IllegalStateException.class)
-      .hasMessage("No language plugins are installed.");
+      .isInstanceOf(UnsatisfiedDependencyException.class)
+      .hasRootCauseMessage("No language plugins are installed.");
   }
 
   private File copyProject(String path) throws Exception {
index dd1e4f496f2e6946962d17f5fa68fa3bf9cd56db..1cef430e5b7882b8a34caf1b3dbd4d5916f210a2 100644 (file)
@@ -73,11 +73,11 @@ public class IssuesMediumTest {
 
     List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
     assertThat(issues).hasSize(8 /* lines */);
-    
+
     List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
     assertThat(externalIssues).isEmpty();
   }
-  
+
   @Test
   public void testOneExternalIssuePerLine() throws Exception {
     File projectDir = new File("test-resources/mediumtest/xoo/sample");
@@ -243,7 +243,8 @@ public class IssuesMediumTest {
         .build())
       .execute();
 
-    assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+    assertThat(logTester.logs(LoggerLevel.WARN)).contains(
+      "Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
 
     List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
     assertThat(issues).isEmpty();
@@ -295,7 +296,8 @@ public class IssuesMediumTest {
         .build())
       .execute();
 
-    assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");
+    assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly(
+      "Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");
 
     List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
     assertThat(issues).hasSize(10);
@@ -303,7 +305,6 @@ public class IssuesMediumTest {
     issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
     assertThat(issues).hasSize(10);
 
-
     // SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules
     logTester.clear();
     result = tester.newAnalysis()
@@ -387,7 +388,8 @@ public class IssuesMediumTest {
         .build())
       .execute();
 
-    assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+    assertThat(logTester.logs(LoggerLevel.WARN)).contains(
+      "Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
 
     List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
     assertThat(issues).hasSize(10);
index 6124897f8577284fc9971e9eb0fb82dae6b60d8d..7ddbe5534e3ddc2d458d443df64f49702694fafd 100644 (file)
@@ -21,12 +21,14 @@ package org.sonar.scanner.mediumtest.log;
 
 import java.util.Collections;
 import java.util.Map;
+import javax.annotation.Priority;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.sonar.api.utils.MessageException;
 import org.sonar.batch.bootstrapper.Batch;
 import org.sonar.batch.bootstrapper.EnvironmentInformation;
 import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
+import org.springframework.beans.factory.UnsatisfiedDependencyException;
 
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
@@ -78,12 +80,12 @@ public class ExceptionHandlingMediumTest {
   @Test
   public void testWithVerbose() {
     setUp(true);
-
     assertThatThrownBy(() -> batch.execute())
-      .isInstanceOf(IllegalStateException.class)
-      .hasMessageContaining("Unable to load component class");
+      .isInstanceOf(UnsatisfiedDependencyException.class)
+      .hasMessageContaining("Error loading settings");
   }
 
+  @Priority(1)
   private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader {
     boolean withCause = false;
 
index bcef91c29acf2eed9207d74a9e294108815786f3..d2db79abfa79f4fabfe08b1715b39597442a55d0 100644 (file)
@@ -25,6 +25,7 @@ import java.io.PipedOutputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -77,8 +78,7 @@ public class ReportPublisherTest {
   private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);
   private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
   private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class);
-  private ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder,
-    new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
+  private ReportPublisher underTest;
 
   @Before
   public void setUp() {
@@ -90,6 +90,8 @@ public class ReportPublisherTest {
     when(properties.metadataFilePath()).thenReturn(reportTempFolder.newDir().toPath()
       .resolve("folder")
       .resolve("report-task.txt"));
+    underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder,
+      new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
   }
 
   @Test
@@ -109,7 +111,7 @@ public class ReportPublisherTest {
     underTest.prepareAndDumpMetadata("TASK-123");
 
     assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
-        "projectKey=org.sonarsource.sonarqube:sonarqube\n" +
+      "projectKey=org.sonarsource.sonarqube:sonarqube\n" +
         "serverUrl=https://localhost\n" +
         "serverVersion=6.4\n" +
         "dashboardUrl=https://localhost/dashboard?id=org.sonarsource.sonarqube%3Asonarqube\n" +
@@ -249,7 +251,6 @@ public class ReportPublisherTest {
   public void should_not_delete_report_if_property_is_set() throws IOException {
     when(properties.shouldKeepReport()).thenReturn(true);
     Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report");
-    Files.createDirectory(reportDir);
 
     underTest.start();
     underTest.stop();
@@ -259,7 +260,6 @@ public class ReportPublisherTest {
   @Test
   public void should_delete_report_by_default() throws IOException {
     Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report");
-    Files.createDirectory(reportDir);
 
     underTest.start();
     underTest.stop();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectScanContainerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectScanContainerTest.java
deleted file mode 100644 (file)
index 36762ca..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.scanner.scan;
-
-import org.junit.Test;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.server.ServerSide;
-import org.sonar.scanner.bootstrap.ExtensionMatcher;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ProjectScanContainerTest {
-
-  @Test
-  public void should_add_only_batch_extensions() {
-    ExtensionMatcher filter = ProjectScanContainer.getScannerProjectExtensionsFilter();
-
-    assertThat(filter.accept(new MyBatchExtension())).isTrue();
-    assertThat(filter.accept(MyBatchExtension.class)).isTrue();
-
-    assertThat(filter.accept(new MyProjectExtension())).isFalse();
-    assertThat(filter.accept(MyProjectExtension.class)).isFalse();
-    assertThat(filter.accept(new MyServerExtension())).isFalse();
-    assertThat(filter.accept(MyServerExtension.class)).isFalse();
-  }
-
-  @ScannerSide
-  @InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-  static class MyBatchExtension  {
-
-  }
-
-  @ScannerSide
-  @InstantiationStrategy(InstantiationStrategy.PER_PROJECT)
-  static class MyProjectExtension {
-
-  }
-
-  @ServerSide
-  static class MyServerExtension  {
-
-  }
-}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/SpringProjectScanContainerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/SpringProjectScanContainerTest.java
new file mode 100644 (file)
index 0000000..1d8ba32
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.scanner.scan;
+
+import org.junit.Test;
+import org.sonar.api.batch.InstantiationStrategy;
+import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.server.ServerSide;
+import org.sonar.scanner.bootstrap.ExtensionMatcher;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SpringProjectScanContainerTest {
+
+  @Test
+  public void should_add_only_batch_extensions() {
+    ExtensionMatcher filter = SpringProjectScanContainer.getScannerProjectExtensionsFilter();
+
+    assertThat(filter.accept(new MyBatchExtension())).isTrue();
+    assertThat(filter.accept(MyBatchExtension.class)).isTrue();
+
+    assertThat(filter.accept(new MyProjectExtension())).isFalse();
+    assertThat(filter.accept(MyProjectExtension.class)).isFalse();
+    assertThat(filter.accept(new MyServerExtension())).isFalse();
+    assertThat(filter.accept(MyServerExtension.class)).isFalse();
+  }
+
+  @ScannerSide
+  @InstantiationStrategy(InstantiationStrategy.PER_BATCH)
+  static class MyBatchExtension  {
+
+  }
+
+  @ScannerSide
+  @InstantiationStrategy(InstantiationStrategy.PER_PROJECT)
+  static class MyProjectExtension {
+
+  }
+
+  @ServerSide
+  static class MyServerExtension  {
+
+  }
+}
index 3266125d64a8aad29869d4c457d97a5b8ce886ce..ec873cf72ae289662cac4faf694e6a3050778c40 100644 (file)
@@ -62,18 +62,18 @@ public class WorkDirectoriesInitializerTest {
     when(root.getWorkDir()).thenReturn(rootWorkDir.toPath());
 
     assertThat(rootWorkDir.list().length).isGreaterThan(1);
-    initializer = new WorkDirectoriesInitializer(hierarchy);
+    initializer = new WorkDirectoriesInitializer();
   }
 
   @Test
   public void testNonExisting() {
     temp.delete();
-    initializer.execute();
+    initializer.execute(hierarchy);
   }
 
   @Test
   public void testClean() {
-    initializer.execute();
+    initializer.execute(hierarchy);
 
     assertThat(rootWorkDir).exists();
     assertThat(lock).exists();
@@ -89,7 +89,7 @@ public class WorkDirectoriesInitializerTest {
     moduleAWorkdir.mkdir();
     new File(moduleAWorkdir, "fooA.txt").createNewFile();
 
-    initializer.execute();
+    initializer.execute(hierarchy);
 
     assertThat(rootWorkDir).exists();
     assertThat(lock).exists();
index b036f742b039e102157bad3901a9970ddb4bea58..9ce2b0e1bd875c4a06a0559e2645e41c18bd9178 100644 (file)
@@ -51,12 +51,6 @@ public class BranchConfigurationProviderTest {
     when(reactor.getRoot()).thenReturn(root);
   }
 
-  @Test
-  public void should_cache_config() {
-    BranchConfiguration configuration = provider.provide(null, projectConfiguration, branches, pullRequests);
-    assertThat(provider.provide(null, projectConfiguration, branches, pullRequests)).isSameAs(configuration);
-  }
-
   @Test
   public void should_use_loader() {
     when(loader.load(eq(projectSettings), eq(branches), eq(pullRequests))).thenReturn(config);
index 3b19ae7cea1492fbed5444e4a54c78e91821a46f..e357a5ef36b9bdcff19c514caa950035a9be86a4 100644 (file)
@@ -41,13 +41,6 @@ public class ProjectBranchesProviderTest {
 
   }
 
-  @Test
-  public void should_cache_branches() {
-    when(scannerProperties.getProjectKey()).thenReturn("project");
-    ProjectBranches branches = provider.provide(null, scannerProperties);
-    assertThat(provider.provide(null, scannerProperties)).isSameAs(branches);
-  }
-
   @Test
   public void should_use_loader() {
     when(scannerProperties.getProjectKey()).thenReturn("key");
index 255bb37df41e54f815f9d395ea37a50ea2ed1767..5749445200b012c6c38e2ef9fdd9a45b71dae7dc 100644 (file)
@@ -41,14 +41,6 @@ public class ProjectPullRequestsProviderTest {
     scannerProperties = mock(ScannerProperties.class);
   }
 
-  @Test
-  public void cache_pull_requests() {
-    when(scannerProperties.getProjectKey()).thenReturn("project");
-    ProjectPullRequests pullRequests = provider.provide(null, scannerProperties);
-
-    assertThat(provider.provide(null, scannerProperties)).isSameAs(pullRequests);
-  }
-
   @Test
   public void should_use_loader() {
     when(scannerProperties.getProjectKey()).thenReturn("key");
index cd8987c1ea3ceb2ad2b7da15342f6e48396ba894..d8c1576c289d967bae78ecd7dd994f7b21781836 100644 (file)
@@ -134,11 +134,4 @@ public class ScmChangedFilesProviderTest {
     verify(scmProvider).branchChangedFiles("target", rootBaseDir);
   }
 
-  @Test
-  public void testCacheObject() {
-    provider.provide(scmConfiguration, branchConfiguration, project);
-    provider.provide(scmConfiguration, branchConfiguration, project);
-    verify(branchConfiguration).isPullRequest();
-  }
-
 }