]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-15994 Migrate Sonarqube IOC framework from Pico to Spring
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Tue, 1 Feb 2022 21:16:25 +0000 (15:16 -0600)
committersonartech <sonartech@sonarsource.com>
Tue, 22 Feb 2022 20:02:46 +0000 (20:02 +0000)
354 files changed:
build.gradle
server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClient.java
server/sonar-auth-bitbucket/src/test/java/org/sonar/auth/bitbucket/BitbucketModuleTest.java
server/sonar-auth-github/src/test/java/org/sonar/auth/github/GitHubModuleTest.java
server/sonar-auth-gitlab/src/test/java/org/sonar/auth/gitlab/GitLabModuleTest.java
server/sonar-auth-ldap/src/test/java/org/sonar/auth/ldap/LdapModuleTest.java
server/sonar-auth-saml/src/test/java/org/sonar/auth/saml/SamlModuleTest.java
server/sonar-ce-common/src/main/java/org/sonar/ce/configuration/WorkerCountProvider.java
server/sonar-ce-task-projectanalysis/build.gradle
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchLoader.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ContainerFactory.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ContainerFactoryImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/duplication/CrossProjectDuplicationStatusHolderImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/duplication/DuplicationMeasures.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filesystem/ComputationTempFolderProvider.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueLifecycle.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ProtoIssueCache.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/SiblingsIssueMerger.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/language/LanguageRepositoryImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/PostMeasuresComputationChecksStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/metric/MetricRepositoryImpl.java
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/step/CoverageMeasuresStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadMeasureComputersStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/TriggerViewRefreshStep.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-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/ReportTaskProcessor.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/ProjectExportContainerPopulator.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/taskprocessor/ProjectExportTaskProcessor.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/util/ProjectExportDumpFSImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectexport/util/ProjectImportDumpFSImpl.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulatorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filesystem/ComputationTempFolderProviderTest.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportComputationStepsTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ViewsCoverageMeasuresStepTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskModuleTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskProcessorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/taskprocessor/IssueSyncTaskProcessorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectexport/ProjectExportComputationStepsTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectexport/ProjectExportContainerPopulatorTest.java
server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/task/ListTaskContainer.java [new file with mode: 0644]
server/sonar-ce-task/build.gradle
server/sonar-ce-task/src/main/java/org/sonar/ce/task/container/LazyUnlessEagerAnnotationStrategy.java [new file with mode: 0644]
server/sonar-ce-task/src/main/java/org/sonar/ce/task/container/TaskContainer.java
server/sonar-ce-task/src/main/java/org/sonar/ce/task/container/TaskContainerImpl.java
server/sonar-ce-task/src/main/java/org/sonar/ce/task/setting/SettingsLoader.java
server/sonar-ce-task/src/main/java/org/sonar/ce/task/step/ComputationStepExecutor.java
server/sonar-ce-task/src/main/java/org/sonar/ce/task/step/ExecuteStatelessInitExtensionsStep.java
server/sonar-ce-task/src/test/java/org/sonar/ce/task/container/TaskContainerImplTest.java
server/sonar-ce/build.gradle
server/sonar-ce/src/main/java/org/sonar/ce/CeDistributedInformationImpl.java
server/sonar-ce/src/main/java/org/sonar/ce/configuration/CeConfigurationImpl.java
server/sonar-ce/src/main/java/org/sonar/ce/configuration/CeWorkerCountSettingWarning.java
server/sonar-ce/src/main/java/org/sonar/ce/container/CePluginRepository.java
server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
server/sonar-ce/src/main/java/org/sonar/ce/httpd/CeHttpServer.java
server/sonar-ce/src/main/java/org/sonar/ce/httpd/HttpAction.java
server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeDatabaseMBeanImpl.java
server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeTasksMBeanImpl.java
server/sonar-ce/src/main/java/org/sonar/ce/platform/ComputeEngineExtensionInstaller.java
server/sonar-ce/src/main/java/org/sonar/ce/platform/DatabaseCompatibility.java
server/sonar-ce/src/main/java/org/sonar/ce/taskprocessor/CeTaskInterrupterProvider.java
server/sonar-ce/src/main/java/org/sonar/ce/taskprocessor/CeTaskProcessorRepositoryImpl.java
server/sonar-ce/src/main/java/org/sonar/ce/taskprocessor/CeWorkerFactoryImpl.java
server/sonar-ce/src/test/java/org/sonar/ce/ComputeEngineImplTest.java
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeDatabaseMBeanImplTest.java
server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java
server/sonar-ce/src/test/java/org/sonar/ce/platform/CECoreExtensionsInstallerTest.java
server/sonar-ce/src/test/java/org/sonar/ce/taskprocessor/CeTaskInterrupterProviderTest.java
server/sonar-ce/src/test/java/org/sonar/ce/taskprocessor/CeTaskProcessorModuleTest.java
server/sonar-db-core/build.gradle
server/sonar-db-core/src/main/java/org/sonar/db/Database.java
server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
server/sonar-db-dao/src/main/java/org/sonar/db/audit/NoOpAuditPersister.java
server/sonar-db-dao/src/main/java/org/sonar/db/property/InternalPropertiesDao.java
server/sonar-db-dao/src/test/java/org/sonar/db/DaoModuleTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/MyBatisTest.java
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/FastSpringContainer.java [new file with mode: 0644]
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/SQDatabase.java
server/sonar-db-migration/build.gradle
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigration.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MigrationConfigurationModule.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MigrationEngineModule.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/charset/DatabaseCharsetChecker.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationContainerImpl.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationContainerPopulatorImpl.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImpl.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/MigrationStepsExecutorImpl.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/MigrationStepsProvider.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/DbVersion.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/MigrationConfigurationModuleTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/MigrationEngineModuleTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/MigrationContainerImplTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/MigrationContainerPopulatorImplTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImplTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/SimpleMigrationContainer.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/step/MigrationStepsExecutorImplTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/step/MigrationStepsProviderTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v00/DbVersion00Test.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v90/DbVersion90Test.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v91/DbVersion91Test.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v92/DbVersion92Test.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v93/DbVersion93Test.java
server/sonar-process/src/main/java/org/sonar/process/cluster/health/SharedHealthStateImpl.java
server/sonar-server-common/src/main/java/org/sonar/server/async/AsyncExecutionMBeanImpl.java
server/sonar-server-common/src/main/java/org/sonar/server/component/index/ComponentIndexDefinition.java
server/sonar-server-common/src/main/java/org/sonar/server/config/ConfigurationProvider.java
server/sonar-server-common/src/main/java/org/sonar/server/es/EsClientProvider.java
server/sonar-server-common/src/main/java/org/sonar/server/es/EsClientStopper.java [deleted file]
server/sonar-server-common/src/main/java/org/sonar/server/es/EsModule.java
server/sonar-server-common/src/main/java/org/sonar/server/extension/CoreExtensionBootstraper.java
server/sonar-server-common/src/main/java/org/sonar/server/extension/CoreExtensionBridge.java
server/sonar-server-common/src/main/java/org/sonar/server/extension/CoreExtensionStopper.java
server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
server/sonar-server-common/src/main/java/org/sonar/server/issue/workflow/IssueWorkflow.java
server/sonar-server-common/src/main/java/org/sonar/server/log/ServerLogging.java
server/sonar-server-common/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndexDefinition.java
server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java
server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java
server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationService.java
server/sonar-server-common/src/main/java/org/sonar/server/platform/ServerFileSystemImpl.java
server/sonar-server-common/src/main/java/org/sonar/server/platform/ServerLifecycleNotifier.java
server/sonar-server-common/src/main/java/org/sonar/server/platform/StartupMetadataProvider.java
server/sonar-server-common/src/main/java/org/sonar/server/platform/TempFolderProvider.java
server/sonar-server-common/src/main/java/org/sonar/server/plugins/InstalledPluginReferentialFactory.java
server/sonar-server-common/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java
server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java
server/sonar-server-common/src/main/java/org/sonar/server/setting/ThreadLocalSettings.java
server/sonar-server-common/src/main/java/org/sonar/server/util/OkHttpClientProvider.java
server/sonar-server-common/src/main/java/org/sonar/server/util/StoppableExecutorService.java
server/sonar-server-common/src/main/java/org/sonar/server/util/StoppableScheduledExecutorService.java
server/sonar-server-common/src/test/java/org/sonar/server/es/EsClientProviderTest.java
server/sonar-server-common/src/test/java/org/sonar/server/es/EsClientStopperTest.java [deleted file]
server/sonar-server-common/src/test/java/org/sonar/server/es/EsModuleTest.java
server/sonar-server-common/src/test/java/org/sonar/server/extension/CoreExtensionBootstraperTest.java
server/sonar-server-common/src/test/java/org/sonar/server/extension/CoreExtensionStopperTest.java
server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/IssuesChangesNotificationModuleTest.java
server/sonar-server-common/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java
server/sonar-server-common/src/test/java/org/sonar/server/platform/StartupMetadataProviderTest.java
server/sonar-server-common/src/test/java/org/sonar/server/platform/TempFolderProviderTest.java
server/sonar-server-common/src/test/java/org/sonar/server/plugins/ServerExtensionInstallerTest.java
server/sonar-server-common/src/test/java/org/sonar/server/util/OkHttpClientProviderTest.java
server/sonar-server-common/src/test/java/org/sonar/server/webhook/WebhookModuleTest.java
server/sonar-webserver-api/src/main/java/org/sonar/server/branch/BranchFeatureProxyImpl.java
server/sonar-webserver-api/src/main/java/org/sonar/server/platform/Platform.java
server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginConsentVerifier.java
server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginDownloader.java
server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginJarLoader.java
server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginUninstaller.java
server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/ServerPluginManager.java
server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/WebServerExtensionInstaller.java
server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java
server/sonar-webserver-api/src/main/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImpl.java
server/sonar-webserver-api/src/main/java/org/sonar/server/setting/SettingsChangeNotifier.java
server/sonar-webserver-api/src/test/java/org/sonar/server/branch/BranchFeatureProxyImplTest.java
server/sonar-webserver-api/src/test/java/org/sonar/server/qualitygate/changeevent/QGChangeEventListenersImplTest.java
server/sonar-webserver-api/src/test/java/org/sonar/server/util/TypeValidationModuleTest.java
server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/IdentityProviderRepository.java
server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/LogOAuthWarning.java
server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/RequestAuthenticatorImpl.java
server/sonar-webserver-auth/src/main/java/org/sonar/server/user/NewUserNotifier.java
server/sonar-webserver-auth/src/main/java/org/sonar/server/user/SecurityRealmFactory.java
server/sonar-webserver-auth/src/main/java/org/sonar/server/user/UserUpdater.java
server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/AuthenticationModuleTest.java
server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/IdentityProviderRepositoryTest.java
server/sonar-webserver-auth/src/test/java/org/sonar/server/usertoken/UserTokenModuleTest.java
server/sonar-webserver-auth/src/testFixtures/java/org/sonar/server/authentication/IdentityProviderRepositoryRule.java
server/sonar-webserver-core/build.gradle
server/sonar-webserver-core/src/main/java/org/sonar/server/notification/NotificationDaemon.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ClusterVerification.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/DefaultServerUpgradeStatus.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/db/CheckDatabaseCharsetAtStartup.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/db/EmbeddedDatabase.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/db/EmbeddedDatabaseFactory.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/BaseSectionMBean.java
server/sonar-webserver-core/src/main/java/org/sonar/server/platform/serverid/ServerIdManager.java
server/sonar-webserver-core/src/main/java/org/sonar/server/qualitygate/ProjectsInWarningDaemon.java
server/sonar-webserver-core/src/main/java/org/sonar/server/rule/RegisterRules.java
server/sonar-webserver-core/src/main/java/org/sonar/server/rule/RuleDefinitionsLoader.java
server/sonar-webserver-core/src/main/java/org/sonar/server/startup/LogServerId.java
server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RegisterMetrics.java
server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RegisterPermissionTemplates.java
server/sonar-webserver-core/src/main/java/org/sonar/server/startup/RenameDeprecatedPropertyKeys.java
server/sonar-webserver-core/src/main/java/org/sonar/server/startup/UpgradeSuggestionsCleaner.java
server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/TelemetryDaemon.java
server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/TelemetryDataLoaderImpl.java
server/sonar-webserver-core/src/test/java/org/sonar/server/ce/CeModuleTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/notification/NotificationModuleTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/SystemInfoWriterModuleTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/WebCoreExtensionsInstallerTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/serverid/ServerIdModuleTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/web/requestid/HttpRequestIdModuleTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/qualitygate/ProjectsInWarningModuleTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/telemetry/TelemetryDataLoaderImplTest.java
server/sonar-webserver-core/src/test/java/org/sonar/server/updatecenter/UpdateCenterModuleTest.java
server/sonar-webserver-es/src/main/java/org/sonar/server/es/IndexCreator.java
server/sonar-webserver-es/src/main/java/org/sonar/server/es/IndexDefinitions.java
server/sonar-webserver-es/src/main/java/org/sonar/server/permission/index/PermissionIndexer.java
server/sonar-webserver-es/src/test/java/org/sonar/server/measure/index/ProjectsEsModuleTest.java
server/sonar-webserver-monitoring/src/main/java/org/sonar/server/monitoring/MainCollector.java
server/sonar-webserver-pushapi/src/test/java/org/sonar/server/pushapi/ServerPushWsModuleTest.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/BatchIndex.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/queue/BranchSupport.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/queue/CeQueueCleaner.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ce/ws/WorkerCountAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/duplication/ws/ShowResponseBuilder.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/health/HealthCheckerImpl.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/language/LanguageValidation.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/notification/ws/NotificationCenter.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/LivenessCheckerImpl.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/builtin/BuiltInQProfileLoader.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/builtin/BuiltInQProfileRepositoryImpl.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/CreateAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/ExportersAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/ImportersAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/PageRepository.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/WebAnalyticsLoaderImpl.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UsersWsModule.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almintegration/ws/AlmIntegrationsWSModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/AlmSettingsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/authentication/ws/AuthenticationWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/badge/ws/ProjectBadgesWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/batch/BatchWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/pr/ws/PullRequestWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/BranchWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/queue/BranchSupportTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/queue/ReportSubmitterTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ce/ws/CeWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/component/ws/ComponentsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/email/ws/EmailsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/favorite/FavoriteModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/favorite/ws/FavoriteWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/health/NodeHealthModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/HotspotsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/IssueWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/measure/live/LiveMeasureModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/measure/ws/MeasuresWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/metric/ws/MetricsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/monitoring/MonitoringWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/newcodeperiod/ws/NewCodePeriodsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/notification/ws/NotificationWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/permission/ws/PermissionsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/ChangeLogLevelServiceModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/HealthCheckerModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/LivenessCheckerImplTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SafeModeHealthCheckerModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SafemodeSystemWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SystemWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/ProjectsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/projectanalysis/ws/ProjectAnalysisWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/projectlink/ws/ProjectLinksWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/projecttag/ws/ProjectTagsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/root/ws/RootsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/ws/SettingsWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/source/ws/SourceWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/WebAnalyticsLoaderImplTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ui/ws/NavigationWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/ChangePasswordActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/CreateActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/usergroups/ws/UserGroupsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/usertoken/ws/UserTokenWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/ws/ws/WebServicesWsModuleTest.java
server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/WebServiceEngine.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/PlatformImpl.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel3.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelSafeMode.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelStartup.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/web/MasterServletFilter.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/web/RegisterServletFilters.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/web/RequestIdFilter.java
server/sonar-webserver/src/main/java/org/sonar/server/platform/web/UserSessionFilter.java
server/sonar-webserver/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevel1Test.java
server/sonar-webserver/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevel2Test.java
server/sonar-webserver/src/test/java/org/sonar/server/platform/platformlevel/PlatformLevelTest.java
server/sonar-webserver/src/test/java/org/sonar/server/platform/web/RequestIdFilterTest.java
server/sonar-webserver/src/test/java/org/sonar/server/platform/web/UserSessionFilterTest.java
sonar-core/build.gradle
sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsInstaller.java
sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java
sonar-core/src/main/java/org/sonar/core/language/LanguagesProvider.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/ClassDerivedBeanDefinition.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java [deleted file]
sonar-core/src/main/java/org/sonar/core/platform/Container.java
sonar-core/src/main/java/org/sonar/core/platform/LazyStrategy.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/LazyUnlessStartableStrategy.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/ListContainer.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/Module.java
sonar-core/src/main/java/org/sonar/core/platform/PicoUtils.java [deleted file]
sonar-core/src/main/java/org/sonar/core/platform/PriorityBeanFactory.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/SpringComponentContainer.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/SpringInitStrategy.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/StartableBeanPostProcessor.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/platform/StartableCloseableSafeLifecyleStrategy.java [deleted file]
sonar-core/src/main/java/org/sonar/core/platform/StartableContainer.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/util/UuidFactoryImpl.java
sonar-core/src/test/java/org/sonar/core/extension/CoreExtensionsInstallerTest.java
sonar-core/src/test/java/org/sonar/core/language/LanguagesProviderTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/platform/ComponentContainerTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/platform/LazyUnlessStartableStrategyTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/platform/ListContainerTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/platform/ModuleTest.java
sonar-core/src/test/java/org/sonar/core/platform/PicoUtilsTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/platform/PriorityBeanFactoryTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/platform/SpringComponentContainerTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/platform/StartableBeanPostProcessorTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/platform/StartableCloseableSafeLifecyleStrategyTest.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/resources/Languages.java
sonar-scanner-engine/build.gradle
sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ClassDerivedBeanDefinition.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalTempFolderProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessor.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PriorityBeanFactory.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringComponentContainer.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessor.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputProjectProvider.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/LanguagesProvider.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringModuleScanContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringProjectScanContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoriesInitializer.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/test/java/org/sonar/scanner/bootstrap/ExtensionInstallerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessorTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionaryTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionaryTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PriorityBeanFactoryTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringComponentContainerTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessorTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/extension/ScannerCoreExtensionsInstallerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/NoLanguagesPluginsMediumTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoriesInitializerTest.java

index e674806af4161e3bebe8705e3d13dd674a6e0af0..aed914a0d00a4221290d69b6a576c9e60d922ecc 100644 (file)
@@ -405,7 +405,6 @@ subprojects {
       }
       dependency 'org.mybatis:mybatis:3.5.9'
       dependency 'org.nanohttpd:nanohttpd:2.3.1'
-      dependency 'org.picocontainer:picocontainer:2.15'
       dependencySet(group: 'org.slf4j', version: '1.7.30') {
         entry 'jcl-over-slf4j'
         entry 'jul-to-slf4j'
index 71d08189bd9b739c6f8e930d45452ea25d2b0fef..f84d1e6b4585034266357393dc8a28d52c912b24 100644 (file)
@@ -27,6 +27,7 @@ import java.util.Objects;
 import java.util.function.Function;
 import java.util.function.UnaryOperator;
 import javax.annotation.Nullable;
+import javax.inject.Inject;
 import okhttp3.Credentials;
 import okhttp3.FormBody;
 import okhttp3.HttpUrl;
@@ -60,6 +61,7 @@ public class BitbucketCloudRestClient {
   private final String bitbucketCloudEndpoint;
   private final String accessTokenEndpoint;
 
+  @Inject
   public BitbucketCloudRestClient(OkHttpClient okHttpClient) {
     this(okHttpClient, ENDPOINT, ACCESS_TOKEN_ENDPOINT);
   }
index 7206c1e22d8f98f0d1e09e928e65a152964f4949..de3bc3b67e66da6b7b51d2c2f46836200610ab96 100755 (executable)
 package org.sonar.auth.bitbucket;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class BitbucketModuleTest {
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new BitbucketModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 9);
+    assertThat(container.getAddedObjects()).hasSize(9);
   }
 
 }
index 0592b53e50e586fe383a422d619acb92aae3a238..f05919bc5186797f39ea5302faa0c7a43c97cc83 100644 (file)
 package org.sonar.auth.github;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class GitHubModuleTest {
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new GitHubModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 13);
+    assertThat(container.getAddedObjects()).hasSize(13);
   }
 
 }
index 5139aa62c72dbb29042d8acbbeddb51ea86895b2..1e4cff031d1b5e01cd8d839b2285e5747d081023 100644 (file)
  */
 package org.sonar.auth.gitlab;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.Container;
 
+import static java.util.Collections.unmodifiableList;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class GitLabModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new GitLabModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 10);
+    assertThat(container.getAddedObjects()).hasSize(10);
   }
 
+  private static class ListContainer implements Container {
+    private final List<Object> objects = new ArrayList<>();
+
+    @Override
+    public Container add(Object... objects) {
+      this.objects.add(objects);
+      return this;
+    }
+
+    public List<Object> getAddedObjects() {
+      return unmodifiableList(new ArrayList<>(objects));
+    }
+
+    @Override
+    public <T> T getComponentByType(Class<T> type) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> Optional<T> getOptionalComponentByType(Class<T> type) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> List<T> getComponentsByType(Class<T> type) {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Container getParent() {
+      throw new UnsupportedOperationException();
+    }
+  }
 }
index 73455f48e7d3410dcd9582898d728f9f1654bd38..6496078dcc9d7993b63a19802be73d2eb0639fee 100644 (file)
 package org.sonar.auth.ldap;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class LdapModuleTest {
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new LdapModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 3);
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
 
 }
index 034352c9f6a98b5d1a0f48f92a57acd6e0121bc1..2479812fcfb122f1d62260230400541f75ea839e 100644 (file)
 package org.sonar.auth.saml;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class SamlModuleTest {
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new SamlModule().configure(container);
-    assertThat(container.size()).isGreaterThan(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER);
+    assertThat(container.getAddedObjects()).hasSize(13);
   }
 }
index 875eb00c85110201570acf67d9d275dc0bf16861..3328cd7101639afd442d440104afbcbb76662b1a 100644 (file)
@@ -23,7 +23,7 @@ import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.server.ServerSide;
 
 /**
- * When an implementation of this interface is available in Pico, the Compute Engine will use the value returned by
+ * When an implementation of this interface is available in the ioc container, the Compute Engine will use the value returned by
  * {@link #get()} as the number of worker the Compute Engine should run on.
  */
 @ComputeEngineSide
index b6d0b390b0dbba9eca5c91cde4ef2f9ba93385a1..bca65c795f67c91ddac7ba6725467dd05c53206e 100644 (file)
@@ -29,7 +29,6 @@ dependencies {
   compile 'com.google.protobuf:protobuf-java'
   compile 'com.googlecode.java-diff-utils:diffutils'
   compile 'org.mybatis:mybatis'
-  compile 'org.picocontainer:picocontainer'
 
   compile project(':sonar-core')
   compile project(':server:sonar-ce-common')
index 3ede8d763729eeff5dc235d68787db4b1f5fe5f0..b7ec255e4b02bdfd019fcd9c36b19bff741d3dc4 100644 (file)
@@ -72,14 +72,6 @@ public class PostProjectAnalysisTasksExecutor implements ComputationStepExecutor
   private final PostProjectAnalysisTask[] postProjectAnalysisTasks;
   private final BatchReportReader reportReader;
 
-  /**
-   * Constructor used by Pico when there is no {@link PostProjectAnalysisTask} in the container.
-   */
-  public PostProjectAnalysisTasksExecutor(org.sonar.ce.task.CeTask ceTask, AnalysisMetadataHolder analysisMetadataHolder,
-    QualityGateHolder qualityGateHolder, QualityGateStatusHolder qualityGateStatusHolder, BatchReportReader reportReader) {
-    this(ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader, null);
-  }
-
   public PostProjectAnalysisTasksExecutor(org.sonar.ce.task.CeTask ceTask, AnalysisMetadataHolder analysisMetadataHolder, QualityGateHolder qualityGateHolder,
     QualityGateStatusHolder qualityGateStatusHolder, BatchReportReader reportReader, @Nullable PostProjectAnalysisTask[] postProjectAnalysisTasks) {
     this.analysisMetadataHolder = analysisMetadataHolder;
index b9253ca52132e9377ff3703c05bcc077b57538e1..3eb24b243ac83ee028a9bcae27bc87452715640a 100644 (file)
  */
 package org.sonar.ce.task.projectanalysis.component;
 
-import javax.annotation.Nullable;
 import org.sonar.api.utils.MessageException;
 import org.sonar.ce.task.projectanalysis.analysis.MutableAnalysisMetadataHolder;
 import org.sonar.scanner.protocol.output.ScannerReport;
-
 import static org.sonar.scanner.protocol.output.ScannerReport.Metadata.BranchType.UNSET;
 
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+
 public class BranchLoader {
   private final MutableAnalysisMetadataHolder metadataHolder;
   private final BranchLoaderDelegate delegate;
@@ -34,6 +35,7 @@ public class BranchLoader {
     this(metadataHolder, null);
   }
 
+  @Inject
   public BranchLoader(MutableAnalysisMetadataHolder metadataHolder, @Nullable BranchLoaderDelegate delegate) {
     this.metadataHolder = metadataHolder;
     this.delegate = delegate;
index 12638017f9f8a14d5b15ba9d6f7b0f98b7be1a6c..7ceb456ab1278b55257ccb007acd0094947a8c0b 100644 (file)
@@ -22,9 +22,9 @@ package org.sonar.ce.task.projectanalysis.container;
 import javax.annotation.Nullable;
 import org.sonar.ce.task.CeTask;
 import org.sonar.ce.task.container.TaskContainer;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
 public interface ContainerFactory {
 
-  TaskContainer create(ComponentContainer parent, CeTask task, @Nullable ReportAnalysisComponentProvider[] componentProviders);
+  TaskContainer create(SpringComponentContainer parent, CeTask task, @Nullable ReportAnalysisComponentProvider[] componentProviders);
 }
index c6635e05877a9eb403ba905712e1ff66b182f6d9..7e58e1b22ed93564657c88765f9fa3c0f65361b0 100644 (file)
@@ -23,11 +23,11 @@ import javax.annotation.Nullable;
 import org.sonar.ce.task.CeTask;
 import org.sonar.ce.task.container.TaskContainer;
 import org.sonar.ce.task.container.TaskContainerImpl;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
 public class ContainerFactoryImpl implements ContainerFactory {
   @Override
-  public TaskContainer create(ComponentContainer parent, CeTask task, @Nullable ReportAnalysisComponentProvider[] componentProviders) {
+  public TaskContainer create(SpringComponentContainer parent, CeTask task, @Nullable ReportAnalysisComponentProvider[] componentProviders) {
     return new TaskContainerImpl(parent, new ProjectAnalysisTaskContainerPopulator(task, componentProviders));
   }
 }
index 4764a7a94462cf73f635515acbf1e03ef04663aa..faa28a22ba6aac13cb32b642897ed227c5e19116 100644 (file)
@@ -165,15 +165,15 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop
     container.add(SettingsLoader.class);
     container.add(task);
     container.add(steps);
-    container.addSingletons(componentClasses());
+    container.add(componentClasses());
     for (ReportAnalysisComponentProvider componentProvider : componentProviders) {
-      container.addSingletons(componentProvider.getComponents());
+      container.add(componentProvider.getComponents());
     }
-    container.addSingletons(steps.orderedStepClasses());
+    container.add(steps.orderedStepClasses());
   }
 
   /**
-   * List of all objects to be injected in the picocontainer dedicated to computation stack.
+   * List of all objects to be injected in the ioc container dedicated to computation stack.
    * Does not contain the steps declared in {@link ReportComputationSteps#orderedStepClasses()}.
    */
   private static List<Object> componentClasses() {
@@ -191,7 +191,7 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop
       new ComputationTempFolderProvider(),
 
       ReportModulesPath.class,
-      MetricModule.class,
+      new MetricModule(),
 
       // holders
       AnalysisMetadataHolderImpl.class,
index 3ba3eec0dafbc8136b984750d6435c783f6b7fa1..0091e343184e585f9fa26aa3311ae9c37f0e3e93 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.ce.task.projectanalysis.duplication;
 
 import javax.annotation.CheckForNull;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
index f180f5a5bbbf964af09bf6bd9bf55bc29f8601e9..103ef9dd4ceb64629a30d7f068cab5b976d8e509 100644 (file)
@@ -26,6 +26,7 @@ import java.util.Optional;
 import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+import javax.inject.Inject;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.ce.task.projectanalysis.component.PathAwareCrawler;
 import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
@@ -53,6 +54,7 @@ public class DuplicationMeasures {
   protected final MeasureRepository measureRepository;
   private final DuplicationRepository duplicationRepository;
 
+  @Inject
   public DuplicationMeasures(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository,
     @Nullable DuplicationRepository duplicationRepository) {
     this.treeRootHolder = treeRootHolder;
@@ -63,9 +65,6 @@ public class DuplicationMeasures {
     this.formulas = List.of(new DuplicationFormula());
   }
 
-  /**
-   * Constructor used by Pico in Views where no DuplicationRepository is available.
-   */
   public DuplicationMeasures(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) {
     this(treeRootHolder, metricRepository, measureRepository, null);
   }
index 49487780cf33364b5812ddd31a0d8c064cba71fd..90ef49f2328b1535611ccae4c1d3730eb5098134 100644 (file)
@@ -21,64 +21,27 @@ package org.sonar.ce.task.projectanalysis.filesystem;
 
 import java.io.File;
 import java.io.IOException;
-import javax.annotation.CheckForNull;
 import org.apache.commons.io.FileUtils;
-import org.picocontainer.ComponentLifecycle;
-import org.picocontainer.PicoContainer;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.impl.utils.DefaultTempFolder;
 import org.sonar.api.utils.TempFolder;
 import org.sonar.server.platform.ServerFileSystem;
+import org.springframework.context.annotation.Bean;
 
 /**
  * Provides a TempFolder instance pointing to a directory dedicated to the processing of a specific item.
  * This directory will be deleted at the end of the processing.
  * This directory is located in the "ce" directory of the temp directory of the SonarQube instance.
  */
-public class ComputationTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
-  private boolean started = false;
-  @CheckForNull
-  private DefaultTempFolder tempFolder = null;
-
+public class ComputationTempFolderProvider {
+  @Bean("ComputationTempFolder")
   public TempFolder provide(ServerFileSystem fs) {
-    if (this.tempFolder == null) {
-      File tempDir = new File(fs.getTempDir(), "ce");
-      try {
-        FileUtils.forceMkdir(tempDir);
-      } catch (IOException e) {
-        throw new IllegalStateException("Unable to create computation temp directory " + tempDir, e);
-      }
-      File computationDir = new DefaultTempFolder(tempDir).newDir();
-      this.tempFolder = new DefaultTempFolder(computationDir, true);
+    File tempDir = new File(fs.getTempDir(), "ce");
+    try {
+      FileUtils.forceMkdir(tempDir);
+    } catch (IOException e) {
+      throw new IllegalStateException("Unable to create computation temp directory " + tempDir, e);
     }
-    return this.tempFolder;
-  }
-
-  @Override
-  public void start(PicoContainer container) {
-    this.started = true;
+    File computationDir = new DefaultTempFolder(tempDir).newDir();
+    return new DefaultTempFolder(computationDir, true);
   }
-
-  @Override
-  public void stop(PicoContainer container) {
-    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;
-  }
-
 }
index 60fa00dea494baac580a2252cc2f22b084d465a5..b57b06cbd0096b0167f6f0b3dd8b4734e31b5c18 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import java.util.Date;
 import java.util.Optional;
+import javax.inject.Inject;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.rules.RuleType;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
@@ -54,6 +55,7 @@ public class IssueLifecycle {
   private final DebtCalculator debtCalculator;
   private final AnalysisMetadataHolder analysisMetadataHolder;
 
+  @Inject
   public IssueLifecycle(AnalysisMetadataHolder analysisMetadataHolder, IssueWorkflow workflow, IssueFieldsSetter updater, DebtCalculator debtCalculator,
     RuleRepository ruleRepository) {
     this(analysisMetadataHolder, IssueChangeContext.createScan(new Date(analysisMetadataHolder.getAnalysisDate())), workflow, updater, debtCalculator, ruleRepository);
index 38a5c6373f496435c8f89a86452ba7ad582de05b..c2e460dd80dcae00f64d9370b6e2e6c1f5c6411a 100644 (file)
  */
 package org.sonar.ce.task.projectanalysis.issue;
 
-import java.io.File;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.TempFolder;
 import org.sonar.ce.task.projectanalysis.util.cache.ProtobufIssueDiskCache;
 
+import javax.inject.Inject;
+import java.io.File;
+
 /**
  * Cache of all the issues involved in the analysis. Their state is as it will be
  * persisted in database (after issue tracking, auto-assignment, ...)
  */
 public class ProtoIssueCache extends ProtobufIssueDiskCache {
-
-  // this constructor is used by picocontainer
+  @Inject
   public ProtoIssueCache(TempFolder tempFolder, System2 system2) {
     super(tempFolder.newFile("issues", ".dat"), system2);
   }
index cb9310473b4c1e05adbdc9b1ad4de02efab9bfba..2d4492bd0666142b8ec87d291c0c29ba390d7fa1 100644 (file)
@@ -25,16 +25,19 @@ import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.tracking.SimpleTracker;
 import org.sonar.core.issue.tracking.Tracking;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class SiblingsIssueMerger {
   private final SiblingsIssuesLoader siblingsIssuesLoader;
   private final SimpleTracker<DefaultIssue, SiblingIssue> tracker;
   private final IssueLifecycle issueLifecycle;
 
+  @Autowired(required = false)
   public SiblingsIssueMerger(SiblingsIssuesLoader resolvedSiblingsIssuesLoader, IssueLifecycle issueLifecycle) {
     this(resolvedSiblingsIssuesLoader, new SimpleTracker<>(), issueLifecycle);
   }
 
+  @Autowired(required = false)
   public SiblingsIssueMerger(SiblingsIssuesLoader siblingsIssuesLoader, SimpleTracker<DefaultIssue, SiblingIssue> tracker, IssueLifecycle issueLifecycle) {
     this.siblingsIssuesLoader = siblingsIssuesLoader;
     this.tracker = tracker;
index 544766e10260c8b11fbe67e248cdbfec530e1a50..33a36e45fa4f2e8aa81940596f3014aae6b8fae8 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.Optional;
 import javax.annotation.Nonnull;
 import org.sonar.api.resources.Language;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static com.google.common.base.Predicates.notNull;
 import static com.google.common.collect.Iterables.filter;
@@ -38,10 +39,12 @@ public class LanguageRepositoryImpl implements LanguageRepository {
 
   private final Map<String, Language> languagesByKey;
 
+  @Autowired(required = false)
   public LanguageRepositoryImpl() {
     this.languagesByKey = Collections.emptyMap();
   }
 
+  @Autowired(required = false)
   public LanguageRepositoryImpl(Language... languages) {
     this.languagesByKey = uniqueIndex(filter(asList(languages), notNull()), LanguageToKey.INSTANCE);
   }
index a0826dea9a7bb60a10ff308df50172be763b14b2..1cc12aa21dd62bf905dd8f3ddcd2adf334f8228f 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
 import org.sonar.ce.task.projectanalysis.metric.Metric;
 import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
 import org.sonar.ce.task.step.ComputationStep;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Execute {@link PostMeasuresComputationCheck} instances in no specific order.
@@ -43,6 +44,7 @@ public class PostMeasuresComputationChecksStep implements ComputationStep {
   private final AnalysisMetadataHolder analysisMetadataHolder;
   private final PostMeasuresComputationCheck[] extensions;
 
+  @Autowired(required = false)
   public PostMeasuresComputationChecksStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository,
     AnalysisMetadataHolder analysisMetadataHolder, PostMeasuresComputationCheck[] extensions) {
     this.treeRootHolder = treeRootHolder;
@@ -55,6 +57,7 @@ public class PostMeasuresComputationChecksStep implements ComputationStep {
   /**
    * Used when zero {@link PostMeasuresComputationCheck} are registered into container.
    */
+  @Autowired(required = false)
   public PostMeasuresComputationChecksStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository,
     AnalysisMetadataHolder analysisMetadataHolder) {
     this(treeRootHolder, metricRepository, measureRepository, analysisMetadataHolder, new PostMeasuresComputationCheck[0]);
index dd122c1f692bec991a8457c1eed49d4e3ac46b05..c94934e0a3e16b263c1ca4a691195fbc18f907d0 100644 (file)
@@ -24,7 +24,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import javax.annotation.CheckForNull;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.metric.MetricDto;
index ad981b68bba6038bdeaa5353ad6095b72b2dedcf..708b35f6b7f7256cdddf38009eb893325a26f9b3 100644 (file)
@@ -37,14 +37,6 @@ public abstract class AbstractComputationSteps implements ComputationSteps {
 
   @Override
   public Iterable<ComputationStep> instances() {
-    return Iterables.transform(
-      orderedStepClasses(),
-      input -> {
-        ComputationStep computationStepType = container.getComponentByType(input);
-        if (computationStepType == null) {
-          throw new IllegalStateException(String.format("Component not found: %s", input));
-        }
-        return computationStepType;
-      });
+    return Iterables.transform(orderedStepClasses(), container::getComponentByType);
   }
 }
index 7d9ae017ac006b7972869ec6149c2cc7709d12aa..2db3a2d6e13976900bf507ea3dd15809e56f21cc 100644 (file)
@@ -20,6 +20,8 @@
 package org.sonar.ce.task.projectanalysis.step;
 
 import java.util.List;
+import javax.annotation.Nullable;
+import javax.inject.Inject;
 import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
 import org.sonar.ce.task.projectanalysis.component.Component;
 import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
@@ -77,7 +79,8 @@ public class CoverageMeasuresStep implements ComputationStep {
   /**
    * Constructor used when processing a Report (ie. a {@link BatchReportReader} instance is available in the container)
    */
-  public CoverageMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository, BatchReportReader reportReader) {
+  @Inject
+  public CoverageMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository, @Nullable BatchReportReader reportReader) {
     this.treeRootHolder = treeRootHolder;
     this.metricRepository = metricRepository;
     this.measureRepository = measureRepository;
@@ -88,20 +91,6 @@ public class CoverageMeasuresStep implements ComputationStep {
     this.uncoveredConditionsMetric = metricRepository.getByKey(UNCOVERED_CONDITIONS_KEY);
   }
 
-  /**
-   * Constructor used when processing Views (ie. no {@link BatchReportReader} instance is available in the container)
-   */
-  public CoverageMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) {
-    this.treeRootHolder = treeRootHolder;
-    this.metricRepository = metricRepository;
-    this.measureRepository = measureRepository;
-    this.linesToCoverMetric = metricRepository.getByKey(LINES_TO_COVER_KEY);
-    this.uncoveredLinesMetric = metricRepository.getByKey(UNCOVERED_LINES_KEY);
-    this.conditionsToCoverMetric = metricRepository.getByKey(CONDITIONS_TO_COVER_KEY);
-    this.uncoveredConditionsMetric = metricRepository.getByKey(UNCOVERED_CONDITIONS_KEY);
-    this.reportReader = null;
-  }
-
   @Override
   public void execute(ComputationStep.Context context) {
     if (reportReader != null) {
@@ -109,7 +98,7 @@ public class CoverageMeasuresStep implements ComputationStep {
     }
     new PathAwareCrawler<>(
       FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository).buildFor(COVERAGE_FORMULAS))
-        .visit(treeRootHolder.getReportTreeRoot());
+      .visit(treeRootHolder.getReportTreeRoot());
   }
 
   private class FileCoverageVisitor extends TypeAwareVisitorAdapter {
index 9f6e3b045ac21d63ffb84ca472e2aa547f30caac..ee8d604da2dd1f7b21790e912f7ef25d49639b3d 100644 (file)
@@ -40,6 +40,7 @@ import org.sonar.ce.task.projectanalysis.api.measurecomputer.MeasureComputerDefi
 import org.sonar.ce.task.projectanalysis.api.measurecomputer.MeasureComputerWrapper;
 import org.sonar.ce.task.projectanalysis.measure.MutableMeasureComputersHolder;
 import org.sonar.ce.task.step.ComputationStep;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.FluentIterable.from;
@@ -53,6 +54,7 @@ public class LoadMeasureComputersStep implements ComputationStep {
   private final MutableMeasureComputersHolder measureComputersHolder;
   private final MeasureComputer[] measureComputers;
 
+  @Autowired(required = false)
   public LoadMeasureComputersStep(MutableMeasureComputersHolder measureComputersHolder, Metrics[] metricsRepositories, MeasureComputer[] measureComputers) {
     this.measureComputersHolder = measureComputersHolder;
     this.measureComputers = measureComputers;
@@ -63,22 +65,25 @@ public class LoadMeasureComputersStep implements ComputationStep {
   }
 
   /**
-   * Constructor override used by Pico to instantiate the class when no plugin is defining metrics
+   * Constructor override used by the ioc container to instantiate the class when no plugin is defining metrics
    */
+  @Autowired(required = false)
   public LoadMeasureComputersStep(MutableMeasureComputersHolder measureComputersHolder, MeasureComputer[] measureComputers) {
     this(measureComputersHolder, new Metrics[] {}, measureComputers);
   }
 
   /**
-   * Constructor override used by Pico to instantiate the class when no plugin is defining measure computers
+   * Constructor override used by the ioc container to instantiate the class when no plugin is defining measure computers
    */
+  @Autowired(required = false)
   public LoadMeasureComputersStep(MutableMeasureComputersHolder measureComputersHolder, Metrics[] metricsRepositories) {
     this(measureComputersHolder, metricsRepositories, new MeasureComputer[] {});
   }
 
   /**
-   * Constructor override used by Pico to instantiate the class when no plugin is defining metrics neither measure computers
+   * Constructor override used by the ioc container to instantiate the class when no plugin is defining metrics neither measure computers
    */
+  @Autowired(required = false)
   public LoadMeasureComputersStep(MutableMeasureComputersHolder measureComputersHolder) {
     this(measureComputersHolder, new Metrics[] {}, new MeasureComputer[] {});
   }
index b6333ee3bb44f600ac381ba3c554c64d80a4e2d6..60cb4bc9d10ef308dc92b77e2620962d33080773 100644 (file)
@@ -23,6 +23,7 @@ import java.util.OptionalInt;
 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
 import org.sonar.ce.task.projectanalysis.view.TriggerViewRefreshDelegate;
 import org.sonar.ce.task.step.ComputationStep;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * This step will trigger refresh of Portfolios and Applications that include the current project.
@@ -34,16 +35,18 @@ public class TriggerViewRefreshStep implements ComputationStep {
   private final AnalysisMetadataHolder analysisMetadata;
 
   /**
-   * Constructor used by Pico when no implementation of {@link TriggerViewRefreshDelegate} is available
+   * Constructor used by the ioc container when no implementation of {@link TriggerViewRefreshDelegate} is available
    */
+  @Autowired(required = false)
   public TriggerViewRefreshStep(AnalysisMetadataHolder analysisMetadata) {
     this.analysisMetadata = analysisMetadata;
     this.triggerViewRefreshDelegates = new TriggerViewRefreshDelegate[0];
   }
 
   /**
-   * Constructor used by Pico when an implementation of {@link TriggerViewRefreshDelegate} is available
+   * Constructor used by the ioc container when an implementation of {@link TriggerViewRefreshDelegate} is available
    */
+  @Autowired(required = false)
   public TriggerViewRefreshStep(AnalysisMetadataHolder analysisMetadata, TriggerViewRefreshDelegate[] triggerViewRefreshDelegates) {
     this.analysisMetadata = analysisMetadata;
     this.triggerViewRefreshDelegates = triggerViewRefreshDelegates;
index be26b4774f47a37b47fae5f9d21d60bc6a3cc707..7f9163911ca60ec00aa20ee3146a84a0fe9fedb0 100644 (file)
@@ -31,18 +31,18 @@ import org.sonar.ce.task.projectanalysis.step.AbstractComputationSteps;
 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 org.sonar.core.platform.SpringComponentContainer;
 
 import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE;
 
 public class AuditPurgeTaskProcessor implements CeTaskProcessor {
   private static final Set<String> HANDLED_TYPES = Set.of(AUDIT_PURGE);
 
-  private final ComponentContainer ceEngineContainer;
+  private final SpringComponentContainer ceEngineContainer;
 
-  public AuditPurgeTaskProcessor(ComponentContainer ceEngineContainer) {
+  public AuditPurgeTaskProcessor(SpringComponentContainer ceEngineContainer) {
     this.ceEngineContainer = ceEngineContainer;
   }
 
index 29879730aa93ee0fe83ce52e3c88eaeb6bcffdc9..edef16213428e4fc73b08049bea5769106d270ed 100644 (file)
@@ -32,18 +32,18 @@ import org.sonar.ce.task.projectanalysis.step.AbstractComputationSteps;
 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 org.sonar.core.platform.SpringComponentContainer;
 
 import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC;
 
 public class IssueSyncTaskProcessor implements CeTaskProcessor {
   private static final Set<String> HANDLED_TYPES = ImmutableSet.of(BRANCH_ISSUE_SYNC);
 
-  private final ComponentContainer ceEngineContainer;
+  private final SpringComponentContainer ceEngineContainer;
 
-  public IssueSyncTaskProcessor(ComponentContainer ceEngineContainer) {
+  public IssueSyncTaskProcessor(SpringComponentContainer ceEngineContainer) {
     this.ceEngineContainer = ceEngineContainer;
   }
 
index 16fac974efda132109ca32e9031b959c2842eea3..b0939163ce57b28b0147ae8dd1c752a4e06b210d 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.ce.task.projectanalysis.taskprocessor;
 import java.util.Collections;
 import java.util.Set;
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 import org.sonar.ce.task.CeTask;
 import org.sonar.ce.task.CeTaskResult;
 import org.sonar.ce.task.container.TaskContainer;
@@ -29,43 +30,36 @@ import org.sonar.ce.task.projectanalysis.container.ContainerFactory;
 import org.sonar.ce.task.step.ComputationStepExecutor;
 import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
 import org.sonar.ce.task.taskprocessor.TaskResultHolder;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.ce.task.projectanalysis.container.ReportAnalysisComponentProvider;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class ReportTaskProcessor implements CeTaskProcessor {
 
   private static final Set<String> HANDLED_TYPES = Collections.singleton(CeTaskTypes.REPORT);
 
   private final ContainerFactory containerFactory;
-  private final ComponentContainer serverContainer;
+  private final SpringComponentContainer serverContainer;
   @CheckForNull
   private final ReportAnalysisComponentProvider[] componentProviders;
 
-  /**
-   * Used when at least one Privileged plugin is installed
-   */
-  public ReportTaskProcessor(ContainerFactory containerFactory, ComponentContainer serverContainer, ReportAnalysisComponentProvider[] componentProviders) {
+  @Autowired(required = false)
+  public ReportTaskProcessor(ContainerFactory containerFactory, SpringComponentContainer serverContainer, @Nullable ReportAnalysisComponentProvider[] componentProviders) {
     this.containerFactory = containerFactory;
     this.serverContainer = serverContainer;
     this.componentProviders = componentProviders;
   }
 
-  /**
-   * Used when no privileged plugin is installed
-   */
-  public ReportTaskProcessor(ContainerFactory containerFactory, ComponentContainer serverContainer) {
-    this.containerFactory = containerFactory;
-    this.serverContainer = serverContainer;
-    this.componentProviders = null;
-  }
-
   /**
    * Used when loaded in WebServer where none of the dependencies are available and where only
    * {@link #getHandledCeTaskTypes()} will be called.
    */
+  @Autowired(required = false)
   public ReportTaskProcessor() {
-    this(null, null, null);
+    this.containerFactory = null;
+    this.serverContainer = null;
+    this.componentProviders = null;
   }
 
   @Override
index 26e9084cc4eb9a0b8c2ebbe88eb85ddc7acec6ce..30f57010550d86388097af02e2fda594d65a8eb4 100644 (file)
@@ -54,8 +54,8 @@ public class ProjectExportContainerPopulator implements ContainerPopulator<TaskC
 
     container.add(projectDescriptor);
     container.add(steps);
-    container.addSingletons(COMPONENT_CLASSES);
-    container.addSingletons(steps.orderedStepClasses());
+    container.add(COMPONENT_CLASSES);
+    container.add(steps.orderedStepClasses());
   }
 
 }
index 68c03bebf1e79185621c8e420b9e3c04a1f53a68..24cbdd9bf4cab1908b2afbff4c8714df5264904b 100644 (file)
@@ -27,15 +27,15 @@ import org.sonar.ce.task.container.TaskContainerImpl;
 import org.sonar.ce.task.projectexport.ProjectExportContainerPopulator;
 import org.sonar.ce.task.projectexport.ProjectExportProcessor;
 import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
 import static org.sonar.db.ce.CeTaskTypes.PROJECT_EXPORT;
 
 public class ProjectExportTaskProcessor implements CeTaskProcessor {
 
-  private final ComponentContainer componentContainer;
+  private final SpringComponentContainer componentContainer;
 
-  public ProjectExportTaskProcessor(ComponentContainer componentContainer) {
+  public ProjectExportTaskProcessor(SpringComponentContainer componentContainer) {
     this.componentContainer = componentContainer;
   }
 
index 6be47c094115f15a52e21c7856930e30f012645b..bd44654516bad9c812a82692d92cac214e87f09c 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.ce.task.projectexport.util;
 
 import java.io.File;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.server.ServerSide;
index 434312438c736f5440064ba1bbebf98eaa1fe2fe..fc23a0602b4f6617658fd49b1c5a06ae553d75a0 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.ce.task.projectexport.util;
 
 import java.io.File;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.server.ServerSide;
index f134ff9a8281f20d5b311955dc7ead15dfe9f309..b3c6aff2ef54351b3a18bc9319b28ee910b5048b 100644 (file)
@@ -116,7 +116,7 @@ public class PostProjectAnalysisTasksExecutorTest {
   @Test
   @UseDataProvider("booleanValues")
   public void does_not_fail_when_there_is_no_PostProjectAnalysisTasksExecutor(boolean allStepsExecuted) {
-    new PostProjectAnalysisTasksExecutor(ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader)
+    new PostProjectAnalysisTasksExecutor(ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader, null)
       .finished(allStepsExecuted);
   }
 
index 0777349a1528dffb9291e7c6df450184af0426f9..911f1415d191e91f97221a14bb7a8f7ed172414c 100644 (file)
@@ -21,21 +21,15 @@ package org.sonar.ce.task.projectanalysis.container;
 
 import com.google.common.collect.ImmutableList;
 import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.junit.Test;
-import org.picocontainer.DefaultPicoContainer;
-import org.picocontainer.PicoContainer;
 import org.reflections.Reflections;
 import org.sonar.ce.task.CeTask;
-import org.sonar.ce.task.container.TaskContainer;
 import org.sonar.ce.task.projectanalysis.step.PersistComponentsStep;
+import org.sonar.ce.task.projectanalysis.task.ListTaskContainer;
 import org.sonar.ce.task.step.ComputationStep;
-import org.sonar.core.platform.ComponentContainer;
 import org.sonar.core.util.stream.MoreCollectors;
 
 import static com.google.common.collect.Sets.difference;
@@ -46,25 +40,23 @@ import static org.mockito.Mockito.when;
 public class ProjectAnalysisTaskContainerPopulatorTest {
   private static final String PROJECTANALYSIS_STEP_PACKAGE = "org.sonar.ce.task.projectanalysis.step";
 
-  private CeTask task = mock(CeTask.class);
-  private ProjectAnalysisTaskContainerPopulator underTest;
+  private final CeTask task = mock(CeTask.class);
+  private final ProjectAnalysisTaskContainerPopulator underTest = new ProjectAnalysisTaskContainerPopulator(task, null);
 
   @Test
   public void item_is_added_to_the_container() {
-    underTest = new ProjectAnalysisTaskContainerPopulator(task, null);
-    AddedObjectsRecorderTaskContainer container = new AddedObjectsRecorderTaskContainer();
+    ListTaskContainer container = new ListTaskContainer();
     underTest.populateContainer(container);
 
-    assertThat(container.added).contains(task);
+    assertThat(container.getAddedComponents()).contains(task);
   }
 
   @Test
   public void all_computation_steps_are_added_in_order_to_the_container() {
-    underTest = new ProjectAnalysisTaskContainerPopulator(task, null);
-    AddedObjectsRecorderTaskContainer container = new AddedObjectsRecorderTaskContainer();
+    ListTaskContainer container = new ListTaskContainer();
     underTest.populateContainer(container);
 
-    Set<String> computationStepClassNames = container.added.stream()
+    Set<String> computationStepClassNames = container.getAddedComponents().stream()
       .map(s -> {
         if (s instanceof Class) {
           return (Class<?>) s;
@@ -94,11 +86,10 @@ public class ProjectAnalysisTaskContainerPopulatorTest {
 
   @Test
   public void at_least_one_core_step_is_added_to_the_container() {
-    underTest = new ProjectAnalysisTaskContainerPopulator(task, null);
-    AddedObjectsRecorderTaskContainer container = new AddedObjectsRecorderTaskContainer();
+    ListTaskContainer container = new ListTaskContainer();
     underTest.populateContainer(container);
 
-    assertThat(container.added).contains(PersistComponentsStep.class);
+    assertThat(container.getAddedComponents()).contains(PersistComponentsStep.class);
   }
 
   @Test
@@ -108,74 +99,16 @@ public class ProjectAnalysisTaskContainerPopulatorTest {
     ReportAnalysisComponentProvider componentProvider = mock(ReportAnalysisComponentProvider.class);
     when(componentProvider.getComponents()).thenReturn(ImmutableList.of(object, clazz));
 
-    underTest = new ProjectAnalysisTaskContainerPopulator(task, new ReportAnalysisComponentProvider[] {componentProvider});
-    AddedObjectsRecorderTaskContainer container = new AddedObjectsRecorderTaskContainer();
+    ProjectAnalysisTaskContainerPopulator populator = new ProjectAnalysisTaskContainerPopulator(task, new ReportAnalysisComponentProvider[] {componentProvider});
+    ListTaskContainer container = new ListTaskContainer();
     container.add(componentProvider);
-    underTest.populateContainer(container);
+    populator.populateContainer(container);
 
-    assertThat(container.added).contains(object, clazz);
+    assertThat(container.getAddedComponents()).contains(object, clazz);
   }
 
   private static final class MyClass {
 
   }
 
-  private static class AddedObjectsRecorderTaskContainer implements TaskContainer {
-    private static final DefaultPicoContainer SOME_EMPTY_PICO_CONTAINER = new DefaultPicoContainer();
-
-    private List<Object> added = new ArrayList<>();
-
-    @Override
-    public void bootup() {
-      // no effect
-    }
-
-    @Override
-    public ComponentContainer getParent() {
-      throw new UnsupportedOperationException("getParent is not implemented");
-    }
-
-    @Override
-    public void close() {
-      throw new UnsupportedOperationException("cleanup is not implemented");
-    }
-
-    @Override
-    public PicoContainer getPicoContainer() {
-      return SOME_EMPTY_PICO_CONTAINER;
-    }
-
-    @Override
-    public ComponentContainer add(Object... objects) {
-      added.addAll(Arrays.asList(objects));
-      return null; // not used anyway
-    }
-
-    @Override
-    public ComponentContainer addSingletons(Iterable<?> components) {
-      for (Object component : components) {
-        added.add(component);
-      }
-      return null; // not used anyway
-    }
-
-    @Override
-    public <T> T getComponentByType(Class<T> type) {
-      for (Object add : added) {
-        if (add.getClass().getSimpleName().contains(type.getSimpleName())) {
-          return (T) add;
-        }
-      }
-      return null;
-    }
-
-    @Override
-    public <T> List<T> getComponentsByType(final Class<T> type) {
-      return added.stream()
-        .filter(input -> input.getClass().getSimpleName().contains(type.getSimpleName()))
-        .map(input -> (T) input)
-        .collect(Collectors.toList());
-    }
-  }
-
 }
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filesystem/ComputationTempFolderProviderTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filesystem/ComputationTempFolderProviderTest.java
new file mode 100644 (file)
index 0000000..896f456
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.ce.task.projectanalysis.filesystem;
+
+import org.apache.commons.io.FileUtils;
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import org.sonar.api.utils.TempFolder;
+import org.sonar.server.platform.ServerFileSystem;
+
+import java.io.File;
+
+public class ComputationTempFolderProviderTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  private final ComputationTempFolderProvider underTest = new ComputationTempFolderProvider();
+
+  @Test
+  public void existing_temp_dir() throws Exception {
+    ServerFileSystem fs = mock(ServerFileSystem.class);
+    File tmpDir = temp.newFolder();
+    when(fs.getTempDir()).thenReturn(tmpDir);
+
+    TempFolder folder = underTest.provide(fs);
+    assertThat(folder).isNotNull();
+    File newDir = folder.newDir();
+    assertThat(newDir).exists().isDirectory();
+    assertThat(newDir.getParentFile().getCanonicalPath()).startsWith(tmpDir.getCanonicalPath());
+  }
+
+  @Test
+  public void create_temp_dir_if_missing() throws Exception {
+    ServerFileSystem fs = mock(ServerFileSystem.class);
+    File tmpDir = temp.newFolder();
+    when(fs.getTempDir()).thenReturn(tmpDir);
+    FileUtils.forceDelete(tmpDir);
+
+    TempFolder folder = underTest.provide(fs);
+    assertThat(folder).isNotNull();
+    File newDir = folder.newDir();
+    assertThat(newDir).exists().isDirectory();
+    assertThat(newDir.getParentFile().getCanonicalPath()).startsWith(tmpDir.getCanonicalPath());
+  }
+}
index bb0a6f6b17721831a21399f6af50f5a938d6b315..247885957a5c4e8f05cb77202e8eec043a1d751f 100644 (file)
  */
 package org.sonar.ce.task.projectanalysis.step;
 
-import com.google.common.collect.Lists;
 import org.junit.Test;
 import org.sonar.ce.task.container.TaskContainerImpl;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.ce.task.step.ComputationStep;
+import org.sonar.core.platform.SpringComponentContainer;
 
+import static com.google.common.collect.Lists.newArrayList;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.mock;
 
@@ -31,33 +32,30 @@ public class ReportComputationStepsTest {
 
   @Test
   public void instances_throws_ISE_if_container_does_not_have_any_step() {
-    assertThatThrownBy(() -> {
-      TaskContainerImpl computeEngineContainer = new TaskContainerImpl(new ComponentContainer(), container -> {
-        // do nothing
-      });
-
-      Lists.newArrayList(new ReportComputationSteps(computeEngineContainer).instances());
-    })
+    TaskContainerImpl computeEngineContainer = new TaskContainerImpl(new SpringComponentContainer(), container -> {
+      // do nothing
+    });
+    Iterable<ComputationStep> instances = new ReportComputationSteps(computeEngineContainer).instances();
+    assertThatThrownBy(() -> newArrayList(instances))
       .isInstanceOf(IllegalStateException.class)
-      .hasMessage("Component not found: " + ExtractReportStep.class);
+      .hasMessageContaining(ExtractReportStep.class.getName());
   }
 
   @Test
   public void instances_throws_ISE_if_container_does_not_have_second_step() {
-    assertThatThrownBy(() -> {
-      final ExtractReportStep reportExtractionStep = mock(ExtractReportStep.class);
-      ComponentContainer componentContainer = new ComponentContainer() {
-        {
-          addSingleton(reportExtractionStep);
-        }
-      };
-      TaskContainerImpl computeEngineContainer = new TaskContainerImpl(componentContainer, container -> {
-        // do nothing
-      });
-
-      Lists.newArrayList(new ReportComputationSteps(computeEngineContainer).instances());
-    })
+    ExtractReportStep reportExtractionStep = mock(ExtractReportStep.class);
+    SpringComponentContainer componentContainer = new SpringComponentContainer() {
+      {
+        add(reportExtractionStep);
+      }
+    }.startComponents();
+    TaskContainerImpl computeEngineContainer = new TaskContainerImpl(componentContainer, container -> {
+      // do nothing
+    });
+    computeEngineContainer.startComponents();
+    Iterable<ComputationStep> instances = new ReportComputationSteps(computeEngineContainer).instances();
+    assertThatThrownBy(() -> newArrayList(instances))
       .isInstanceOf(IllegalStateException.class)
-      .hasMessage("Component not found: class org.sonar.ce.task.projectanalysis.step.PersistScannerContextStep");
+      .hasMessageContaining("org.sonar.ce.task.projectanalysis.step.PersistScannerContextStep");
   }
 }
index e01374588d53da94657adb3418bf5477d60ec0fa..2f5300b77d1121f32dbf8e1c9173f11b2dbb99d5 100644 (file)
@@ -62,7 +62,7 @@ public class ViewsCoverageMeasuresStepTest {
   @Rule
   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
 
-  CoverageMeasuresStep underTest = new CoverageMeasuresStep(treeRootHolder, metricRepository, measureRepository);
+  CoverageMeasuresStep underTest = new CoverageMeasuresStep(treeRootHolder, metricRepository, measureRepository, null);
 
   @Before
   public void setUp() {
index 9be01d4a36337c6009b89b0802450b983b4eaade..4c52736de16c1c82c3fcd2bdda6569001df084e8 100644 (file)
 package org.sonar.ce.task.projectanalysis.taskprocessor;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class AuditPurgeTaskModuleTest {
-
   @Test
   public void verifyCountOfAddedComponents() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new AuditPurgeTaskModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 1);
+    assertThat(container.getAddedObjects()).hasSize(1);
   }
-
 }
index 53e0165c2f6e6c8b5938a70a895a7d52b5621cb5..3ed573ec31719ef90a99f58297e18c9e3b0197dd 100644 (file)
@@ -26,18 +26,18 @@ import org.mockito.Mockito;
 import org.sonar.ce.task.CeTask;
 import org.sonar.ce.task.container.TaskContainer;
 import org.sonar.ce.task.step.ComputationStep;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
 import static org.sonar.ce.task.projectanalysis.taskprocessor.AuditPurgeTaskProcessor.AuditPurgeComputationSteps;
 import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 public class AuditPurgeTaskProcessorTest {
 
-  private ComponentContainer ceEngineContainer = Mockito.mock(ComponentContainer.class);
-
-  private AuditPurgeTaskProcessor underTest = new AuditPurgeTaskProcessor(ceEngineContainer);
-  private TaskContainer container = Mockito.spy(TaskContainer.class);
+  private final SpringComponentContainer ceEngineContainer = mock(SpringComponentContainer.class);
+  private final AuditPurgeTaskProcessor underTest = new AuditPurgeTaskProcessor(ceEngineContainer);
+  private final TaskContainer container = Mockito.spy(TaskContainer.class);
 
   @Test
   public void getHandledCeTaskTypes() {
index df577f2df5e42130677acb0e12557dbc3a1d22ba..9f2929f8eb31bd66309b0f6575751bc5e810da91 100644 (file)
@@ -26,18 +26,18 @@ import org.mockito.Mockito;
 import org.sonar.ce.task.CeTask;
 import org.sonar.ce.task.container.TaskContainer;
 import org.sonar.ce.task.step.ComputationStep;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
 import static org.sonar.ce.task.projectanalysis.taskprocessor.IssueSyncTaskProcessor.SyncComputationSteps;
 import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC;
 
 public class IssueSyncTaskProcessorTest {
 
-  private ComponentContainer ceEngineContainer = Mockito.mock(ComponentContainer.class);
-
-  private IssueSyncTaskProcessor underTest = new IssueSyncTaskProcessor(ceEngineContainer);
-  private TaskContainer container = Mockito.spy(TaskContainer.class);
+  private final SpringComponentContainer ceEngineContainer = mock(SpringComponentContainer.class);
+  private final IssueSyncTaskProcessor underTest = new IssueSyncTaskProcessor(ceEngineContainer);
+  private final TaskContainer container = Mockito.spy(TaskContainer.class);
 
   @Test
   public void getHandledCeTaskTypes() {
index 3dcc9c5a2d3f8914fe3948661afddda1ea5c6805..9e63aaaa01a53a9f64bf1ac704c8b19633a5e71d 100644 (file)
@@ -24,18 +24,19 @@ import org.junit.Test;
 import org.sonar.ce.task.container.TaskContainer;
 import org.sonar.ce.task.container.TaskContainerImpl;
 import org.sonar.ce.task.projectanalysis.step.ComplexityMeasuresStep;
-import org.sonar.ce.task.projectexport.steps.LoadProjectStep;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.ce.task.step.ComputationStep;
+import org.sonar.core.platform.SpringComponentContainer;
 
 import static com.google.common.collect.ImmutableList.copyOf;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class ProjectExportComputationStepsTest {
-
-  private TaskContainer container = mock(TaskContainer.class);
-  private ProjectExportComputationSteps underTest = new ProjectExportComputationSteps(container);
+  private final TaskContainer container = mock(TaskContainer.class);
+  private final ProjectExportComputationSteps underTest = new ProjectExportComputationSteps(container);
 
   @Test
   public void count_step_classes() {
@@ -44,29 +45,30 @@ public class ProjectExportComputationStepsTest {
 
   @Test
   public void instances_throws_ISE_if_steps_do_not_exist_in_container() {
-    assertThatThrownBy(() -> copyOf(underTest.instances()))
+    when(container.getComponentByType(any())).thenThrow(new IllegalStateException("Error"));
+    Iterable<ComputationStep> instances = underTest.instances();
+    assertThatThrownBy(() -> copyOf(instances))
       .isInstanceOf(IllegalStateException.class)
-      .hasMessage("Component not found: " + LoadProjectStep.class);
+      .hasMessage("Error");
   }
 
   @Test
   public void instances_throws_ISE_if_container_does_not_have_second_step() {
-    assertThatThrownBy(() -> {
-      final ComplexityMeasuresStep reportExtractionStep = mock(ComplexityMeasuresStep.class);
-
-      ComponentContainer componentContainer = new ComponentContainer() {
-        {
-          addSingleton(reportExtractionStep);
-        }
-      };
-      TaskContainerImpl computeEngineContainer = new TaskContainerImpl(componentContainer, container -> {
-        // do nothing
-      });
+    ComplexityMeasuresStep reportExtractionStep = mock(ComplexityMeasuresStep.class);
 
-      Lists.newArrayList(new ProjectExportComputationSteps(computeEngineContainer).instances());
-    })
+    SpringComponentContainer componentContainer = new SpringComponentContainer() {
+      {
+        add(reportExtractionStep);
+      }
+    }.startComponents();
+    TaskContainerImpl computeEngineContainer = new TaskContainerImpl(componentContainer, container -> {
+      // do nothing
+    });
+    computeEngineContainer.startComponents();
+    Iterable<ComputationStep> instances = new ProjectExportComputationSteps(computeEngineContainer).instances();
+    assertThatThrownBy(() -> Lists.newArrayList(instances))
       .isInstanceOf(IllegalStateException.class)
-      .hasMessage("Component not found: class org.sonar.ce.task.projectexport.steps.LoadProjectStep");
+      .hasMessageContaining("class org.sonar.ce.task.projectexport.steps.LoadProjectStep");
 
   }
 }
index 999f78f1220d40050a367dbccc7ff29570b56c06..d6760965d93ad9eb65e7e94acdab6133276f20d1 100644 (file)
  */
 package org.sonar.ce.task.projectexport;
 
-import com.google.common.base.Predicate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
 import org.junit.Test;
-import org.picocontainer.PicoContainer;
-import org.sonar.ce.task.container.TaskContainer;
+import org.sonar.ce.task.projectanalysis.task.ListTaskContainer;
 import org.sonar.ce.task.projectexport.taskprocessor.ProjectDescriptor;
 import org.sonar.ce.task.setting.SettingsLoader;
-import org.sonar.ce.task.step.ComputationStep;
-import org.sonar.core.platform.ComponentContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class ProjectExportContainerPopulatorTest {
-
-  private static final int COMPONENTS_BY_DEFAULT_IN_CONTAINER = 2;
-
   private final ProjectDescriptor descriptor = new ProjectDescriptor("project_uuid", "project_key", "Project Name");
   private final ProjectExportContainerPopulator underTest = new ProjectExportContainerPopulator(descriptor);
 
   @Test
   public void test_populateContainer() {
-    RecorderTaskContainer container = new RecorderTaskContainer();
+    ListTaskContainer container = new ListTaskContainer();
     underTest.populateContainer(container);
-    assertThat(container.addedComponents)
-      .hasSize(COMPONENTS_BY_DEFAULT_IN_CONTAINER + 8)
+    assertThat(container.getAddedComponents())
+      .hasSize(29)
       .contains(descriptor, SettingsLoader.class);
   }
-
-  private static class RecorderTaskContainer implements TaskContainer {
-    private final List<Object> addedComponents = new ArrayList<>();
-
-    @Override
-    public ComponentContainer add(Object... objects) {
-      addedComponents.addAll(Arrays.asList(objects));
-      // not used anyway
-      return null;
-    }
-
-    @Override
-    public ComponentContainer addSingletons(Iterable<?> components) {
-      List<Object> filteredComponents = StreamSupport.stream(components.spliterator(), false)
-        .filter((Predicate<Object>) input -> !(input instanceof Class) || !ComputationStep.class.isAssignableFrom((Class<?>) input))
-        .collect(Collectors.toList());
-
-      addedComponents.addAll(filteredComponents);
-      // not used anyway
-      return null;
-    }
-
-    @Override
-    public ComponentContainer getParent() {
-      throw new UnsupportedOperationException("getParent is not implemented");
-    }
-
-    @Override
-    public void bootup() {
-      throw new UnsupportedOperationException("bootup is not implemented");
-    }
-
-    @Override
-    public void close() {
-      throw new UnsupportedOperationException("close is not implemented");
-    }
-
-    @Override
-    public PicoContainer getPicoContainer() {
-      throw new UnsupportedOperationException("getParent is not implemented");
-    }
-
-    @Override
-    public <T> T getComponentByType(Class<T> type) {
-      throw new UnsupportedOperationException("getParent is not implemented");
-    }
-
-    @Override
-    public <T> List<T> getComponentsByType(final Class<T> type) {
-      throw new UnsupportedOperationException("getParent is not implemented");
-    }
-  }
 }
diff --git a/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/task/ListTaskContainer.java b/server/sonar-ce-task-projectanalysis/src/testFixtures/java/org/sonar/ce/task/projectanalysis/task/ListTaskContainer.java
new file mode 100644 (file)
index 0000000..c22b9ae
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.ce.task.projectanalysis.task;
+
+import com.google.common.collect.Iterables;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.sonar.ce.task.container.TaskContainer;
+import org.sonar.core.platform.Module;
+import org.sonar.core.platform.SpringComponentContainer;
+
+public class ListTaskContainer implements TaskContainer {
+  private final List<Object> addedComponents = new ArrayList<>();
+
+  @Override
+  public SpringComponentContainer add(Object... objects) {
+    for (Object o : objects) {
+      if (o instanceof Module) {
+        ((Module) o).configure(this);
+      } else if (o instanceof Iterable) {
+        add(Iterables.toArray((Iterable<?>) o, Object.class));
+      } else {
+        this.addedComponents.add(o);
+      }
+    }
+    // not used anyway
+    return null;
+  }
+
+  public List<Object> getAddedComponents() {
+    return addedComponents;
+  }
+
+  @Override
+  public SpringComponentContainer getParent() {
+    throw new UnsupportedOperationException("getParent is not implemented");
+  }
+
+  @Override
+  public void bootup() {
+    throw new UnsupportedOperationException("bootup is not implemented");
+  }
+
+  @Override
+  public void close() {
+    throw new UnsupportedOperationException("close is not implemented");
+  }
+
+  @Override
+  public <T> T getComponentByType(Class<T> type) {
+    throw new UnsupportedOperationException("getParent is not implemented");
+  }
+
+  @Override public <T> Optional<T> getOptionalComponentByType(Class<T> type) {
+    throw new UnsupportedOperationException("getParent is not implemented");
+  }
+
+  @Override
+  public <T> List<T> getComponentsByType(final Class<T> type) {
+    throw new UnsupportedOperationException("getParent is not implemented");
+  }
+}
index 6a18c0ce3294a49c74c95b1bbd321aa84aa6f17c..d7d426b8b51564cedff1e2b2d7b900c62b1aced3 100644 (file)
@@ -18,7 +18,6 @@ dependencies {
   // please keep the list grouped by configuration and ordered by name
 
   compile 'com.google.guava:guava'
-  compile 'org.picocontainer:picocontainer'
   compile 'org.slf4j:jul-to-slf4j'
   compile 'org.slf4j:slf4j-api'
 
diff --git a/server/sonar-ce-task/src/main/java/org/sonar/ce/task/container/LazyUnlessEagerAnnotationStrategy.java b/server/sonar-ce-task/src/main/java/org/sonar/ce/task/container/LazyUnlessEagerAnnotationStrategy.java
new file mode 100644 (file)
index 0000000..b5b4388
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.ce.task.container;
+
+import javax.annotation.Nullable;
+import org.sonar.core.platform.SpringInitStrategy;
+import org.springframework.beans.factory.config.BeanDefinition;
+
+public class LazyUnlessEagerAnnotationStrategy extends SpringInitStrategy {
+  @Override
+  protected boolean isLazyInit(BeanDefinition beanDefinition, @Nullable Class<?> clazz) {
+    return clazz == null || clazz.getAnnotation(EagerStart.class) == null;
+  }
+}
index 2a3979f1c7f8f74d39dedff6be93ad588c5053d1..c38d70e5002a71e03d2c86e2d2ccc8ee5e2845ae 100644 (file)
  */
 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.Container;
+import org.sonar.core.platform.ExtensionContainer;
 
 /**
- * The Compute Engine task container. Created for a specific parent {@link ComponentContainer} and a specific {@link CeTask}.
+ * The Compute Engine task container. Created for a specific parent {@link ExtensionContainer} and a specific {@link CeTask}.
  */
 public interface TaskContainer extends Container, AutoCloseable {
 
-  ComponentContainer getParent();
+  ExtensionContainer getParent();
 
   /**
    * Starts task container, starting any startable component in it.
@@ -41,10 +40,4 @@ public interface TaskContainer extends Container, AutoCloseable {
    */
   @Override
   void close();
-
-  /**
-   * Access to the underlying pico container.
-   */
-  PicoContainer getPicoContainer();
-
 }
index c8d67ab2a73cb183a2e198240fbd7ec7394ad4f9..6c514a93911ec2db79fc146ad88269c2f4829e54 100644 (file)
  */
 package org.sonar.ce.task.container;
 
-import java.util.List;
-import org.picocontainer.ComponentAdapter;
-import org.picocontainer.DefaultPicoContainer;
-import org.picocontainer.LifecycleStrategy;
-import org.picocontainer.MutablePicoContainer;
-import org.picocontainer.behaviors.OptInCaching;
-import org.picocontainer.monitors.NullComponentMonitor;
-import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.platform.ComponentContainer;
 import org.sonar.core.platform.ContainerPopulator;
-import org.sonar.core.platform.Module;
-import org.sonar.core.platform.StartableCloseableSafeLifecyleStrategy;
+import org.sonar.core.platform.SpringComponentContainer;
 
 import static java.util.Objects.requireNonNull;
 
-public class TaskContainerImpl extends ComponentContainer implements TaskContainer {
-
-  public TaskContainerImpl(ComponentContainer parent, ContainerPopulator<TaskContainer> populator) {
-    super(createContainer(requireNonNull(parent)), parent.getComponentByType(PropertyDefinitions.class));
+public class TaskContainerImpl extends SpringComponentContainer implements TaskContainer {
 
+  public TaskContainerImpl(SpringComponentContainer parent, ContainerPopulator<TaskContainer> populator) {
+    super(parent, new LazyUnlessEagerAnnotationStrategy());
     populateContainer(requireNonNull(populator));
   }
 
   private void populateContainer(ContainerPopulator<TaskContainer> populator) {
     populator.populateContainer(this);
-    populateFromModules();
-  }
-
-  private void populateFromModules() {
-    List<Module> modules = getComponentsByType(Module.class);
-    for (Module module : modules) {
-      module.configure(this);
-    }
-  }
-
-  /**
-   * Creates a PicContainer which extends the specified ComponentContainer <strong>but is not referenced in return</strong>
-   * and lazily starts its components.
-   */
-  private static MutablePicoContainer createContainer(ComponentContainer parent) {
-    LifecycleStrategy lifecycleStrategy = new StartableCloseableSafeLifecyleStrategy() {
-      @Override
-      public boolean isLazy(ComponentAdapter<?> adapter) {
-        return adapter.getComponentImplementation().getAnnotation(EagerStart.class) == null;
-      }
-    };
-
-    return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, parent.getPicoContainer(), new NullComponentMonitor());
   }
 
   @Override
index d5fc039e991b6c5628c620e48a3bcaacf463c7c4..cae9ed665da38db39893f2d0ac4dd1ac87bbfd03 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.ce.task.setting;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.config.internal.Settings;
 import org.sonar.ce.task.container.EagerStart;
index b2ecc7d421aea4ca2a4d2badf805c482d2c85421..b00f8b1432d9c043f33fa117398220bb3d74ab3d 100644 (file)
@@ -25,6 +25,7 @@ import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.ce.task.CeTaskInterrupter;
 import org.sonar.core.util.logs.Profiler;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.lang.String.format;
@@ -38,14 +39,12 @@ public final class ComputationStepExecutor {
   @CheckForNull
   private final Listener listener;
 
-  /**
-   * Used when no {@link ComputationStepExecutor.Listener} is available in pico
-   * container.
-   */
+  @Autowired(required = false)
   public ComputationStepExecutor(ComputationSteps steps, CeTaskInterrupter taskInterrupter) {
     this(steps, taskInterrupter, null);
   }
 
+  @Autowired(required = false)
   public ComputationStepExecutor(ComputationSteps steps, CeTaskInterrupter taskInterrupter, @Nullable Listener listener) {
     this.steps = steps;
     this.taskInterrupter = taskInterrupter;
index 04294b1dff9b0520cf3b0816842519a7f0dc7e13..08f609e9cdf2630dde73d3dee31eedbbcf87c3f7 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.ce.task.step;
 
 import org.sonar.api.ce.ComputeEngineSide;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Execute {@link StatelessInitExtension} instances in no specific order.
@@ -31,6 +32,7 @@ public class ExecuteStatelessInitExtensionsStep implements ComputationStep {
 
   private final StatelessInitExtension[] extensions;
 
+  @Autowired(required = false)
   public ExecuteStatelessInitExtensionsStep(StatelessInitExtension[] extensions) {
     this.extensions = extensions;
   }
@@ -38,6 +40,7 @@ public class ExecuteStatelessInitExtensionsStep implements ComputationStep {
   /**
    * Used when zero {@link StatelessInitExtension} are registered into container.
    */
+  @Autowired(required = false)
   public ExecuteStatelessInitExtensionsStep() {
     this(new StatelessInitExtension[0]);
   }
index b39be56616b05f080013ce4ab95a27ce9af5a05a..c2df2f4923cfb78da365fa711703a87af6326ab0 100644 (file)
  */
 package org.sonar.ce.task.container;
 
+import org.junit.Before;
 import org.junit.Test;
-import org.picocontainer.Startable;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.api.Startable;
 import org.sonar.core.platform.ContainerPopulator;
+import org.sonar.core.platform.SpringComponentContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -30,8 +31,13 @@ import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 public class TaskContainerImplTest {
-  private ComponentContainer parent = new ComponentContainer();
-  private ContainerPopulator<TaskContainer> populator = spy(new DummyContainerPopulator());
+  private final SpringComponentContainer parent = new SpringComponentContainer();
+  private final ContainerPopulator<TaskContainer> populator = spy(new DummyContainerPopulator());
+
+  @Before
+  public void before() {
+    parent.startComponents();
+  }
 
   @Test
   public void constructor_fails_fast_on_null_container() {
@@ -41,7 +47,8 @@ public class TaskContainerImplTest {
 
   @Test
   public void constructor_fails_fast_on_null_item() {
-    assertThatThrownBy(() -> new TaskContainerImpl(new ComponentContainer(), null))
+    SpringComponentContainer c = new SpringComponentContainer();
+    assertThatThrownBy(() -> new TaskContainerImpl(c, null))
       .isInstanceOf(NullPointerException.class);
   }
 
@@ -52,18 +59,10 @@ public class TaskContainerImplTest {
     verify(populator).populateContainer(ceContainer);
   }
 
-  @Test
-  public void ce_container_is_not_child_of_specified_container() {
-    TaskContainerImpl ceContainer = new TaskContainerImpl(parent, populator);
-
-    assertThat(parent.getChildren()).isEmpty();
-    verify(populator).populateContainer(ceContainer);
-  }
-
   @Test
   public void bootup_starts_components_lazily_unless_they_are_annotated_with_EagerStart() {
-    final DefaultStartable defaultStartable = new DefaultStartable();
-    final EagerStartable eagerStartable = new EagerStartable();
+    DefaultStartable defaultStartable = new DefaultStartable();
+    EagerStartable eagerStartable = new EagerStartable();
     TaskContainerImpl ceContainer = new TaskContainerImpl(parent, container -> {
       container.add(defaultStartable);
       container.add(eagerStartable);
index 1cb412e850d60c26b1dcd79b54a5ed12ce6ef808..a495260bd6fbb33558ec7b3de0f8a79647dd74dc 100644 (file)
@@ -15,7 +15,6 @@ dependencies {
   compile 'commons-io:commons-io'
   compile 'org.apache.commons:commons-dbcp2'
   compile 'org.nanohttpd:nanohttpd'
-  compile 'org.picocontainer:picocontainer'
   compile project(':server:sonar-ce-common')
   compile project(':server:sonar-ce-task')
   compile project(':server:sonar-ce-task-projectanalysis')
@@ -36,7 +35,7 @@ dependencies {
   testCompile 'org.awaitility:awaitility'
   testCompile 'org.mockito:mockito-core'
   testCompile 'org.slf4j:slf4j-api'
-  
+
   testCompile testFixtures(project(':server:sonar-db-dao'))
 
 }
index cd7aa8c5ba5696264e455e51f3824ee2a7b2f1c1..d05bf940db4fd5c39bbe5e0cd2e861fb2fab370b 100644 (file)
@@ -24,7 +24,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.locks.Lock;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.ce.taskprocessor.CeWorker;
index 90409c1abe511783d5bdcba732e52b65f4a118f2..7f9e14f4ec4470d0f3537f1d30975262a24b7906 100644 (file)
@@ -23,6 +23,7 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.MessageException;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static java.lang.String.format;
 import static org.sonar.process.ProcessProperties.Property.CE_GRACEFUL_STOP_TIMEOUT;
@@ -47,10 +48,12 @@ public class CeConfigurationImpl implements CeConfiguration {
   private final long gracefulStopTimeoutInMs;
   private int workerCount;
 
+  @Autowired(required = false)
   public CeConfigurationImpl(Configuration configuration) {
     this(configuration, null);
   }
 
+  @Autowired(required = false)
   public CeConfigurationImpl(Configuration configuration, @Nullable WorkerCountProvider workerCountProvider) {
     this.workerCountProvider = workerCountProvider;
     this.gracefulStopTimeoutInMs = configuration.getLong(CE_GRACEFUL_STOP_TIMEOUT.getKey())
index 04314bd16228c06800d430dce42016e420e119b5..600af1d5a3075e436e68cfd5b1ed976acfd35b61 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.ce.configuration;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
index bd8fe3ccfba6242ce6200637a1a0cdf0ceb77167..5e2a0f50a9536141ccda5b537decea6a585f61fe 100644 (file)
@@ -28,7 +28,7 @@ import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 import org.apache.commons.io.FileUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.Plugin;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.platform.ExplodedPlugin;
index 0db125b2406708f66114711d59e0e5f47e0b1e92..ed0329121e575a04818d349b9ff01efa1dba1d5c 100644 (file)
@@ -31,7 +31,6 @@ import org.sonar.api.internal.MetadataLoader;
 import org.sonar.api.internal.SonarRuntimeImpl;
 import org.sonar.api.profiles.XMLProfileParser;
 import org.sonar.api.profiles.XMLProfileSerializer;
-import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.ResourceTypes;
 import org.sonar.api.rules.AnnotationRuleParser;
 import org.sonar.api.server.profile.BuiltInQualityProfileAnnotationLoader;
@@ -71,19 +70,19 @@ import org.sonar.core.component.DefaultResourceTypes;
 import org.sonar.core.config.CorePropertyDefinitions;
 import org.sonar.core.extension.CoreExtensionRepositoryImpl;
 import org.sonar.core.extension.CoreExtensionsLoader;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.language.LanguagesProvider;
+import org.sonar.core.platform.Container;
 import org.sonar.core.platform.EditionProvider;
-import org.sonar.core.platform.Module;
 import org.sonar.core.platform.PlatformEditionProvider;
 import org.sonar.core.platform.PluginClassLoader;
 import org.sonar.core.platform.PluginClassloaderFactory;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.core.util.UuidFactoryImpl;
 import org.sonar.db.DBSessionsImpl;
 import org.sonar.db.DaoModule;
 import org.sonar.db.DbClient;
 import org.sonar.db.DefaultDatabase;
 import org.sonar.db.MyBatis;
-import org.sonar.db.audit.AuditPersister;
 import org.sonar.db.audit.NoOpAuditPersister;
 import org.sonar.db.purge.PurgeProfiler;
 import org.sonar.process.NetworkUtilsImpl;
@@ -161,11 +160,11 @@ import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED;
 
 public class ComputeEngineContainerImpl implements ComputeEngineContainer {
 
-  private ComputeEngineStatus computeEngineStatus;
+  private ComputeEngineStatus computeEngineStatus = null;
   @CheckForNull
-  private ComponentContainer level1;
+  private SpringComponentContainer level1 = null;
   @CheckForNull
-  private ComponentContainer level4;
+  private SpringComponentContainer level4 = null;
 
   @Override
   public void setComputeEngineStatus(ComputeEngineStatus computeEngineStatus) {
@@ -174,24 +173,20 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
 
   @Override
   public ComputeEngineContainer start(Props props) {
-    this.level1 = new ComponentContainer();
+    this.level1 = new SpringComponentContainer();
     populateLevel1(this.level1, props, requireNonNull(computeEngineStatus));
-    configureFromModules(this.level1);
     startLevel1(this.level1);
 
-    ComponentContainer level2 = this.level1.createChild();
+    SpringComponentContainer level2 = this.level1.createChild();
     populateLevel2(level2);
-    configureFromModules(level2);
     startLevel2(level2);
 
-    ComponentContainer level3 = level2.createChild();
+    SpringComponentContainer level3 = level2.createChild();
     populateLevel3(level3);
-    configureFromModules(level3);
     startLevel3(level3);
 
     this.level4 = level3.createChild();
     populateLevel4(this.level4, props);
-    configureFromModules(this.level4);
     startLevel4(this.level4);
 
     startupTasks();
@@ -199,36 +194,32 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
     return this;
   }
 
-  private static void startLevel1(ComponentContainer level1) {
+  private static void startLevel1(SpringComponentContainer level1) {
+    level1.startComponents();
     level1.getComponentByType(CoreExtensionsLoader.class)
       .load();
     level1.getComponentByType(CECoreExtensionsInstaller.class)
       .install(level1, hasPlatformLevel(1), noAdditionalSideFilter());
-
-    if (level1.getComponentByType(AuditPersister.class) == null) {
-      level1.add(NoOpAuditPersister.class);
-    }
-    level1.startComponents();
   }
 
-  private static void startLevel2(ComponentContainer level2) {
-    level2.getComponentByType(CECoreExtensionsInstaller.class)
+  private static void startLevel2(SpringComponentContainer level2) {
+    level2.getParent().getComponentByType(CECoreExtensionsInstaller.class)
       .install(level2, hasPlatformLevel(2), noAdditionalSideFilter());
 
     level2.startComponents();
   }
 
-  private static void startLevel3(ComponentContainer level3) {
-    level3.getComponentByType(CECoreExtensionsInstaller.class)
+  private static void startLevel3(SpringComponentContainer level3) {
+    level3.getParent().getComponentByType(CECoreExtensionsInstaller.class)
       .install(level3, hasPlatformLevel(3), noAdditionalSideFilter());
 
     level3.startComponents();
   }
 
-  private static void startLevel4(ComponentContainer level4) {
-    level4.getComponentByType(CECoreExtensionsInstaller.class)
+  private static void startLevel4(SpringComponentContainer level4) {
+    level4.getParent().getComponentByType(CECoreExtensionsInstaller.class)
       .install(level4, hasPlatformLevel4OrNone(), noAdditionalSideFilter());
-    level4.getComponentByType(ServerExtensionInstaller.class)
+    level4.getParent().getComponentByType(ServerExtensionInstaller.class)
       .installExtensions(level4);
 
     level4.startComponents();
@@ -239,7 +230,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
   }
 
   private void startupTasks() {
-    ComponentContainer startupLevel = this.level4.createChild();
+    SpringComponentContainer startupLevel = this.level4.createChild();
     startupLevel.add(startupComponents());
     startupLevel.startComponents();
     // done in PlatformLevelStartup
@@ -272,11 +263,11 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
   }
 
   @VisibleForTesting
-  protected ComponentContainer getComponentContainer() {
+  protected SpringComponentContainer getComponentContainer() {
     return level4;
   }
 
-  private static void populateLevel1(ComponentContainer container, Props props, ComputeEngineStatus computeEngineStatus) {
+  private static void populateLevel1(Container container, Props props, ComputeEngineStatus computeEngineStatus) {
     Version apiVersion = MetadataLoader.loadVersion(System2.INSTANCE);
     SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE);
     container.add(
@@ -300,19 +291,20 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
       Clock.systemDefaultZone(),
 
       // DB
-      DaoModule.class,
+      new DaoModule(),
       ReadOnlyPropertiesDao.class,
       DBSessionsImpl.class,
       DbClient.class,
 
       // Elasticsearch
-      EsModule.class,
+      new EsModule(),
 
       // rules/qprofiles
       RuleIndex.class,
 
       new OkHttpClientProvider(),
       computeEngineStatus,
+      NoOpAuditPersister.class,
 
       CoreExtensionRepositoryImpl.class,
       CoreExtensionsLoader.class,
@@ -320,9 +312,9 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
     container.add(toArray(CorePropertyDefinitions.all()));
   }
 
-  private static void populateLevel2(ComponentContainer container) {
+  private static void populateLevel2(Container container) {
     container.add(
-      MigrationConfigurationModule.class,
+      new MigrationConfigurationModule(),
       DatabaseVersion.class,
       DatabaseCompatibility.class,
 
@@ -347,7 +339,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
     );
   }
 
-  private static void populateLevel3(ComponentContainer container) {
+  private static void populateLevel3(Container container) {
     container.add(
       new StartupMetadataProvider(),
       JdbcUrlSanitizer.class,
@@ -357,7 +349,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
       SynchronousAsyncExecution.class);
   }
 
-  private static void populateLevel4(ComponentContainer container, Props props) {
+  private static void populateLevel4(Container container, Props props) {
     container.add(
       ResourceTypes.class,
       DefaultResourceTypes.get(),
@@ -377,7 +369,8 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
       RuleIndexer.class,
 
       // languages
-      Languages.class, // used by CommonRuleDefinitionsImpl
+      // used by CommonRuleDefinitionsImpl
+      LanguagesProvider.class,
 
       // measure
       MetricFinder.class,
@@ -412,7 +405,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
       NewIssuesNotificationHandler.newMetadata(),
       MyNewIssuesNotificationHandler.class,
       MyNewIssuesNotificationHandler.newMetadata(),
-      IssuesChangesNotificationModule.class,
+      new IssuesChangesNotificationModule(),
 
       // Notifications
       QGChangeEmailTemplate.class,
@@ -420,7 +413,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
       NotificationService.class,
       DefaultNotificationManager.class,
       EmailNotificationChannel.class,
-      ReportAnalysisFailureNotificationModule.class,
+      new ReportAnalysisFailureNotificationModule(),
 
       // System
       ServerLogging.class,
@@ -433,21 +426,21 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
       CoreExtensionStopper.class,
 
       // Compute engine (must be after Views and Developer Cockpit)
-      CeConfigurationModule.class,
-      CeQueueModule.class,
-      CeHttpModule.class,
-      CeTaskCommonsModule.class,
-      ProjectAnalysisTaskModule.class,
-      IssueSyncTaskModule.class,
-      AuditPurgeTaskModule.class,
-      CeTaskProcessorModule.class,
+      new CeConfigurationModule(),
+      new CeQueueModule(),
+      new CeHttpModule(),
+      new CeTaskCommonsModule(),
+      new ProjectAnalysisTaskModule(),
+      new IssueSyncTaskModule(),
+      new AuditPurgeTaskModule(),
+      new CeTaskProcessorModule(),
       OfficialDistribution.class,
 
       InternalPropertiesImpl.class,
       ProjectConfigurationFactory.class,
 
       // webhooks
-      WebhookModule.class,
+      new WebhookModule(),
 
       QualityGateFinder.class,
       QualityGateEvaluatorImpl.class
@@ -462,7 +455,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
         CEQueueStatusImpl.class);
     } else if (props.valueAsBoolean(CLUSTER_ENABLED.getKey())) {
       container.add(
-        CeCleaningModule.class,
+        new CeCleaningModule(),
 
         // system health
         CeDistributedInformationImpl.class,
@@ -474,7 +467,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
         DistributedCEQueueStatusImpl.class);
     } else {
       container.add(
-        CeCleaningModule.class,
+        new CeCleaningModule(),
         StandaloneCeDistributedInformation.class,
         CEQueueStatusImpl.class);
     }
@@ -490,11 +483,4 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
   private static Object[] toArray(List<?> list) {
     return list.toArray(new Object[list.size()]);
   }
-
-  private static void configureFromModules(ComponentContainer container) {
-    List<Module> modules = container.getComponentsByType(Module.class);
-    for (Module module : modules) {
-      module.configure(container);
-    }
-  }
 }
index c89d4d262928b7960ad8a46ad046892f49e49927..53289686c414be2aca8c23501661cc249c9f014a 100644 (file)
@@ -29,7 +29,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Properties;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.slf4j.LoggerFactory;
 import org.sonar.process.sharedmemoryfile.DefaultProcessCommands;
 
index 78c6076f348cab82d9e959d035c3f4363f632f33..06b26bd035cb9c5e12bae7f883df54d435c0394a 100644 (file)
@@ -27,7 +27,7 @@ import fi.iki.elonen.NanoHTTPD.Response;
  *
  * <p>
  * Method {@link #register(ActionRegistry)} of the action will be called right before the HTTP server is started (server
- * is started by the Pico Container). It's the action's responsibility to call the method
+ * is started by the ioc container). It's the action's responsibility to call the method
  * {@link ActionRegistry#register(ActionRegistry)} to register itself for a given path.
  * </p>
  * <p>
index 2fda18722c7adcef791b4020a9f506b286070fdb..c392abd1e050403889a567ca7ea841d609a7058f 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.ce.monitoring;
 
 import org.apache.commons.dbcp2.BasicDataSource;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.db.DbClient;
 import org.sonar.process.Jmx;
 import org.sonar.process.systeminfo.SystemInfoSection;
index 9927d4e5b5a0ec12e9f51913292d71b4d6bc9af3..ec7bc99fdbe32060ed152e278af9c688849f40e8 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.ce.monitoring;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.ce.configuration.CeConfiguration;
 import org.sonar.ce.taskprocessor.CeWorker;
 import org.sonar.ce.taskprocessor.CeWorkerController;
index 916df2843a63859899477b8b8569176569d8526e..be950ba895d77473b15767be52bd7a94e56eaed8 100644 (file)
@@ -21,14 +21,15 @@ package org.sonar.ce.platform;
 
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.ce.ComputeEngineSide;
+import org.sonar.api.config.Configuration;
 import org.sonar.core.platform.PluginRepository;
 import org.sonar.server.plugins.ServerExtensionInstaller;
 
 import static java.util.Collections.singleton;
 
 public class ComputeEngineExtensionInstaller extends ServerExtensionInstaller {
-  public ComputeEngineExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository) {
-    super(sonarRuntime, pluginRepository, singleton(ComputeEngineSide.class));
+  public ComputeEngineExtensionInstaller(Configuration configuration, SonarRuntime sonarRuntime, PluginRepository pluginRepository) {
+    super(configuration, sonarRuntime, pluginRepository, singleton(ComputeEngineSide.class));
   }
 
 }
index c7925a6970629d75faf4a4c2428230175194cd03..5ffaa8ae78333f8e7eb8666fe17c1f7d1d55cc39 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.ce.platform;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.server.platform.db.migration.version.DatabaseVersion;
 
 import static com.google.common.base.Preconditions.checkState;
index 072d1243c924a7cf2ef74b52303b966b9f1c1044..386516d5c6220f2132da9f6ca935b0f264de26fe 100644 (file)
  */
 package org.sonar.ce.taskprocessor;
 
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.System2;
 import org.sonar.ce.task.CeTaskInterrupter;
+import org.springframework.context.annotation.Bean;
 
 import static com.google.common.base.Preconditions.checkState;
 
-public class CeTaskInterrupterProvider extends ProviderAdapter {
+public class CeTaskInterrupterProvider {
   private static final String PROPERTY_CE_TASK_TIMEOUT = "sonar.ce.task.timeoutSeconds";
 
-  private CeTaskInterrupter instance;
-
+  @Bean("CeTaskInterrupter")
   public CeTaskInterrupter provide(Configuration configuration, CeWorkerController ceWorkerController, System2 system2) {
-    if (instance == null) {
-      instance = configuration.getLong(PROPERTY_CE_TASK_TIMEOUT)
-        .filter(timeOutInSeconds -> {
-          checkState(timeOutInSeconds >= 1, "The property '%s' must be a long value >= 1. Got '%s'", PROPERTY_CE_TASK_TIMEOUT, timeOutInSeconds);
-          return true;
-        })
-        .map(timeOutInSeconds -> (CeTaskInterrupter) new TimeoutCeTaskInterrupter(timeOutInSeconds * 1_000L, ceWorkerController, system2))
-        .orElseGet(SimpleCeTaskInterrupter::new);
-    }
-    return instance;
+    return configuration.getLong(PROPERTY_CE_TASK_TIMEOUT)
+      .filter(timeOutInSeconds -> {
+        checkState(timeOutInSeconds >= 1, "The property '%s' must be a long value >= 1. Got '%s'", PROPERTY_CE_TASK_TIMEOUT, timeOutInSeconds);
+        return true;
+      })
+      .map(timeOutInSeconds -> (CeTaskInterrupter) new TimeoutCeTaskInterrupter(timeOutInSeconds * 1_000L, ceWorkerController, system2))
+      .orElseGet(SimpleCeTaskInterrupter::new);
   }
 }
index ba52236abbaf50a37ba150491edffd6fdee5992d..8496a8c158d0bc8648562a6b7f3e11d35dfebbea 100644 (file)
@@ -36,7 +36,7 @@ import static java.lang.String.format;
 
 /**
  * {@link CeTaskProcessorRepository} implementation which provides access to the {@link CeTaskProcessor} existing in the
- * PicoContainer the current object belongs to.
+ * ioc container the current object belongs to.
  */
 public class CeTaskProcessorRepositoryImpl implements CeTaskProcessorRepository {
   private final Map<String, CeTaskProcessor> taskProcessorByCeTaskType;
index dc8005b8e35139498331434c527a1604f79bf842..3f0cf3720dd3fc80a06740de8ed540f5ab2edf23 100644 (file)
@@ -25,6 +25,7 @@ import java.util.stream.Stream;
 import org.sonar.ce.queue.InternalCeQueue;
 import org.sonar.core.util.UuidFactory;
 import org.sonar.core.util.stream.MoreCollectors;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class CeWorkerFactoryImpl implements CeWorkerFactory {
   private final UuidFactory uuidFactory;
@@ -35,15 +36,15 @@ public class CeWorkerFactoryImpl implements CeWorkerFactory {
   private Set<CeWorker> ceWorkers = Collections.emptySet();
 
   /**
-   * Used by Pico when there is no {@link CeWorker.ExecutionListener} in the container.
+   * Used by the ioc container when there is no {@link CeWorker.ExecutionListener} in the container.
    */
-  public CeWorkerFactoryImpl(InternalCeQueue queue, CeTaskProcessorRepository taskProcessorRepository,
-    UuidFactory uuidFactory, CeWorkerController ceWorkerController) {
+  @Autowired(required = false)
+  public CeWorkerFactoryImpl(InternalCeQueue queue, CeTaskProcessorRepository taskProcessorRepository, UuidFactory uuidFactory, CeWorkerController ceWorkerController) {
     this(queue, taskProcessorRepository, uuidFactory, ceWorkerController, new CeWorker.ExecutionListener[0]);
   }
 
-  public CeWorkerFactoryImpl(InternalCeQueue queue, CeTaskProcessorRepository taskProcessorRepository,
-    UuidFactory uuidFactory, CeWorkerController ceWorkerController,
+  @Autowired(required = false)
+  public CeWorkerFactoryImpl(InternalCeQueue queue, CeTaskProcessorRepository taskProcessorRepository, UuidFactory uuidFactory, CeWorkerController ceWorkerController,
     CeWorker.ExecutionListener[] executionListeners) {
     this.queue = queue;
     this.taskProcessorRepository = taskProcessorRepository;
index f23f1b17acbc34369e9945bacbddf861eb806c94..8274a6f07e97d81ea04497f016d6782771814c9c 100644 (file)
@@ -29,21 +29,21 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 public class ComputeEngineImplTest {
 
-  private ComputeEngineContainer computeEngineContainer = new NoOpComputeEngineContainer();
-  private ComputeEngine underTest = new ComputeEngineImpl(new Props(new Properties()), computeEngineContainer);
+  private final ComputeEngineContainer computeEngineContainer = new NoOpComputeEngineContainer();
+  private final ComputeEngine underTest = new ComputeEngineImpl(new Props(new Properties()), computeEngineContainer);
 
   @Test
   public void startup_throws_ISE_when_called_twice() {
     underTest.startup();
 
-    assertThatThrownBy(() -> underTest.startup())
+    assertThatThrownBy(underTest::startup)
       .isInstanceOf(IllegalStateException.class)
       .hasMessage("startup() can not be called multiple times");
   }
 
   @Test
   public void stopProcessing_throws_ISE_if_startup_was_not_called_before() {
-    assertThatThrownBy(() -> underTest.stopProcessing())
+    assertThatThrownBy(underTest::stopProcessing)
       .isInstanceOf(IllegalStateException.class)
       .hasMessage("stopProcessing() must not be called before startup()");
   }
@@ -53,7 +53,7 @@ public class ComputeEngineImplTest {
     underTest.startup();
     underTest.shutdown();
 
-    assertThatThrownBy(() -> underTest.stopProcessing())
+    assertThatThrownBy(underTest::stopProcessing)
       .isInstanceOf(IllegalStateException.class)
       .hasMessage("stopProcessing() can not be called after shutdown()");
   }
@@ -63,14 +63,14 @@ public class ComputeEngineImplTest {
     underTest.startup();
     underTest.stopProcessing();
 
-    assertThatThrownBy(() -> underTest.stopProcessing())
+    assertThatThrownBy(underTest::stopProcessing)
       .isInstanceOf(IllegalStateException.class)
       .hasMessage("stopProcessing() can not be called multiple times");
   }
 
   @Test
   public void shutdown_throws_ISE_if_startup_was_not_called_before() {
-    assertThatThrownBy(() -> underTest.shutdown())
+    assertThatThrownBy(underTest::shutdown)
       .isInstanceOf(IllegalStateException.class)
       .hasMessage("shutdown() must not be called before startup()");
   }
@@ -80,7 +80,7 @@ public class ComputeEngineImplTest {
     underTest.startup();
     underTest.shutdown();
 
-    assertThatThrownBy(() -> underTest.shutdown())
+    assertThatThrownBy(underTest::shutdown)
       .isInstanceOf(IllegalStateException.class)
       .hasMessage("shutdown() can not be called multiple times");
   }
index de401a23f5236c08aaa21bf0a4db1095226073fe..3e14671ea1b9a6e708ce623e0044da489ff32e57 100644 (file)
@@ -25,20 +25,15 @@ import java.io.IOException;
 import java.util.Date;
 import java.util.Locale;
 import java.util.Properties;
-import java.util.stream.Collectors;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang.StringUtils;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.picocontainer.ComponentAdapter;
-import org.picocontainer.MutablePicoContainer;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.System2;
-import org.sonar.ce.CeDistributedInformationImpl;
-import org.sonar.ce.StandaloneCeDistributedInformation;
 import org.sonar.core.extension.ServiceLoaderWrapper;
 import org.sonar.db.DbTester;
 import org.sonar.db.property.PropertyDto;
@@ -46,6 +41,7 @@ import org.sonar.process.ProcessId;
 import org.sonar.process.ProcessProperties;
 import org.sonar.process.Props;
 import org.sonar.server.property.InternalProperties;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
 import static java.lang.String.valueOf;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -68,14 +64,13 @@ public class ComputeEngineContainerImplTest {
 
   public DbTester db = DbTester.create(System2.INSTANCE);
 
-  private ComputeEngineContainerImpl underTest;
-  private ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
-  private ProcessProperties processProperties = new ProcessProperties(serviceLoaderWrapper);
+  private final ServiceLoaderWrapper serviceLoaderWrapper = mock(ServiceLoaderWrapper.class);
+  private final ProcessProperties processProperties = new ProcessProperties(serviceLoaderWrapper);
+  private final ComputeEngineContainerImpl underTest = new ComputeEngineContainerImpl();
 
   @Before
   public void setUp() {
     when(serviceLoaderWrapper.load()).thenReturn(ImmutableSet.of());
-    underTest = new ComputeEngineContainerImpl();
     underTest.setComputeEngineStatus(mock(ComputeEngineStatus.class));
   }
 
@@ -95,26 +90,18 @@ public class ComputeEngineContainerImplTest {
 
     underTest.start(new Props(properties));
 
-    MutablePicoContainer picoContainer = underTest.getComponentContainer().getPicoContainer();
+    AnnotationConfigApplicationContext context = underTest.getComponentContainer().context();
     try {
-      assertThat(picoContainer.getComponentAdapters()).hasSizeGreaterThan(1);
-      assertThat(picoContainer.getParent().getComponentAdapters()).hasSizeGreaterThan(1);
-      assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSizeGreaterThan(1);
-      assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSizeGreaterThan(1);
-      assertThat(
-        picoContainer.getComponentAdapters().stream()
-          .map(ComponentAdapter::getComponentImplementation)
-          .collect(Collectors.toList())).doesNotContain(
-            (Class) CeDistributedInformationImpl.class).contains(
-              StandaloneCeDistributedInformation.class);
-      assertThat(picoContainer.getParent().getParent().getParent().getParent()).isNull();
+      assertThat(context.getBeanDefinitionNames()).hasSizeGreaterThan(1);
+      assertThat(context.getParent().getBeanDefinitionNames()).hasSizeGreaterThan(1);
+      assertThat(context.getParent().getParent().getBeanDefinitionNames()).hasSizeGreaterThan(1);
+      assertThat(context.getParent().getParent().getParent().getBeanDefinitionNames()).hasSizeGreaterThan(1);
+      assertThat(context.getParent().getParent().getParent().getParent()).isNull();
     } finally {
       underTest.stop();
     }
 
-    assertThat(picoContainer.getLifecycleState().isStarted()).isFalse();
-    assertThat(picoContainer.getLifecycleState().isStopped()).isFalse();
-    assertThat(picoContainer.getLifecycleState().isDisposed()).isTrue();
+    assertThat(context.isActive()).isFalse();
   }
 
   private String cleanJdbcUrl() {
index b93f9dc7737fe9416b335ad2a37f6890d1fcd10c..35894dd9fdb11c23ebbbf06366cd763522d1b387 100644 (file)
@@ -24,20 +24,29 @@ import javax.annotation.CheckForNull;
 import javax.management.InstanceNotFoundException;
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
+import org.sonar.process.Jmx;
 import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.ce.monitoring.CeDatabaseMBean.OBJECT_NAME;
 
 public class CeDatabaseMBeanImplTest {
 
   @Rule
   public DbTester dbTester = DbTester.create(System2.INSTANCE);
 
-  private CeDatabaseMBeanImpl underTest = new CeDatabaseMBeanImpl(dbTester.getDbClient());
+  private final CeDatabaseMBeanImpl underTest = new CeDatabaseMBeanImpl(dbTester.getDbClient());
+
+  @BeforeClass
+  public static void beforeClass() {
+    // if any other class starts a container where CeDatabaseMBeanImpl is added, it will have been registered
+    Jmx.unregister(OBJECT_NAME);
+  }
 
   @Test
   public void register_and_unregister() throws Exception {
@@ -62,7 +71,7 @@ public class CeDatabaseMBeanImplTest {
   @CheckForNull
   private ObjectInstance getMBean() throws Exception {
     try {
-      return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(CeDatabaseMBean.OBJECT_NAME));
+      return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(OBJECT_NAME));
     } catch (InstanceNotFoundException e) {
       return null;
     }
index 8e072f09d60c0d5ee274e150202bdb9ad116673c..390f846546eb24a8b6bf17fe813333600cc26723 100644 (file)
@@ -33,17 +33,20 @@ import javax.management.InstanceNotFoundException;
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
 import org.apache.commons.lang.RandomStringUtils;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.sonar.ce.configuration.CeConfiguration;
 import org.sonar.ce.taskprocessor.CeWorker;
 import org.sonar.ce.taskprocessor.CeWorkerController;
 import org.sonar.ce.taskprocessor.CeWorkerFactory;
 import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.process.Jmx;
 import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.sonar.ce.monitoring.CeTasksMBean.OBJECT_NAME;
 
 public class CeTasksMBeanImplTest {
   private static final long PENDING_COUNT = 2;
@@ -63,8 +66,14 @@ public class CeTasksMBeanImplTest {
     })
     .collect(MoreCollectors.toSet());
 
-  private CeWorkerController ceWorkerController = mock(CeWorkerController.class);
-  private CeTasksMBeanImpl underTest = new CeTasksMBeanImpl(new DumbCEQueueStatus(), new DumbCeConfiguration(), new DumbCeWorkerFactory(), ceWorkerController);
+  private final CeWorkerController ceWorkerController = mock(CeWorkerController.class);
+  private final CeTasksMBeanImpl underTest = new CeTasksMBeanImpl(new DumbCEQueueStatus(), new DumbCeConfiguration(), new DumbCeWorkerFactory(), ceWorkerController);
+
+  @BeforeClass
+  public static void beforeClass() {
+    // if any other class starts a container where CeTasksMBeanImpl is added, it will have been registered
+    Jmx.unregister(OBJECT_NAME);
+  }
 
   @Test
   public void register_and_unregister() throws Exception {
@@ -84,7 +93,7 @@ public class CeTasksMBeanImplTest {
   @CheckForNull
   private ObjectInstance getMBean() throws Exception {
     try {
-      return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(CeTasksMBean.OBJECT_NAME));
+      return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(OBJECT_NAME));
     } catch (InstanceNotFoundException e) {
       return null;
     }
index 33e3616f6bd8ddeb5e3e37282671e2697f62c6fc..6e270946699edca6efd5655fcd623aa61599f9b9 100644 (file)
@@ -25,6 +25,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.stream.Stream;
+
 import org.junit.Test;
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.ScannerSide;
@@ -32,7 +33,7 @@ import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.extension.CoreExtension;
 import org.sonar.core.extension.CoreExtensionRepository;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -61,14 +62,13 @@ public class CECoreExtensionsInstallerTest {
             NoAnnotationClass.class, OtherAnnotationClass.class, MultipleAnnotationClass.class);
         }
       }));
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
-    assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
-    assertThat(container.getComponentByType(CeClass.class)).isNotNull();
-    assertThat(container.getComponentByType(MultipleAnnotationClass.class)).isNotNull();
+    assertThat(container.getAddedObjects())
+      .hasSize(2)
+      .contains(CeClass.class, MultipleAnnotationClass.class);
   }
 
   @ComputeEngineSide
index d1108df0260d81a7faa949a1b347884bfa48dae8..77c5b75f5c0c94aa054cc13767bd8928505701bf 100644 (file)
@@ -32,10 +32,10 @@ import static org.mockito.Mockito.mock;
 
 public class CeTaskInterrupterProviderTest {
 
-  private MapSettings settings = new MapSettings();
-  private CeWorkerController ceWorkerController = mock(CeWorkerController.class);
-  private System2 system2 = mock(System2.class);
-  private CeTaskInterrupterProvider underTest = new CeTaskInterrupterProvider();
+  private final MapSettings settings = new MapSettings();
+  private final CeWorkerController ceWorkerController = mock(CeWorkerController.class);
+  private final System2 system2 = mock(System2.class);
+  private final CeTaskInterrupterProvider underTest = new CeTaskInterrupterProvider();
 
   @Test
   public void provide_returns_a_SimpleCeTaskInterrupter_instance_if_configuration_is_empty() {
@@ -45,15 +45,6 @@ public class CeTaskInterrupterProviderTest {
       .isInstanceOf(SimpleCeTaskInterrupter.class);
   }
 
-  @Test
-  public void provide_always_return_the_same_SimpleCeTaskInterrupter_instance() {
-    CeTaskInterrupter instance = underTest.provide(settings.asConfig(), ceWorkerController, system2);
-
-    assertThat(instance)
-      .isSameAs(underTest.provide(settings.asConfig(), ceWorkerController, system2))
-      .isSameAs(underTest.provide(new MapSettings().asConfig(), ceWorkerController, system2));
-  }
-
   @Test
   public void provide_returns_a_TimeoutCeTaskInterrupter_instance_if_property_taskTimeout_has_a_value() throws IllegalAccessException, NoSuchFieldException {
     int timeout = 1 + new Random().nextInt(2222);
@@ -100,18 +91,6 @@ public class CeTaskInterrupterProviderTest {
       .hasMessage("The property 'sonar.ce.task.timeoutSeconds' must be a long value >= 1. Got '" + negativeValue + "'");
   }
 
-  @Test
-  public void provide_always_return_the_same_TimeoutCeTaskInterrupter_instance() {
-    int timeout = 1 + new Random().nextInt(2222);
-    settings.setProperty("sonar.ce.task.timeoutSeconds", timeout);
-
-    CeTaskInterrupter instance = underTest.provide(settings.asConfig(), ceWorkerController, system2);
-
-    assertThat(instance)
-      .isSameAs(underTest.provide(settings.asConfig(), ceWorkerController, system2))
-      .isSameAs(underTest.provide(new MapSettings().setProperty("sonar.ce.task.timeoutSeconds", 999).asConfig(), ceWorkerController, system2));
-  }
-
   private static Object readField(CeTaskInterrupter instance, String fieldName) throws NoSuchFieldException, IllegalAccessException {
     Class<?> clazz = instance.getClass();
     Field timeoutField = clazz.getDeclaredField(fieldName);
index 11d95dca8d0d1d6c8253346d238810f7bd6cdc1e..3921b60b92e65c62fb7bfbb16d196d19fcdb5d12 100644 (file)
 package org.sonar.ce.taskprocessor;
 
 import org.junit.Test;
-import org.picocontainer.ComponentAdapter;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import org.sonar.ce.notification.ReportAnalysisFailureNotificationExecutionListener;
-import org.sonar.ce.task.CeTaskInterrupter;
-import org.sonar.core.platform.ComponentContainer;
-
-import static org.assertj.core.api.Assertions.assertThat;
+import org.sonar.core.platform.ExtensionContainer;
 
 public class CeTaskProcessorModuleTest {
   private CeTaskProcessorModule underTest = new CeTaskProcessorModule();
 
   @Test
-  public void defines_CeWorker_ExecutionListener_for_CeLogging() {
-    ComponentContainer container = new ComponentContainer();
+  public void defines_module() {
+    var container = mock(ExtensionContainer.class);
 
     underTest.configure(container);
 
-    assertThat(container.getPicoContainer().getComponentAdapters(CeWorker.ExecutionListener.class)
-      .stream()
-      .map(ComponentAdapter::getComponentImplementation))
-        .contains(CeLoggingWorkerExecutionListener.class);
-  }
-
-  @Test
-  public void defines_ExecutionListener_for_report_processing_failure_notifications() {
-    ComponentContainer container = new ComponentContainer();
-
-    underTest.configure(container);
+    verify(container).add(CeTaskProcessorRepositoryImpl.class);
+    verify(container).add(CeLoggingWorkerExecutionListener.class);
+    verify(container).add(ReportAnalysisFailureNotificationExecutionListener.class);
+    verify(container).add(any(CeTaskInterrupterProvider.class));
+    verify(container).add(CeTaskInterrupterWorkerExecutionListener.class);
+    verify(container).add(CeWorkerFactoryImpl.class);
+    verify(container).add(CeWorkerControllerImpl.class);
+    verify(container).add(CeProcessingSchedulerExecutorServiceImpl.class);
+    verify(container).add(CeProcessingSchedulerImpl.class);
 
-    assertThat(container.getPicoContainer().getComponentAdapters(CeWorker.ExecutionListener.class)
-      .stream()
-      .map(ComponentAdapter::getComponentImplementation))
-        .contains(ReportAnalysisFailureNotificationExecutionListener.class);
-  }
-
-  @Test
-  public void defines_CeTaskInterrupterProvider_object() {
-    ComponentContainer container = new ComponentContainer();
-
-    underTest.configure(container);
-    assertThat(container.getPicoContainer().getComponentAdapter(CeTaskInterrupter.class))
-      .isInstanceOf(CeTaskInterrupterProvider.class);
   }
 }
index 2466304fb751dab15e8b6e70c00ae434efc161e4..3e1290bfd7c2fdce571bc36f2f3f714a9c1027f6 100644 (file)
@@ -14,7 +14,6 @@ dependencies {
   compile 'commons-lang:commons-lang'
   compile 'org.apache.commons:commons-dbcp2'
   compile 'org.mybatis:mybatis'
-  compile 'org.picocontainer:picocontainer'
   compile 'org.slf4j:slf4j-api'
   compile project(':server:sonar-process')
   compile project(path: ':sonar-plugin-api', configuration: 'shadow')
index 515e4b6fcf2a3b5760d204bb87a8d99155870ea3..d9071ece5413531632a0ef8e7e379fd91c6db657 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.db;
 
 import javax.sql.DataSource;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.db.dialect.Dialect;
 
 /**
index bf75d7a596583f53bf0aa4e78326800b63641c14..d128c08158fb429b94e55d1a56b07464b2de3c74 100644 (file)
@@ -157,16 +157,19 @@ import org.sonar.db.user.UserTokenDto;
 import org.sonar.db.user.UserTokenMapper;
 import org.sonar.db.webhook.WebhookDeliveryMapper;
 import org.sonar.db.webhook.WebhookMapper;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class MyBatis implements Startable {
   private final List<MyBatisConfExtension> confExtensions;
   private final Database database;
   private SqlSessionFactory sessionFactory;
 
+  @Autowired(required = false)
   public MyBatis(Database database) {
     this(database, null);
   }
 
+  @Autowired(required = false)
   public MyBatis(Database database, @Nullable MyBatisConfExtension[] confExtensions) {
     this.confExtensions = confExtensions == null ? Collections.emptyList() : Arrays.asList(confExtensions);
     this.database = database;
index eb1d6a091699dc95ebcb08474beec85ab4dd4124..2567bfbc8f0f79f8d0d2bb6b2c831807e1272b14 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.db.audit;
 
+import javax.annotation.Priority;
 import org.sonar.db.DbSession;
 import org.sonar.db.audit.model.ComponentKeyNewValue;
 import org.sonar.db.audit.model.ComponentNewValue;
@@ -38,6 +39,7 @@ import org.sonar.db.audit.model.UserPermissionNewValue;
 import org.sonar.db.audit.model.UserTokenNewValue;
 import org.sonar.db.audit.model.WebhookNewValue;
 
+@Priority(2)
 public class NoOpAuditPersister implements AuditPersister {
   @Override
   public void addUserGroup(DbSession dbSession, UserGroupNewValue newValue) {
index 235b832177a59ee3b13c33c6fa7babd548ae47d6..132e5b08c93b2fe5bd764ff10afc6868958524ec 100644 (file)
@@ -57,11 +57,7 @@ public class InternalPropertiesDao implements Dao {
   private static final Optional<String> OPTIONAL_OF_EMPTY_STRING = Optional.of("");
 
   private final System2 system2;
-  private AuditPersister auditPersister;
-
-  public InternalPropertiesDao(System2 system2) {
-    this.system2 = system2;
-  }
+  private final AuditPersister auditPersister;
 
   public InternalPropertiesDao(System2 system2, AuditPersister auditPersister) {
     this.system2 = system2;
@@ -89,7 +85,7 @@ public class InternalPropertiesDao implements Dao {
       mapper.insertAsText(key, value, now);
     }
 
-    if (auditPersister != null && auditPersister.isTrackedProperty(key)) {
+    if (auditPersister.isTrackedProperty(key)) {
       if (deletedRows > 0) {
         auditPersister.updateProperty(dbSession, new PropertyNewValue(key, value), false);
       } else {
@@ -112,7 +108,7 @@ public class InternalPropertiesDao implements Dao {
     int deletedRows = mapper.deleteByKey(key);
     mapper.insertAsEmpty(key, system2.now());
 
-    if (auditPersister != null && auditPersister.isTrackedProperty(key)) {
+    if (auditPersister.isTrackedProperty(key)) {
       if (deletedRows > 0) {
         auditPersister.updateProperty(dbSession, new PropertyNewValue(key, ""), false);
       } else {
@@ -124,7 +120,7 @@ public class InternalPropertiesDao implements Dao {
   public void delete(DbSession dbSession, String key) {
     int deletedRows = getMapper(dbSession).deleteByKey(key);
 
-    if (auditPersister != null && deletedRows > 0 && auditPersister.isTrackedProperty(key)) {
+    if (deletedRows > 0 && auditPersister.isTrackedProperty(key)) {
       auditPersister.deleteProperty(dbSession, new PropertyNewValue(key), false);
     }
   }
index b312959a5ce936990bd11089899c54c0b71a04d5..96f261556af0332073ded4febc5a4677685014e6 100644 (file)
 package org.sonar.db;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class DaoModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new DaoModule().configure(container);
-    assertThat(container.size()).isGreaterThan(1);
+    assertThat(container.getAddedObjects()).hasSizeGreaterThan(1);
   }
 }
index 63b11946b3151da72d22e3957b19bc54c70e9e5d..4414ef3309a2824859300fa81f013751c34866fa 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.db;
 
 import org.apache.ibatis.session.Configuration;
 import org.hamcrest.core.Is;
-import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -46,11 +45,6 @@ public class MyBatisTest {
 
   private MyBatis underTest = new MyBatis(database);
 
-  @After
-  public void tearDown() {
-    underTest.stop();
-  }
-
   @Test
   public void shouldConfigureMyBatis() {
     underTest.start();
index 9e3e83f17e8be4ae0dc28883c6ca5961c7a1a331..d8d9e8bb483f69b2d6a1e9b919366415f5855c82 100644 (file)
@@ -28,7 +28,6 @@ import java.util.Map;
 import java.util.stream.Stream;
 import javax.annotation.Nullable;
 import org.apache.commons.dbcp2.BasicDataSource;
-import org.picocontainer.containers.TransientPicoContainer;
 import org.sonar.api.utils.System2;
 import org.sonar.core.util.SequenceUuidFactory;
 import org.sonar.core.util.UuidFactory;
@@ -145,15 +144,16 @@ public class DbTester extends AbstractDbTester<TestDbImpl> {
   }
 
   private void initDbClient() {
-    TransientPicoContainer ioc = new TransientPicoContainer();
-    ioc.addComponent(auditPersister);
-    ioc.addComponent(db.getMyBatis());
-    ioc.addComponent(system2);
-    ioc.addComponent(uuidFactory);
-    for (Class daoClass : DaoModule.classes()) {
-      ioc.addComponent(daoClass);
+    FastSpringContainer ioc = new FastSpringContainer();
+    ioc.add(auditPersister);
+    ioc.add(db.getMyBatis());
+    ioc.add(system2);
+    ioc.add(uuidFactory);
+    for (Class<?> daoClass : DaoModule.classes()) {
+      ioc.add(daoClass);
     }
-    List<Dao> daos = ioc.getComponents(Dao.class);
+    ioc.start();
+    List<Dao> daos = ioc.getComponentsByType(Dao.class);
     client = new DbClient(db.getDatabase(), db.getMyBatis(), new TestDBSessions(db.getMyBatis()), daos.toArray(new Dao[daos.size()]));
   }
 
diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/FastSpringContainer.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/FastSpringContainer.java
new file mode 100644 (file)
index 0000000..47b5cde
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.db;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
+import org.sonar.core.platform.Container;
+import org.sonar.core.platform.StartableBeanPostProcessor;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
+import org.springframework.context.support.GenericApplicationContext;
+
+/**
+ * A fast(er) Spring container. It doesn't support several things that are supported in
+ * {@link org.sonar.core.platform.SpringComponentContainer}, such as:
+ * <ul>
+ *   <li>Adding extensions</li>
+ *   <li>Use of annotations</li>
+ *   <li>Adding duplicate components from different Classloaders</li>
+ *   <li>Hierarchy of container</li>
+ *   <li>Different initialization strategies</li>
+ * </ul>
+ */
+public class FastSpringContainer implements Container {
+  private final GenericApplicationContext context = new GenericApplicationContext();
+
+  public FastSpringContainer() {
+    ((AbstractAutowireCapableBeanFactory) context.getBeanFactory()).setParameterNameDiscoverer(null);
+    add(StartableBeanPostProcessor.class);
+  }
+
+  @Override
+  public Container add(Object... objects) {
+    for (Object o : objects) {
+      if (o instanceof Class) {
+        Class<?> clazz = (Class<?>) o;
+        context.registerBean(clazz.getName(), clazz);
+      } else {
+        registerInstance(o);
+      }
+    }
+    return this;
+  }
+
+  public void start() {
+    context.refresh();
+  }
+
+  private <T> void registerInstance(T instance) {
+    Supplier<T> supplier = () -> instance;
+    Class<T> clazz = (Class<T>) instance.getClass();
+    context.registerBean(clazz.getName(), clazz, supplier);
+  }
+
+  @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> Optional<T> getOptionalComponentByType(Class<T> type) {
+    try {
+      return Optional.of(context.getBean(type));
+    } catch (NoSuchBeanDefinitionException t) {
+      return Optional.empty();
+    }
+  }
+
+  @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);
+    }
+  }
+
+  @Override
+  public Container getParent() {
+    return null;
+  }
+}
index 169bf9763c2a258e64ad420b8f156f396c2a8256..dc515bfcd4f6c4c3eb9c51b1f564bbe62cd80f61 100644 (file)
@@ -35,7 +35,8 @@ import org.sonar.api.internal.SonarRuntimeImpl;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.Version;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.Container;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.core.util.UuidFactoryFast;
 import org.sonar.core.util.logs.Profiler;
 import org.sonar.db.dialect.Dialect;
@@ -43,15 +44,12 @@ import org.sonar.process.logging.LogbackHelper;
 import org.sonar.server.platform.db.migration.MigrationConfigurationModule;
 import org.sonar.server.platform.db.migration.engine.MigrationContainer;
 import org.sonar.server.platform.db.migration.engine.MigrationContainerImpl;
-import org.sonar.server.platform.db.migration.engine.MigrationContainerPopulator;
-import org.sonar.server.platform.db.migration.engine.MigrationContainerPopulatorImpl;
 import org.sonar.server.platform.db.migration.history.MigrationHistoryTableImpl;
 import org.sonar.server.platform.db.migration.step.MigrationStep;
 import org.sonar.server.platform.db.migration.step.MigrationStepExecutionException;
 import org.sonar.server.platform.db.migration.step.MigrationSteps;
 import org.sonar.server.platform.db.migration.step.MigrationStepsExecutor;
 import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
-import org.sonar.server.platform.db.migration.version.DbVersion;
 
 import static com.google.common.base.Preconditions.checkState;
 
@@ -101,29 +99,23 @@ public class SQDatabase extends DefaultDatabase {
     }
   }
 
-  public static final class H2MigrationContainerPopulator extends MigrationContainerPopulatorImpl {
-    public H2MigrationContainerPopulator(DbVersion... dbVersions) {
-      super(H2StepExecutor.class, dbVersions);
-    }
-  }
-
   public static final class H2StepExecutor implements MigrationStepsExecutor {
     private static final String STEP_START_PATTERN = "{}...";
     private static final String STEP_STOP_PATTERN = "{}: {}";
 
-    private final ComponentContainer componentContainer;
+    private final Container container;
 
-    public H2StepExecutor(ComponentContainer componentContainer) {
-      this.componentContainer = componentContainer;
+    public H2StepExecutor(Container container) {
+      this.container = container;
     }
 
     @Override
     public void execute(List<RegisteredMigrationStep> steps) {
-      steps.forEach(step -> execute(step, componentContainer));
+      steps.forEach(step -> execute(step, container));
     }
 
-    private void execute(RegisteredMigrationStep step, ComponentContainer componentContainer) {
-      MigrationStep migrationStep = componentContainer.getComponentByType(step.getStepClass());
+    private void execute(RegisteredMigrationStep step, Container container) {
+      MigrationStep migrationStep = container.getComponentByType(step.getStepClass());
       checkState(migrationStep != null, "Can not find instance of " + step.getStepClass());
 
       execute(step, migrationStep);
@@ -149,24 +141,23 @@ public class SQDatabase extends DefaultDatabase {
   }
 
   private void executeDbMigrations(NoopDatabase noopDatabase) {
-    ComponentContainer parentContainer = new ComponentContainer();
-    parentContainer.add(noopDatabase);
-    parentContainer.add(H2MigrationContainerPopulator.class);
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.add(noopDatabase);
     MigrationConfigurationModule migrationConfigurationModule = new MigrationConfigurationModule();
-    migrationConfigurationModule.configure(parentContainer);
+    migrationConfigurationModule.configure(container);
 
     // dependencies required by DB migrations
-    parentContainer.add(SonarRuntimeImpl.forSonarQube(Version.create(8, 0), SonarQubeSide.SERVER, SonarEdition.COMMUNITY));
-    parentContainer.add(UuidFactoryFast.getInstance());
-    parentContainer.add(System2.INSTANCE);
-    parentContainer.add(MapSettings.class);
+    container.add(SonarRuntimeImpl.forSonarQube(Version.create(8, 0), SonarQubeSide.SERVER, SonarEdition.COMMUNITY));
+    container.add(UuidFactoryFast.getInstance());
+    container.add(System2.INSTANCE);
+    container.add(MapSettings.class);
 
-    parentContainer.startComponents();
-
-    MigrationContainer migrationContainer = new MigrationContainerImpl(parentContainer, parentContainer.getComponentByType(MigrationContainerPopulator.class));
+    container.startComponents();
+    MigrationContainer migrationContainer = new MigrationContainerImpl(container, H2StepExecutor.class);
     MigrationSteps migrationSteps = migrationContainer.getComponentByType(MigrationSteps.class);
-    migrationContainer.getComponentByType(MigrationStepsExecutor.class)
-      .execute(migrationSteps.readAll());
+    MigrationStepsExecutor executor = migrationContainer.getComponentByType(MigrationStepsExecutor.class);
+
+    executor.execute(migrationSteps.readAll());
   }
 
   private void createMigrationHistoryTable(NoopDatabase noopDatabase) {
index 466b47e251b9c9fcf73c48dac228a0f622fa874a..1cb23f4fdceefda7293fe759fa048da66a4868be 100644 (file)
@@ -11,7 +11,6 @@ dependencies {
   compile 'commons-lang:commons-lang'
   compile 'commons-codec:commons-codec'
   compile 'com.fasterxml.staxmate:staxmate'
-  compile 'org.picocontainer:picocontainer'
 
   compile project(':server:sonar-db-core')
   compile project(':server:sonar-process')
index e24c7f9e6e252a9d136d3fb48c7839d658342efe..7598ec022bf101bf90d178950fe7141f43e9c71a 100644 (file)
@@ -26,10 +26,6 @@ public interface DatabaseMigration {
    * <p>
    * Migration can not be started twice but calling this method wont raise an error.
    * </p>
-   * <p>
-   * <strong>This method should be named {@code start} but it can not be because it will be called by the pico container
-   * and this will cause unwanted behavior</strong>
-   * </p>
    */
   void startIt();
 
index 6351152b24a194650baa5d2d421bc70d170115a5..a6e8762c030fb555c2e2ed515be94e61a2fed1cf 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.platform.db.migration;
 import org.sonar.core.platform.Module;
 import org.sonar.server.platform.db.migration.history.MigrationHistoryImpl;
 import org.sonar.server.platform.db.migration.history.MigrationHistoryMeddler;
+import org.sonar.server.platform.db.migration.history.MigrationHistoryTableImpl;
 import org.sonar.server.platform.db.migration.sql.DbPrimaryKeyConstraintFinder;
 import org.sonar.server.platform.db.migration.sql.DropPrimaryKeySqlGenerator;
 import org.sonar.server.platform.db.migration.step.MigrationStepRegistryImpl;
@@ -36,6 +37,7 @@ public class MigrationConfigurationModule extends Module {
   @Override
   protected void configureModule() {
     add(
+      MigrationHistoryTableImpl.class,
       // DbVersion implementations
       DbVersion00.class,
       DbVersion90.class,
index 47aaeadb3a097c1f1a7b64453220733e60bacb68..5632ee164aebf1f4605d511580cc7c5927561496 100644 (file)
@@ -20,8 +20,8 @@
 package org.sonar.server.platform.db.migration;
 
 import org.sonar.core.platform.Module;
-import org.sonar.server.platform.db.migration.engine.MigrationContainerPopulatorImpl;
 import org.sonar.server.platform.db.migration.engine.MigrationEngineImpl;
+import org.sonar.server.platform.db.migration.step.MigrationStepsExecutorImpl;
 
 /**
  * Defines the components for the migration engine.
@@ -30,7 +30,7 @@ public class MigrationEngineModule extends Module {
   @Override
   protected void configureModule() {
     add(
-      MigrationContainerPopulatorImpl.class,
+      MigrationStepsExecutorImpl.class,
       MigrationEngineImpl.class);
   }
 }
index 8e222273a43046e0d99e914314a8a176ed0c43a4..d046b1730d7814791d1d40cfc3f01d173aef0597 100644 (file)
@@ -23,6 +23,8 @@ import com.google.common.annotations.VisibleForTesting;
 import java.sql.Connection;
 import java.sql.SQLException;
 import javax.annotation.CheckForNull;
+import javax.inject.Inject;
+
 import org.sonar.db.Database;
 import org.sonar.db.dialect.Dialect;
 import org.sonar.db.dialect.H2;
@@ -46,6 +48,7 @@ public class DatabaseCharsetChecker {
   private final Database db;
   private final SqlExecutor sqlExecutor;
 
+  @Inject
   public DatabaseCharsetChecker(Database db) {
     this(db, new SqlExecutor());
   }
index 7785c369247ed081d25bb6dfb4b2bc0db66dbbfa..1977660bdbe768d828a788140009a3dee1823b53 100644 (file)
  */
 package org.sonar.server.platform.db.migration.engine;
 
-import org.picocontainer.ComponentAdapter;
-import org.picocontainer.DefaultPicoContainer;
-import org.picocontainer.LifecycleStrategy;
-import org.picocontainer.MutablePicoContainer;
-import org.picocontainer.behaviors.OptInCaching;
-import org.picocontainer.monitors.NullComponentMonitor;
+import java.util.HashSet;
+import java.util.Set;
 import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.core.platform.StartableCloseableSafeLifecyleStrategy;
+import org.sonar.core.platform.LazyStrategy;
+import org.sonar.core.platform.SpringComponentContainer;
+import org.sonar.server.platform.db.migration.step.MigrationStep;
+import org.sonar.server.platform.db.migration.step.MigrationSteps;
+import org.sonar.server.platform.db.migration.step.MigrationStepsExecutor;
 
-import static java.util.Objects.requireNonNull;
+import static java.util.Collections.emptyList;
 
-public class MigrationContainerImpl extends ComponentContainer implements MigrationContainer {
+public class MigrationContainerImpl extends SpringComponentContainer implements MigrationContainer {
 
-  public MigrationContainerImpl(ComponentContainer parent, MigrationContainerPopulator populator) {
-    super(createContainer(requireNonNull(parent)), parent.getComponentByType(PropertyDefinitions.class));
-
-    populateContainer(requireNonNull(populator));
+  public MigrationContainerImpl(SpringComponentContainer parent, Class<? extends MigrationStepsExecutor> executor) {
+    super(parent, parent.getComponentByType(PropertyDefinitions.class), emptyList(), new LazyStrategy());
+    add(executor);
+    addSteps(parent.getComponentByType(MigrationSteps.class));
     startComponents();
   }
 
-  private void populateContainer(MigrationContainerPopulator populator) {
-    populator.populateContainer(this);
-  }
-
-  /**
-   * Creates a PicContainer which extends the specified ComponentContainer <strong>but is not referenced in return</strong>.
-   */
-  private static MutablePicoContainer createContainer(ComponentContainer parent) {
-    LifecycleStrategy lifecycleStrategy = new StartableCloseableSafeLifecyleStrategy() {
-      @Override
-      public boolean isLazy(ComponentAdapter<?> adapter) {
-        return true;
+  private void addSteps(MigrationSteps migrationSteps) {
+    Set<Class<? extends MigrationStep>> classes = new HashSet<>();
+    migrationSteps.readAll().forEach(step -> {
+      Class<? extends MigrationStep> stepClass = step.getStepClass();
+      if (!classes.contains(stepClass)) {
+        add(stepClass);
+        classes.add(stepClass);
       }
-    };
-    return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, parent.getPicoContainer(), new NullComponentMonitor());
+    });
   }
 
   @Override
index 0b9469d1085f61cbc962f57cf1bd76ce6b415e33..22a92d3c05974940929ba5abb42fbf6a73d140d2 100644 (file)
@@ -32,37 +32,26 @@ import org.sonar.server.platform.db.migration.version.DbVersion;
  * Responsible for:
  * <ul>
  *   <li>adding all the {@link MigrationStep} classes to the container after building it</li>
- *   <li>adding dependencies for them to the container if there aren't already available in parent container
- *   (see {@link DbVersion#getSupportComponents()})</li>
  *   <li>adding the {@link MigrationStepsExecutorImpl} to the container</li>
  * </ul>
  */
 public class MigrationContainerPopulatorImpl implements MigrationContainerPopulator {
-  private final DbVersion[] dbVersions;
   private final Class<? extends MigrationStepsExecutor> executorType;
 
-  public MigrationContainerPopulatorImpl(DbVersion... dbVersions) {
-    this(MigrationStepsExecutorImpl.class, dbVersions);
+  public MigrationContainerPopulatorImpl() {
+    this(MigrationStepsExecutorImpl.class);
   }
 
-  protected MigrationContainerPopulatorImpl(Class<? extends MigrationStepsExecutor> executorType, DbVersion... dbVersions) {
-    this.dbVersions = dbVersions;
+  protected MigrationContainerPopulatorImpl(Class<? extends MigrationStepsExecutor> executorType) {
     this.executorType = executorType;
   }
 
   @Override
   public void populateContainer(MigrationContainer container) {
     container.add(executorType);
-    populateFromDbVersion(container);
     populateFromMigrationSteps(container);
   }
 
-  private void populateFromDbVersion(MigrationContainer container) {
-    Arrays.stream(dbVersions)
-      .flatMap(DbVersion::getSupportComponents)
-      .forEach(container::add);
-  }
-
   private static void populateFromMigrationSteps(MigrationContainer container) {
     MigrationSteps migrationSteps = container.getComponentByType(MigrationSteps.class);
     Set<Class<? extends MigrationStep>> classes = new HashSet<>();
index b4cb6d18e1deebe7821ba11b342b7d900d906cbd..0ceee8817f23be190ae46d82c533a1a4e0ad0238 100644 (file)
@@ -23,35 +23,33 @@ import java.util.List;
 import java.util.Optional;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.AnnotationUtils;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.process.ProcessProperties;
 import org.sonar.server.platform.db.migration.SupportsBlueGreen;
 import org.sonar.server.platform.db.migration.history.MigrationHistory;
 import org.sonar.server.platform.db.migration.step.MigrationSteps;
 import org.sonar.server.platform.db.migration.step.MigrationStepsExecutor;
+import org.sonar.server.platform.db.migration.step.MigrationStepsExecutorImpl;
 import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
 
 import static java.lang.String.format;
 
 public class MigrationEngineImpl implements MigrationEngine {
   private final MigrationHistory migrationHistory;
-  private final ComponentContainer serverContainer;
-  private final MigrationContainerPopulator populator;
+  private final SpringComponentContainer serverContainer;
   private final MigrationSteps migrationSteps;
   private final Configuration configuration;
 
-  public MigrationEngineImpl(MigrationHistory migrationHistory, ComponentContainer serverContainer,
-    MigrationContainerPopulator populator, MigrationSteps migrationSteps, Configuration configuration) {
+  public MigrationEngineImpl(MigrationHistory migrationHistory, SpringComponentContainer serverContainer, MigrationSteps migrationSteps, Configuration configuration) {
     this.migrationHistory = migrationHistory;
     this.serverContainer = serverContainer;
-    this.populator = populator;
     this.migrationSteps = migrationSteps;
     this.configuration = configuration;
   }
 
   @Override
   public void execute() {
-    MigrationContainer migrationContainer = new MigrationContainerImpl(serverContainer, populator);
+    MigrationContainer migrationContainer = new MigrationContainerImpl(serverContainer, MigrationStepsExecutorImpl.class);
     boolean blueGreen = configuration.getBoolean(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey()).orElse(false);
     try {
       MigrationStepsExecutor stepsExecutor = migrationContainer.getComponentByType(MigrationStepsExecutor.class);
index 8aca6291592827dfdbb6f10bd8565bed34fa9300..e8ab9e4bc25b7c0664e3536044872b4fb3bdb2ea 100644 (file)
@@ -22,8 +22,8 @@ package org.sonar.server.platform.db.migration.step;
 import java.util.List;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.platform.Container;
 import org.sonar.core.util.logs.Profiler;
-import org.sonar.server.platform.db.migration.engine.MigrationContainer;
 import org.sonar.server.platform.db.migration.history.MigrationHistory;
 
 import static com.google.common.base.Preconditions.checkState;
@@ -35,10 +35,10 @@ public class MigrationStepsExecutorImpl implements MigrationStepsExecutor {
   private static final String STEP_START_PATTERN = "{}...";
   private static final String STEP_STOP_PATTERN = "{}: {}";
 
-  private final MigrationContainer migrationContainer;
+  private final Container migrationContainer;
   private final MigrationHistory migrationHistory;
 
-  public MigrationStepsExecutorImpl(MigrationContainer migrationContainer, MigrationHistory migrationHistory) {
+  public MigrationStepsExecutorImpl(Container migrationContainer, MigrationHistory migrationHistory) {
     this.migrationContainer = migrationContainer;
     this.migrationHistory = migrationHistory;
   }
index ab10e8b1cb94410f436a27949057179f5c3c53e5..d5213656d282048973d0c1b56479cbc652a76287 100644 (file)
 package org.sonar.server.platform.db.migration.step;
 
 import java.util.Arrays;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.server.platform.db.migration.version.DbVersion;
+import org.springframework.context.annotation.Bean;
 
 /**
  * This class is responsible for providing the {@link MigrationSteps} to be injected in classes that need it and
  * ensures that there's only one such instance.
  */
-public class MigrationStepsProvider extends ProviderAdapter {
-  private MigrationSteps migrationSteps;
-
+public class MigrationStepsProvider {
+  @Bean("MigrationSteps")
   public MigrationSteps provide(InternalMigrationStepRegistry migrationStepRegistry, DbVersion... dbVersions) {
-    if (migrationSteps == null) {
-      migrationSteps = buildMigrationSteps(migrationStepRegistry, dbVersions);
-    }
-    return migrationSteps;
-  }
-
-  private static MigrationSteps buildMigrationSteps(InternalMigrationStepRegistry migrationStepRegistry, DbVersion[] dbVersions) {
     Arrays.stream(dbVersions).forEach(dbVersion -> dbVersion.addSteps(migrationStepRegistry));
     return migrationStepRegistry.build();
   }
index 2d831fc1b35f571d790d0269cf5a334290eaa0cc..e3be1104258c452ed50454441e49399fb4546afd 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version;
 
-import java.util.stream.Stream;
 import org.sonar.server.platform.db.migration.step.MigrationStepRegistry;
 
 public interface DbVersion {
-  /**
-   * Components (if any) supporting the {@link org.sonar.server.platform.db.migration.step.MigrationStep} classes
-   * added to the registry in {@link #addSteps(MigrationStepRegistry)}.
-   * <p>
-   * These components will be added to the {@link org.sonar.server.platform.db.migration.engine.MigrationContainer} in
-   * which the {@link org.sonar.server.platform.db.migration.step.MigrationStep} classes will be instantiated and run.
-   * </p>
-   */
-  default Stream<Object> getSupportComponents() {
-    return Stream.empty();
-  }
-
   void addSteps(MigrationStepRegistry registry);
 }
index 0e4814f45f2d493e77838b240facecda27153f6e..711fc3fc0a2d4bd792465da32e10216e79e36d81 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.platform.db.migration;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -29,11 +29,11 @@ public class MigrationConfigurationModuleTest {
 
   @Test
   public void verify_component_count() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    assertThat(container.getPicoContainer().getComponentAdapters()).isNotEmpty();
+    assertThat(container.getAddedObjects()).isNotEmpty();
   }
 
 }
index 274db07c793dc115c34efbfe1ea0c9d22975c4e7..d04ce11ed72cd685bff171560252b5fd56afee86 100644 (file)
 package org.sonar.server.platform.db.migration;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class MigrationEngineModuleTest {
   private MigrationEngineModule underTest = new MigrationEngineModule();
 
   @Test
   public void verify_component_count() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    assertThat(container.getPicoContainer().getComponentAdapters())
-        .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
+    assertThat(container.getAddedObjects()).hasSize(2);
   }
 }
index 1e3a9dd45099f540b7ba469c93a32d4f751083d2..f0534766f3ca1f67a5149e06ea3cee6e83894d90 100644 (file)
  */
 package org.sonar.server.platform.db.migration.engine;
 
+import java.sql.SQLException;
+import java.util.List;
+import org.junit.Before;
 import org.junit.Test;
-import org.picocontainer.Startable;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.api.Startable;
+import org.sonar.core.platform.SpringComponentContainer;
+import org.sonar.server.platform.db.migration.step.InternalMigrationStepRegistry;
+import org.sonar.server.platform.db.migration.step.MigrationStep;
+import org.sonar.server.platform.db.migration.step.MigrationStepRegistryImpl;
+import org.sonar.server.platform.db.migration.step.MigrationStepsExecutor;
+import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class MigrationContainerImplTest {
-  private ComponentContainer parent = new ComponentContainer();
-  private MigrationContainerPopulator populator = container -> container.add(StartCallCounter.class);
-
-  private MigrationContainerImpl underTest = new MigrationContainerImpl(parent, populator);
+  private final SpringComponentContainer parent = new SpringComponentContainer();
+  private MigrationContainerImpl underTest;
+
+  @Before
+  public void setUp() {
+    InternalMigrationStepRegistry registry = new MigrationStepRegistryImpl();
+    registry.add(1, "test", NoOpMigrationStep.class);
+
+    parent.add(registry.build());
+    parent.startComponents();
+    underTest = new MigrationContainerImpl(parent, NoOpExecutor.class);
+    underTest.add(StartCallCounter.class);
+  }
 
   @Test
-  public void pico_container_of_migration_container_has_pico_container_of_specified_container_as_parent() {
-    assertThat(underTest.getPicoContainer().getParent()).isEqualTo(parent.getPicoContainer());
+  public void adds_migration_steps_to_migration_container() {
+    assertThat(underTest.getComponentByType(MigrationStep.class)).isInstanceOf(NoOpMigrationStep.class);
   }
 
   @Test
-  public void pico_container_of_parent_does_not_have_pico_container_of_migration_container_as_child() {
-    assertThat(parent.getPicoContainer().removeChildContainer(underTest.getPicoContainer())).isFalse();
+  public void context_of_migration_container_has_specified_context_as_parent() {
+    assertThat(underTest.context().getParent()).isEqualTo(parent.context());
   }
 
   @Test
-  public void pico_container_of_migration_container_is_started_in_constructor() {
-    assertThat(underTest.getPicoContainer().getLifecycleState().isStarted()).isTrue();
+  public void context_of_migration_container_is_started_in_constructor() {
+    assertThat(underTest.context().isActive()).isTrue();
   }
 
   @Test
@@ -58,11 +75,26 @@ public class MigrationContainerImplTest {
 
   @Test
   public void cleanup_does_not_fail_even_if_stop_of_component_fails() {
-    MigrationContainerImpl underTest = new MigrationContainerImpl(parent, (container -> container.add(StopFailing.class)));
+    parent.add(StopFailing.class);
+    MigrationContainerImpl underTest = new MigrationContainerImpl(parent, NoOpExecutor.class);
 
     underTest.cleanup();
   }
 
+  private static class NoOpExecutor implements MigrationStepsExecutor {
+    @Override
+    public void execute(List<RegisteredMigrationStep> steps) {
+
+    }
+  }
+
+  private static class NoOpMigrationStep implements MigrationStep {
+    @Override
+    public void execute() throws SQLException {
+
+    }
+  }
+
   public static final class StartCallCounter implements Startable {
     private static int startCalls = 0;
 
index fb937d4c77f54b1c5f93553b5bf0c1969b5e0457..2ce177c874ed3e95461032cdc96589412f81e54f 100644 (file)
  */
 package org.sonar.server.platform.db.migration.engine;
 
-import java.util.stream.Stream;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.server.platform.db.migration.history.MigrationHistory;
 import org.sonar.server.platform.db.migration.step.MigrationStep;
-import org.sonar.server.platform.db.migration.step.MigrationStepRegistry;
 import org.sonar.server.platform.db.migration.step.MigrationSteps;
 import org.sonar.server.platform.db.migration.step.MigrationStepsExecutorImpl;
 import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
-import org.sonar.server.platform.db.migration.version.DbVersion;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
@@ -37,40 +34,15 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 public class MigrationContainerPopulatorImplTest {
-  private MigrationContainer migrationContainer = new SimpleMigrationContainer();
-  private MigrationSteps migrationSteps = mock(MigrationSteps.class);
-  private MigrationContainerPopulatorImpl underTest = new MigrationContainerPopulatorImpl();
+  private final SimpleMigrationContainer migrationContainer = new SimpleMigrationContainer();
+  private final MigrationSteps migrationSteps = mock(MigrationSteps.class);
+  private final MigrationContainerPopulatorImpl underTest = new MigrationContainerPopulatorImpl();
 
   @Before
   public void setUp() {
     migrationContainer.add(migrationSteps);
   }
 
-  @Test
-  public void populateContainer_adds_components_of_DbVersion_getSupportComponents() {
-    MigrationContainerPopulatorImpl underTest = new MigrationContainerPopulatorImpl(
-      new NoRegistryDbVersion() {
-        @Override
-        public Stream<Object> getSupportComponents() {
-          return Stream.of(Clazz2.class);
-        }
-      },
-      new NoRegistryDbVersion(),
-      new NoRegistryDbVersion() {
-        @Override
-        public Stream<Object> getSupportComponents() {
-          return Stream.of(Clazz1.class, Clazz3.class);
-        }
-      });
-    when(migrationSteps.readAll()).thenReturn(emptyList());
-
-    underTest.populateContainer(migrationContainer);
-
-    assertThat(migrationContainer.getComponentsByType(Clazz1.class)).isNotNull();
-    assertThat(migrationContainer.getComponentsByType(Clazz2.class)).isNotNull();
-    assertThat(migrationContainer.getComponentsByType(Clazz3.class)).isNotNull();
-  }
-
   @Test
   public void populateContainer_adds_MigrationStepsExecutorImpl() {
     when(migrationSteps.readAll()).thenReturn(emptyList());
@@ -78,6 +50,7 @@ public class MigrationContainerPopulatorImplTest {
     // add MigrationStepsExecutorImpl's dependencies
     migrationContainer.add(mock(MigrationHistory.class));
 
+    migrationContainer.startComponents();
     underTest.populateContainer(migrationContainer);
 
     assertThat(migrationContainer.getComponentByType(MigrationStepsExecutorImpl.class)).isNotNull();
@@ -90,6 +63,7 @@ public class MigrationContainerPopulatorImplTest {
       new RegisteredMigrationStep(2, "bar", MigrationStep2.class),
       new RegisteredMigrationStep(3, "dor", MigrationStep3.class)));
 
+    migrationContainer.startComponents();
     underTest.populateContainer(migrationContainer);
 
     assertThat(migrationContainer.getComponentsByType(MigrationStep1.class)).isNotNull();
@@ -106,6 +80,7 @@ public class MigrationContainerPopulatorImplTest {
       new RegisteredMigrationStep(4, "foo2", MigrationStep1.class),
       new RegisteredMigrationStep(5, "dor", MigrationStep3.class)));
 
+    migrationContainer.startComponents();
     underTest.populateContainer(migrationContainer);
 
     assertThat(migrationContainer.getComponentsByType(MigrationStep1.class)).isNotNull();
@@ -143,16 +118,4 @@ public class MigrationContainerPopulatorImplTest {
   public static final class Clazz3 {
 
   }
-
-  /**
-   * An implementation of DbVersion to be passed to {@link MigrationContainerPopulatorImpl}'s constructor which is
-   * not supposed to call the {@link DbVersion#addSteps(MigrationStepRegistry)} method and therefor has an
-   * implementation that throws a {@link UnsupportedOperationException} when called.
-   */
-  private static class NoRegistryDbVersion implements DbVersion {
-    @Override
-    public void addSteps(MigrationStepRegistry registry) {
-      throw new UnsupportedOperationException("addSteps is not supposed to be called");
-    }
-  }
 }
index 0506326ca7d5280312f17e8aa9cddfd2987d372e..f0b31e5c9aa189cb4b2d8ae077ecd77c750d8acb 100644 (file)
  */
 package org.sonar.server.platform.db.migration.engine;
 
+import java.sql.SQLException;
 import java.util.List;
 import java.util.Optional;
+import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.config.internal.ConfigurationBridge;
 import org.sonar.api.config.internal.MapSettings;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.process.ProcessProperties;
 import org.sonar.server.platform.db.migration.SupportsBlueGreen;
 import org.sonar.server.platform.db.migration.history.MigrationHistory;
@@ -38,42 +40,50 @@ import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 public class MigrationEngineImplTest {
-  private MigrationHistory migrationHistory = mock(MigrationHistory.class);
-  private ComponentContainer serverContainer = new ComponentContainer();
-  private MigrationStepsExecutor stepsExecutor = mock(MigrationStepsExecutor.class);
-  private MigrationContainerPopulator populator = container -> container.add(stepsExecutor);
-  private MigrationSteps migrationSteps = mock(MigrationSteps.class);
-
-  private MapSettings settings = new MapSettings();
-  private MigrationEngineImpl underTest = new MigrationEngineImpl(migrationHistory, serverContainer, populator, migrationSteps, new ConfigurationBridge(settings));
+  private final MigrationHistory migrationHistory = mock(MigrationHistory.class);
+  private final SpringComponentContainer serverContainer = new SpringComponentContainer();
+  private final MigrationSteps migrationSteps = mock(MigrationSteps.class);
+  private final StepRegistry stepRegistry = new StepRegistry();
+  private final MapSettings settings = new MapSettings();
+  private final MigrationEngineImpl underTest = new MigrationEngineImpl(migrationHistory, serverContainer, migrationSteps, new ConfigurationBridge(settings));
+
+  @Before
+  public void before() {
+    serverContainer.add(migrationSteps);
+    serverContainer.add(migrationHistory);
+    serverContainer.add(stepRegistry);
+    serverContainer.startComponents();
+  }
 
   @Test
   public void execute_execute_all_steps_of_there_is_no_last_migration_number() {
     when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.empty());
-    List<RegisteredMigrationStep> steps = singletonList(new RegisteredMigrationStep(1, "doo", MigrationStep.class));
+    List<RegisteredMigrationStep> steps = singletonList(new RegisteredMigrationStep(1, "doo", TestMigrationStep.class));
     when(migrationSteps.readAll()).thenReturn(steps);
 
     underTest.execute();
 
-    verify(migrationSteps).readAll();
-    verify(stepsExecutor).execute(steps);
+    verify(migrationSteps, times(2)).readAll();
+    assertThat(stepRegistry.stepRan).isTrue();
   }
 
   @Test
   public void execute_execute_steps_from_last_migration_number_plus_1() {
     when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.of(50L));
-    List<RegisteredMigrationStep> steps = singletonList(new RegisteredMigrationStep(1, "doo", MigrationStep.class));
+    List<RegisteredMigrationStep> steps = singletonList(new RegisteredMigrationStep(1, "doo", TestMigrationStep.class));
     when(migrationSteps.readFrom(51)).thenReturn(steps);
+    when(migrationSteps.readAll()).thenReturn(steps);
 
     underTest.execute();
 
     verify(migrationSteps).readFrom(51);
-    verify(stepsExecutor).execute(steps);
+    assertThat(stepRegistry.stepRan).isTrue();
   }
 
   @Test
@@ -82,11 +92,12 @@ public class MigrationEngineImplTest {
     when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.of(50L));
     List<RegisteredMigrationStep> steps = singletonList(new RegisteredMigrationStep(1, "doo", TestBlueGreenMigrationStep.class));
     when(migrationSteps.readFrom(51)).thenReturn(steps);
+    when(migrationSteps.readAll()).thenReturn(steps);
 
     underTest.execute();
 
     verify(migrationSteps).readFrom(51);
-    verify(stepsExecutor).execute(steps);
+    assertThat(stepRegistry.stepRan).isTrue();
   }
 
   @Test
@@ -95,7 +106,7 @@ public class MigrationEngineImplTest {
     when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.of(50L));
     List<RegisteredMigrationStep> steps = asList(
       new RegisteredMigrationStep(1, "foo", TestBlueGreenMigrationStep.class),
-      new RegisteredMigrationStep(2, "bar", MigrationStep.class));
+      new RegisteredMigrationStep(2, "bar", TestMigrationStep.class));
     when(migrationSteps.readFrom(51)).thenReturn(steps);
 
     try {
@@ -103,16 +114,43 @@ public class MigrationEngineImplTest {
       fail();
     } catch (IllegalStateException e) {
       assertThat(e).hasMessage("All migrations canceled. #2 does not support blue/green deployment: bar");
-      verifyZeroInteractions(stepsExecutor);
+      assertThat(stepRegistry.stepRan).isFalse();
+    }
+  }
+
+  private static class NoOpExecutor implements MigrationStepsExecutor {
+    @Override
+    public void execute(List<RegisteredMigrationStep> steps) {
+      // no op
+    }
+  }
+
+  private static class StepRegistry {
+    boolean stepRan = false;
+  }
+
+  private static class TestMigrationStep implements MigrationStep {
+    private final StepRegistry registry;
+
+    public TestMigrationStep(StepRegistry registry) {
+      this.registry = registry;
+    }
+    @Override
+    public void execute() throws SQLException {
+      registry.stepRan = true;
     }
   }
 
   @SupportsBlueGreen
   private static class TestBlueGreenMigrationStep implements MigrationStep {
+    private final StepRegistry registry;
 
+    public TestBlueGreenMigrationStep(StepRegistry registry) {
+      this.registry = registry;
+    }
     @Override
-    public void execute() {
-
+    public void execute() throws SQLException {
+      registry.stepRan = true;
     }
   }
 }
index cf7a049ef45ef0b6fcece22bbc60daab41d69564..3fc3bb69a9cebebed4878cb90ee7b7dc7a438c3f 100644 (file)
@@ -19,9 +19,9 @@
  */
 package org.sonar.server.platform.db.migration.engine;
 
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
-public final class SimpleMigrationContainer extends ComponentContainer implements MigrationContainer {
+public final class SimpleMigrationContainer extends SpringComponentContainer implements MigrationContainer {
 
   @Override
   public void cleanup() {
index c4f61331303c5e5e7d82d6a701897026699cc300..cdd6cf86ac9257a7b9a7c089fc7ee876f9ad08fc 100644 (file)
@@ -29,6 +29,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.server.platform.db.migration.engine.MigrationContainer;
 import org.sonar.server.platform.db.migration.engine.SimpleMigrationContainer;
 import org.sonar.server.platform.db.migration.history.MigrationHistory;
@@ -59,11 +60,12 @@ public class MigrationStepsExecutorImplTest {
   public void execute_fails_with_ISE_if_no_instance_of_computation_step_exist_in_container() {
     List<RegisteredMigrationStep> steps = asList(registeredStepOf(1, MigrationStep1.class));
 
+    ((SpringComponentContainer) migrationContainer).startComponents();
     try {
       underTest.execute(steps);
       fail("execute should have thrown a IllegalStateException");
     } catch (IllegalStateException e) {
-      assertThat(e).hasMessage("Can not find instance of " + MigrationStep1.class);
+      assertThat(e).hasMessage("Unable to load component " + MigrationStep1.class);
     } finally {
       assertThat(logTester.logs()).hasSize(2);
       assertLogLevel(LoggerLevel.INFO, "Executing DB migrations...");
@@ -87,6 +89,7 @@ public class MigrationStepsExecutorImplTest {
   @Test
   public void execute_execute_the_instance_of_type_specified_in_step_in_stream_order() {
     migrationContainer.add(MigrationStep1.class, MigrationStep2.class, MigrationStep3.class);
+    ((SpringComponentContainer) migrationContainer).startComponents();
 
     underTest.execute(asList(
       registeredStepOf(1, MigrationStep2.class),
@@ -119,6 +122,7 @@ public class MigrationStepsExecutorImplTest {
       registeredStepOf(2, SqlExceptionFailingMigrationStep.class),
       registeredStepOf(3, MigrationStep3.class));
 
+    ((SpringComponentContainer) migrationContainer).startComponents();
     try {
       underTest.execute(steps);
       fail("a MigrationStepExecutionException should have been thrown");
@@ -147,6 +151,7 @@ public class MigrationStepsExecutorImplTest {
       registeredStepOf(2, RuntimeExceptionFailingMigrationStep.class),
       registeredStepOf(3, MigrationStep3.class));
 
+    ((SpringComponentContainer) migrationContainer).startComponents();
     try {
       underTest.execute(steps);
       fail("should throw MigrationStepExecutionException");
index 40bc5fb99b537e1868b13df8aea2cb830a264e31..2f58a1dfa548d5165a44d60f85b4b0dc2a16f575 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.platform.db.migration.step;
 
-import java.util.Random;
 import org.junit.Test;
 import org.mockito.InOrder;
 import org.sonar.server.platform.db.migration.version.DbVersion;
@@ -30,13 +29,12 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 public class MigrationStepsProviderTest {
 
-  private InternalMigrationStepRegistry internalMigrationStepRegistry = mock(InternalMigrationStepRegistry.class);
-  private MigrationStepsProvider underTest = new MigrationStepsProvider();
+  private final InternalMigrationStepRegistry internalMigrationStepRegistry = mock(InternalMigrationStepRegistry.class);
+  private final MigrationStepsProvider underTest = new MigrationStepsProvider();
 
   @Test
   public void provide_throws_ISE_with_registry_build_throws_ISE_because_it_is_empty() {
@@ -49,7 +47,7 @@ public class MigrationStepsProviderTest {
   }
 
   @Test
-  public void provide_calls_DbVersion_addStep_in_order_and_only_once() {
+  public void provide_calls_DbVersion_addStep_in_order() {
     DbVersion dbVersion1 = newMockFailingOnSecondBuildCall();
     DbVersion dbVersion2 = newMockFailingOnSecondBuildCall();
     DbVersion dbVersion3 = newMockFailingOnSecondBuildCall();
@@ -64,24 +62,6 @@ public class MigrationStepsProviderTest {
     inOrder.verify(dbVersion2).addSteps(internalMigrationStepRegistry);
     inOrder.verify(dbVersion3).addSteps(internalMigrationStepRegistry);
     inOrder.verifyNoMoreInteractions();
-
-    // calling a second time with another argument, it's just ignored
-    DbVersion dbVersion4 = newMockFailingOnSecondBuildCall();
-    assertThat(underTest.provide(internalMigrationStepRegistry, dbVersion4)).isSameAs(expected);
-    verifyZeroInteractions(dbVersion4);
-  }
-
-  @Test
-  public void provide_always_returns_the_same_MigrationSteps_instance_and_calls_registry_build_only_once() {
-    MigrationSteps migrationSteps = mock(MigrationSteps.class);
-    when(internalMigrationStepRegistry.build())
-      .thenReturn(migrationSteps)
-      .thenThrow(new RuntimeException("method build should not be called twice"));
-
-    for (int i = 0; i < Math.abs(new Random().nextInt(50)) + 1; i++) {
-      assertThat(underTest.provide(internalMigrationStepRegistry)).isSameAs(migrationSteps);
-    }
-
   }
 
   private static DbVersion newMockFailingOnSecondBuildCall() {
index d4941aa97c19f456882d3ef83d33d4ac0147e157..92a05b1c2131558688e98fafb9903d57278838a2 100644 (file)
@@ -21,18 +21,12 @@ package org.sonar.server.platform.db.migration.version.v00;
 
 import org.junit.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationCount;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber;
 
 public class DbVersion00Test {
   private DbVersion00 underTest = new DbVersion00();
 
-  @Test
-  public void verify_no_support_component() {
-    assertThat(underTest.getSupportComponents()).isEmpty();
-  }
-
   @Test
   public void migrationNumber_starts_at_1153() {
     verifyMinimumMigrationNumber(underTest, 1);
index b9c1960fa6b6a8bf525d7ccaf16cfa56c57d92e1..6549102afc992963a149d3d3e1906549d402e7e3 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.platform.db.migration.version.v90;
 
 import org.junit.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationCount;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber;
 
@@ -29,11 +28,6 @@ public class DbVersion90Test {
 
   private final DbVersion90 underTest = new DbVersion90();
 
-  @Test
-  public void verify_no_support_component() {
-    assertThat(underTest.getSupportComponents()).isEmpty();
-  }
-
   @Test
   public void migrationNumber_starts_at_5001() {
     verifyMinimumMigrationNumber(underTest, 5001);
index 3b118ed75bd0a09417f5a4b369b1798e5f97ce4e..d8650e4bb11694b433697156479173e8a6313aea 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.platform.db.migration.version.v91;
 
 import org.junit.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationCount;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber;
 
@@ -29,11 +28,6 @@ public class DbVersion91Test {
 
   private final DbVersion91 underTest = new DbVersion91();
 
-  @Test
-  public void verify_no_support_component() {
-    assertThat(underTest.getSupportComponents()).isEmpty();
-  }
-
   @Test
   public void migrationNumber_starts_at_6001() {
     verifyMinimumMigrationNumber(underTest, 6001);
index 6df422e23e94b957752f325ee36271859282528e..bf036b4622cfcdc89a1d49df2227be4717704b97 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.platform.db.migration.version.v92;
 
 import org.junit.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationNotEmpty;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber;
 
@@ -29,11 +28,6 @@ public class DbVersion92Test {
 
   private final DbVersion92 underTest = new DbVersion92();
 
-  @Test
-  public void verify_no_support_component() {
-    assertThat(underTest.getSupportComponents()).isEmpty();
-  }
-
   @Test
   public void migrationNumber_starts_at_6101() {
     verifyMinimumMigrationNumber(underTest, 6101);
index d4479465020373e4defd94af1ad3b45ae4f0f740..12934c1456f2d1fd8d44aedb256e74738ae87284 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.platform.db.migration.version.v93;
 
 import org.junit.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationNotEmpty;
 import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber;
 
@@ -29,11 +28,6 @@ public class DbVersion93Test {
 
   private final DbVersion93 underTest = new DbVersion93();
 
-  @Test
-  public void verify_no_support_component() {
-    assertThat(underTest.getSupportComponents()).isEmpty();
-  }
-
   @Test
   public void migrationNumber_starts_at_6101() {
     verifyMinimumMigrationNumber(underTest, 6201);
index b4a58551d30d867b1425ba1dc7b16dd38af5e212..b2a5b7d5746d94df1dfacd26208269766579f8bf 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.process.cluster.hz.HazelcastMember;
 import org.sonar.process.cluster.hz.HazelcastObjects;
 
 import static java.util.Objects.requireNonNull;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class SharedHealthStateImpl implements SharedHealthState {
   private static final Logger LOG = LoggerFactory.getLogger(SharedHealthStateImpl.class);
@@ -39,10 +40,12 @@ public class SharedHealthStateImpl implements SharedHealthState {
 
   private final HazelcastMember hzMember;
 
+  @Autowired(required = false)
   public SharedHealthStateImpl(HazelcastMember hzMember) {
     this.hzMember = hzMember;
   }
 
+  @Autowired(required = false)
   public SharedHealthStateImpl() {
     this(null);
   }
index d0f6d8c6ce5608e14be39b69d6d05098c8c68d72..87c8f749fd29ff748d3d8ef71e30e3c75a27c300 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.async;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.process.Jmx;
 
 public class AsyncExecutionMBeanImpl implements AsyncExecutionMBean, Startable {
index b77f46ef4f04365249fda674311cece0de6502bd..cadee3af7970334654a37fe1f19dbe324377ebaf 100644 (file)
@@ -36,6 +36,8 @@ import static org.sonar.server.es.newindex.SettingsConfiguration.MANUAL_REFRESH_
 import static org.sonar.server.es.newindex.SettingsConfiguration.newBuilder;
 import static org.sonar.server.permission.index.IndexAuthorizationConstants.TYPE_AUTHORIZATION;
 
+import javax.inject.Inject;
+
 public class ComponentIndexDefinition implements IndexDefinition {
 
   public static final Index DESCRIPTOR = Index.withRelations("components");
@@ -58,6 +60,7 @@ public class ComponentIndexDefinition implements IndexDefinition {
     this.enableSource = enableSource;
   }
 
+  @Inject
   public ComponentIndexDefinition(Configuration config) {
     this(config, false);
   }
index babc5971a4e1033f22286f55e0b2f402e1961ede..f4a8c7cca58e4b5cf5bbbf7ceb43ebfd50df91f2 100644 (file)
  */
 package org.sonar.server.config;
 
-import java.util.Optional;
-import java.util.function.UnaryOperator;
+import static java.util.function.UnaryOperator.identity;
 import org.apache.commons.lang.ArrayUtils;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.config.PropertyDefinition;
-import org.sonar.api.config.internal.Settings;
-
-import static java.util.function.UnaryOperator.identity;
 import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
+import org.sonar.api.config.internal.Settings;
+import org.springframework.context.annotation.Bean;
 
-public class ConfigurationProvider extends ProviderAdapter {
+import java.util.Optional;
+import java.util.function.UnaryOperator;
 
-  private Configuration configuration;
+public class ConfigurationProvider {
 
+  @Bean("Configuration")
   public Configuration provide(Settings settings) {
-    if (configuration == null) {
-      configuration = new ServerConfigurationAdapter(settings);
-    }
-    return configuration;
+    return new ServerConfigurationAdapter(settings);
   }
 
   private static class ServerConfigurationAdapter implements Configuration {
index 16afc5b7e082eef17c72bbc219d4c47dd26aaed5..41f87cb5c977f9d599476d692078323a4476efd5 100644 (file)
@@ -28,13 +28,13 @@ import java.util.List;
 import java.util.stream.Collectors;
 import org.apache.http.HttpHost;
 import org.elasticsearch.common.settings.Settings;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.process.cluster.NodeType;
+import org.springframework.context.annotation.Bean;
 
 import static org.sonar.process.ProcessProperties.Property.CLUSTER_ENABLED;
 import static org.sonar.process.ProcessProperties.Property.CLUSTER_NAME;
@@ -47,38 +47,33 @@ import static org.sonar.process.cluster.NodeType.SEARCH;
 
 @ComputeEngineSide
 @ServerSide
-public class EsClientProvider extends ProviderAdapter {
-
+public class EsClientProvider {
   private static final Logger LOGGER = Loggers.get(EsClientProvider.class);
 
-  private EsClient cache;
-
+  @Bean("EsClient")
   public EsClient provide(Configuration config) {
-    if (cache == null) {
-      Settings.Builder esSettings = Settings.builder();
+    Settings.Builder esSettings = Settings.builder();
 
-      // mandatory property defined by bootstrap process
-      esSettings.put("cluster.name", config.get(CLUSTER_NAME.getKey()).get());
+    // mandatory property defined by bootstrap process
+    esSettings.put("cluster.name", config.get(CLUSTER_NAME.getKey()).get());
 
-      boolean clusterEnabled = config.getBoolean(CLUSTER_ENABLED.getKey()).orElse(false);
-      boolean searchNode = !clusterEnabled || SEARCH.equals(NodeType.parse(config.get(CLUSTER_NODE_TYPE.getKey()).orElse(null)));
-      List<HttpHost> httpHosts;
-      if (clusterEnabled && !searchNode) {
-        httpHosts = getHttpHosts(config);
+    boolean clusterEnabled = config.getBoolean(CLUSTER_ENABLED.getKey()).orElse(false);
+    boolean searchNode = !clusterEnabled || SEARCH.equals(NodeType.parse(config.get(CLUSTER_NODE_TYPE.getKey()).orElse(null)));
+    List<HttpHost> httpHosts;
+    if (clusterEnabled && !searchNode) {
+      httpHosts = getHttpHosts(config);
 
-        LOGGER.info("Connected to remote Elasticsearch: [{}]", displayedAddresses(httpHosts));
-      } else {
-        // defaults provided in:
-        // * in org.sonar.process.ProcessProperties.Property.SEARCH_HOST
-        // * in org.sonar.process.ProcessProperties.Property.SEARCH_PORT
-        HostAndPort host = HostAndPort.fromParts(config.get(SEARCH_HOST.getKey()).get(), config.getInt(SEARCH_PORT.getKey()).get());
-        httpHosts = Collections.singletonList(toHttpHost(host));
-        LOGGER.info("Connected to local Elasticsearch: [{}]", displayedAddresses(httpHosts));
-      }
-
-      cache = new EsClient(config.get(CLUSTER_SEARCH_PASSWORD.getKey()).orElse(null), httpHosts.toArray(new HttpHost[0]));
+      LOGGER.info("Connected to remote Elasticsearch: [{}]", displayedAddresses(httpHosts));
+    } else {
+      // defaults provided in:
+      // * in org.sonar.process.ProcessProperties.Property.SEARCH_HOST
+      // * in org.sonar.process.ProcessProperties.Property.SEARCH_PORT
+      HostAndPort host = HostAndPort.fromParts(config.get(SEARCH_HOST.getKey()).get(), config.getInt(SEARCH_PORT.getKey()).get());
+      httpHosts = Collections.singletonList(toHttpHost(host));
+      LOGGER.info("Connected to local Elasticsearch: [{}]", displayedAddresses(httpHosts));
     }
-    return cache;
+
+    return new EsClient(config.get(CLUSTER_SEARCH_PASSWORD.getKey()).orElse(null), httpHosts.toArray(new HttpHost[0]));
   }
 
   private static List<HttpHost> getHttpHosts(Configuration config) {
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/es/EsClientStopper.java b/server/sonar-server-common/src/main/java/org/sonar/server/es/EsClientStopper.java
deleted file mode 100644 (file)
index ef0957c..0000000
+++ /dev/null
@@ -1,53 +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.server.es;
-
-import org.sonar.api.Startable;
-
-/**
- * Workaround of a behaviour of picocontainer: components
- * instantiated by {@link org.picocontainer.injectors.ProviderAdapter}
- * can't have a lifecycle. The methods start() and stop()
- * of {@link Startable} are not executed.
- * The same behaviour exists for the {@link org.picocontainer.injectors.ProviderAdapter}
- * itself.
- *
- * As {@link EsClientStopper} implements {@link Startable}, it can
- * close {@link EsClient} when process shutdowns.
- *
- */
-public class EsClientStopper implements Startable {
-
-  private final EsClient esClient;
-
-  public EsClientStopper(EsClient esClient) {
-    this.esClient = esClient;
-  }
-
-  @Override
-  public void start() {
-    // nothing to do
-  }
-
-  @Override
-  public void stop() {
-    esClient.close();
-  }
-}
index 8d5762a7e889cc601cf49df22a9a6dd6bac92154..f6697d6e85d8c2183e1ca3d265692b0d593b3ca2 100644 (file)
@@ -25,6 +25,5 @@ public class EsModule extends Module {
   @Override
   protected void configureModule() {
     add(new EsClientProvider());
-    add(EsClientStopper.class);
   }
 }
index fe6600e00e2c5d70a3452befc37e8fb4e8845b3c..6e3d37b922a3451a7f56e0daf21954c377aa90ab 100644 (file)
@@ -25,7 +25,7 @@ import org.sonar.api.platform.ServerStartHandler;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
 import static java.lang.String.format;
 
@@ -35,9 +35,9 @@ import static java.lang.String.format;
 public class CoreExtensionBootstraper implements ServerStartHandler {
   private static final Logger LOGGER = Loggers.get(CoreExtensionBootstraper.class);
 
-  private final ComponentContainer componentContainer;
+  private final SpringComponentContainer componentContainer;
 
-  public CoreExtensionBootstraper(ComponentContainer componentContainer) {
+  public CoreExtensionBootstraper(SpringComponentContainer componentContainer) {
     this.componentContainer = componentContainer;
   }
 
index f1f9e379faec02f81afe384ebb573e4ebe9b65a9..f68235dee48f7926229ae33817ca4ddf44470aaa 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.extension;
 
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
 /**
  * Interface implemented by the Extension point exposed by the Core Extensions that serves as the unique access
@@ -32,11 +32,11 @@ public interface CoreExtensionBridge {
   /**
    * Bootstraps the plugin.
    *
-   * @param parent the parent ComponentContainer which provides Platform components for the Privileged plugin to use.
+   * @param parent the parent SpringComponentContainer which provides Platform components for the Privileged plugin to use.
    *
    * @throws IllegalStateException if called more than once
    */
-  void startPlugin(ComponentContainer parent);
+  void startPlugin(SpringComponentContainer parent);
 
   /**
    * This method is called when Platform is shutting down.
index 6ed176639431a39c9d289f812c40f57ecb9ab2df..d03548ac46d804d14d19ab71adbf3985103baf5e 100644 (file)
 package org.sonar.server.extension;
 
 import java.util.List;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.Container;
 
 import static java.lang.String.format;
 
@@ -35,9 +35,9 @@ import static java.lang.String.format;
 public class CoreExtensionStopper implements Startable {
   private static final Logger LOGGER = Loggers.get(CoreExtensionStopper.class);
 
-  private final ComponentContainer platformContainer;
+  private final Container platformContainer;
 
-  public CoreExtensionStopper(ComponentContainer platformContainer) {
+  public CoreExtensionStopper(Container platformContainer) {
     this.platformContainer = platformContainer;
   }
 
index 34c211d318b73120beb9d4fc1ccf6f24e2548602..fed04f29c974b679bbe1f633e41d72dcf3960605 100644 (file)
@@ -32,6 +32,8 @@ import static org.sonar.server.es.newindex.SettingsConfiguration.MANUAL_REFRESH_
 import static org.sonar.server.es.newindex.SettingsConfiguration.newBuilder;
 import static org.sonar.server.permission.index.IndexAuthorizationConstants.TYPE_AUTHORIZATION;
 
+import javax.inject.Inject;
+
 /**
  * Definition of ES index "issues", including settings and fields.
  */
@@ -110,6 +112,7 @@ public class IssueIndexDefinition implements IndexDefinition {
   private final Configuration config;
   private final boolean enableSource;
 
+  @Inject
   public IssueIndexDefinition(Configuration config) {
     this(config, false);
   }
index c39ebfee08c402a70287777eeba0d94e467e6bbc..f3b533175385914f14a84b752d877caae7b0f49d 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.issue.workflow;
 
 import java.util.List;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.issue.DefaultTransitions;
 import org.sonar.api.issue.Issue;
index 8e3c7fa4f46bcc1b4b497b65ac6513d7e2e94004..196fb2253db219547ad016050b8e5c577c3db16d 100644 (file)
@@ -23,7 +23,8 @@ import ch.qos.logback.classic.Level;
 import ch.qos.logback.classic.Logger;
 import com.google.common.annotations.VisibleForTesting;
 import java.io.File;
-import org.picocontainer.Startable;
+import javax.inject.Inject;
+import org.sonar.api.Startable;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.config.Configuration;
@@ -47,6 +48,7 @@ public class ServerLogging implements Startable {
   private final ServerProcessLogging serverProcessLogging;
   private final Database database;
 
+  @Inject
   public ServerLogging(Configuration config, ServerProcessLogging serverProcessLogging, Database database) {
     this(new LogbackHelper(), config, serverProcessLogging, database);
   }
index 5ade001ab94a551d886f70e8fa413b2df920a1a3..a4d3534e391e2eae0a63d53c769e4788d6e5e9a8 100644 (file)
@@ -34,6 +34,8 @@ import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.SORTABLE_
 import static org.sonar.server.es.newindex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
 import static org.sonar.server.es.newindex.SettingsConfiguration.newBuilder;
 
+import javax.inject.Inject;
+
 public class ProjectMeasuresIndexDefinition implements IndexDefinition {
 
   public static final Index DESCRIPTOR = Index.withRelations("projectmeasures");
@@ -71,6 +73,7 @@ public class ProjectMeasuresIndexDefinition implements IndexDefinition {
     this.enableSource = enableSource;
   }
 
+  @Inject
   public ProjectMeasuresIndexDefinition(Configuration config) {
     this(config, false);
   }
index aafa02f2c6f1442c4339ffbcd1951969d877bb15..c3bd24b8bc3cd14b861cdd2dac3a689758898959 100644 (file)
@@ -56,13 +56,10 @@ public class DefaultNotificationManager implements NotificationManager {
 
   private static final String UNABLE_TO_READ_NOTIFICATION = "Unable to read notification";
 
-  private NotificationChannel[] notificationChannels;
+  private final NotificationChannel[] notificationChannels;
   private final DbClient dbClient;
   private boolean alreadyLoggedDeserializationIssue = false;
 
-  /**
-   * Default constructor used by Pico
-   */
   public DefaultNotificationManager(NotificationChannel[] channels, DbClient dbClient) {
     this.notificationChannels = channels;
     this.dbClient = dbClient;
index f31572a35b2b94dd67ce3ad9dfa23f5d93721b21..925cc6bf43685532eeb4558e63c2e2fee12f64c8 100644 (file)
@@ -32,7 +32,7 @@ import static java.util.Objects.requireNonNull;
 /**
  * The notification manager receives notifications and is in charge of storing them so that they are processed by the notification service.
  * <p>
- * Pico provides an instance of this class, and plugins just need to create notifications and pass them to this manager with
+ * The ioc container provides an instance of this class, and plugins just need to create notifications and pass them to this manager with
  * the {@link NotificationManager#scheduleForSending(Notification)} method.
  * </p>
  */
index 8092ef3ad54ba958266c0152a0043f678366fe45..710658ca9983da7fd6c94002cdd135bcab8b0269 100644 (file)
@@ -39,6 +39,7 @@ import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.util.stream.MoreCollectors;
 import org.sonar.db.DbClient;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
@@ -52,6 +53,7 @@ public class NotificationService {
   private final List<NotificationHandler<? extends Notification>> handlers;
   private final DbClient dbClient;
 
+  @Autowired(required = false)
   public NotificationService(DbClient dbClient, NotificationDispatcher[] dispatchers, NotificationHandler<? extends Notification>[] handlers) {
     this.dbClient = dbClient;
     this.dispatchers = ImmutableList.copyOf(dispatchers);
@@ -59,22 +61,25 @@ public class NotificationService {
   }
 
   /**
-   * Used by Pico when there are no handler nor dispatcher.
+   * Used by the ioc container when there are no handler nor dispatcher.
    */
+  @Autowired(required = false)
   public NotificationService(DbClient dbClient) {
     this(dbClient, new NotificationDispatcher[0], new NotificationHandler[0]);
   }
 
   /**
-   * Used by Pico when there are no dispatcher.
+   * Used by the ioc container when there are no dispatcher.
    */
+  @Autowired(required = false)
   public NotificationService(DbClient dbClient, NotificationHandler[] handlers) {
     this(dbClient, new NotificationDispatcher[0], handlers);
   }
 
   /**
-   * Used by Pico when there are no handler.
+   * Used by the ioc container when there are no handler.
    */
+  @Autowired(required = false)
   public NotificationService(DbClient dbClient, NotificationDispatcher[] dispatchers) {
     this(dbClient, dispatchers, new NotificationHandler[0]);
   }
index 687d490057add43d9d3be5750cc1dd01307fa177..eed1210d9b70b24bb40faf6ca116cd6767683597 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.platform;
 import java.io.File;
 import java.io.IOException;
 import org.apache.commons.io.FileUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
index f71654e8b353195e606aefa411348b76b621bb12..fa720a5239b95b651767a206cb2fe9f78869fe13 100644 (file)
  */
 package org.sonar.server.platform;
 
-import org.picocontainer.Startable;
-import org.sonar.api.utils.log.Loggers;
+import javax.annotation.Nullable;
+import org.sonar.api.Startable;
 import org.sonar.api.platform.Server;
 import org.sonar.api.platform.ServerStartHandler;
 import org.sonar.api.platform.ServerStopHandler;
+import org.sonar.api.utils.log.Loggers;
 
 /**
  * @since 2.2
  */
 public class ServerLifecycleNotifier implements Startable {
 
-  private ServerStartHandler[] startHandlers;
-  private ServerStopHandler[] stopHandlers;
-  private Server server;
+  private final ServerStartHandler[] startHandlers;
+  private final ServerStopHandler[] stopHandlers;
+  private final Server server;
 
-  public ServerLifecycleNotifier(Server server, ServerStartHandler[] startHandlers, ServerStopHandler[] stopHandlers) {
-    this.startHandlers = startHandlers;
-    this.stopHandlers = stopHandlers;
+  public ServerLifecycleNotifier(Server server, @Nullable ServerStartHandler[] startHandlers, @Nullable ServerStopHandler[] stopHandlers) {
+    this.startHandlers = startHandlers != null ? startHandlers :  new ServerStartHandler[0];
+    this.stopHandlers = stopHandlers != null ? stopHandlers: new ServerStopHandler[0];
     this.server = server;
   }
 
-  public ServerLifecycleNotifier(Server server, ServerStartHandler[] startHandlers) {
-    this(server, startHandlers, new ServerStopHandler[0]);
-  }
-
-  public ServerLifecycleNotifier(Server server, ServerStopHandler[] stopHandlers) {
-    this(server, new ServerStartHandler[0], stopHandlers);
-  }
-
-  public ServerLifecycleNotifier(Server server) {
-    this(server, new ServerStartHandler[0], new ServerStopHandler[0]);
-  }
-
   @Override
   public void start() {
     /* IMPORTANT :
      we want to be sure that handlers are notified when all other services are started.
-     That's why the class Platform explicitely executes the method notifyStart(), instead of letting picocontainer
+     That's why the class Platform explicitely executes the method notifyStart(), instead of letting the ioc container
      choose the startup order.
      */
   }
index 88efc4d81f833acba13a6bbc65688deec41252c0..19e714c9a287e39d5ded6b9070a983774514bc0b 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.platform;
 
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.SonarQubeSide;
 import org.sonar.api.SonarRuntime;
@@ -30,6 +29,7 @@ import org.sonar.api.utils.System2;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.property.PropertyDto;
+import org.springframework.context.annotation.Bean;
 
 import static com.google.common.base.Preconditions.checkState;
 import static org.apache.commons.lang.StringUtils.isBlank;
@@ -37,19 +37,14 @@ import static org.sonar.api.CoreProperties.SERVER_STARTTIME;
 
 @ComputeEngineSide
 @ServerSide
-public class StartupMetadataProvider extends ProviderAdapter {
-
-  private StartupMetadata cache = null;
-
+public class StartupMetadataProvider {
+  @Bean("StartupMetadata")
   public StartupMetadata provide(System2 system, SonarRuntime runtime, WebServer webServer, DbClient dbClient) {
-    if (cache == null) {
-      if (runtime.getSonarQubeSide() == SonarQubeSide.SERVER && webServer.isStartupLeader()) {
-        cache = generate(system);
-      } else {
-        cache = load(dbClient);
-      }
+    if (runtime.getSonarQubeSide() == SonarQubeSide.SERVER && webServer.isStartupLeader()) {
+      return generate(system);
+    } else {
+      return load(dbClient);
     }
-    return cache;
   }
 
   /**
index af3c93c31dd49a2d70e49fcb870538e26d413c05..9c5d476b045815ec3cabc3cbcecc2af8cef635c5 100644 (file)
@@ -22,24 +22,19 @@ package org.sonar.server.platform;
 import java.io.File;
 import java.io.IOException;
 import org.apache.commons.io.FileUtils;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.impl.utils.DefaultTempFolder;
 import org.sonar.api.utils.TempFolder;
+import org.springframework.context.annotation.Bean;
 
-public class TempFolderProvider extends ProviderAdapter {
-
-  private TempFolder tempFolder;
-
+public class TempFolderProvider {
+  @Bean("TempFolder")
   public TempFolder provide(ServerFileSystem fs) {
-    if (tempFolder == null) {
-      File tempDir = new File(fs.getTempDir(), "tmp");
-      try {
-        FileUtils.forceMkdir(tempDir);
-      } catch (IOException e) {
-        throw new IllegalStateException("Unable to create temp directory " + tempDir, e);
-      }
-      tempFolder = new DefaultTempFolder(tempDir);
+    File tempDir = new File(fs.getTempDir(), "tmp");
+    try {
+      FileUtils.forceMkdir(tempDir);
+    } catch (IOException e) {
+      throw new IllegalStateException("Unable to create temp directory " + tempDir, e);
     }
-    return tempFolder;
+    return new DefaultTempFolder(tempDir);
   }
 }
index 78530477e2632ae2167d291108ad9b7e685448f4..a93f2d80d734acc2d559c0591efb20e8a17267c8 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.plugins;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.core.platform.PluginRepository;
 import org.sonar.updatecenter.common.PluginReferential;
 
index 89b64ce6365bb9a2cb8b148654123ac16dec0419..523d70fe1dc944aca65dcfe49e84593919f6f704 100644 (file)
@@ -22,18 +22,19 @@ package org.sonar.server.plugins;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ListMultimap;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import java.util.Set;
 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.api.utils.AnnotationUtils;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 import org.sonar.core.platform.PluginInfo;
 import org.sonar.core.platform.PluginRepository;
 
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.Set;
+
 import static java.lang.String.format;
 import static java.util.Objects.requireNonNull;
 
@@ -41,18 +42,21 @@ import static java.util.Objects.requireNonNull;
  * Loads the plugins server extensions and injects them to DI container
  */
 public abstract class ServerExtensionInstaller {
+  private final Configuration configuration;
   private final SonarRuntime sonarRuntime;
   private final PluginRepository pluginRepository;
   private final Set<Class<? extends Annotation>> supportedAnnotationTypes;
 
-  protected ServerExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository, Collection<Class<? extends Annotation>> supportedAnnotationTypes) {
+  protected ServerExtensionInstaller(Configuration configuration, SonarRuntime sonarRuntime, PluginRepository pluginRepository,
+    Collection<Class<? extends Annotation>> supportedAnnotationTypes) {
     requireNonNull(supportedAnnotationTypes, "At least one supported annotation type must be specified");
+    this.configuration = configuration;
     this.sonarRuntime = sonarRuntime;
     this.pluginRepository = pluginRepository;
     this.supportedAnnotationTypes = ImmutableSet.copyOf(supportedAnnotationTypes);
   }
 
-  public void installExtensions(ComponentContainer container) {
+  public void installExtensions(ExtensionContainer container) {
     ListMultimap<PluginInfo, Object> installedExtensionsByPlugin = ArrayListMultimap.create();
     for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
       try {
@@ -62,7 +66,7 @@ public abstract class ServerExtensionInstaller {
 
         Plugin.Context context = new PluginContextImpl.Builder()
           .setSonarRuntime(sonarRuntime)
-          .setBootConfiguration(container.getComponentByType(Configuration.class))
+          .setBootConfiguration(configuration)
           .build();
         plugin.define(context);
         for (Object extension : context.getExtensions()) {
@@ -79,7 +83,7 @@ public abstract class ServerExtensionInstaller {
     }
   }
 
-  private Object installExtension(ComponentContainer container, PluginInfo pluginInfo, Object extension) {
+  private Object installExtension(ExtensionContainer container, PluginInfo pluginInfo, Object extension) {
     for (Class<? extends Annotation> supportedAnnotationType : supportedAnnotationTypes) {
       if (AnnotationUtils.getAnnotation(extension, supportedAnnotationType) != null) {
         container.addExtension(pluginInfo, extension);
index b4f42b8fb57adabd150b98f677936bf90185510a..23b0b2a2693fdc65a899b89ccf9d30072d5d4991 100644 (file)
@@ -37,6 +37,8 @@ import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.SORTABLE_
 import static org.sonar.server.es.newindex.SettingsConfiguration.MANUAL_REFRESH_INTERVAL;
 import static org.sonar.server.es.newindex.SettingsConfiguration.newBuilder;
 
+import javax.inject.Inject;
+
 /**
  * Definition of ES index "rules", including settings and fields.
  */
@@ -82,6 +84,7 @@ public class RuleIndexDefinition implements IndexDefinition {
   private final Configuration config;
   private final boolean enableSource;
 
+  @Inject
   public RuleIndexDefinition(Configuration config) {
     this(config, false);
   }
index 530f318adf99a1bdf060478a5393dcd06186c7ba..0bc77907753663d35e31f26aab00f6ad557e529c 100644 (file)
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
+import javax.inject.Inject;
 import org.apache.ibatis.exceptions.PersistenceException;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.ce.ComputeEngineSide;
@@ -60,6 +61,7 @@ public class ThreadLocalSettings extends Settings {
   private Map<String, String> getPropertiesDbFailureCache = Collections.emptyMap();
   private SettingLoader settingLoader;
 
+  @Inject
   public ThreadLocalSettings(PropertyDefinitions definitions, Properties props) {
     this(definitions, props, new NopSettingLoader());
   }
index ca822c8cb97e539d4c420ca37518b7e0f642ae11..8c1a88e9484106dd80db818d8827cd73531141d3 100644 (file)
 package org.sonar.server.util;
 
 import okhttp3.OkHttpClient;
-import org.picocontainer.injectors.ProviderAdapter;
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.server.ServerSide;
 import org.sonarqube.ws.client.OkHttpClientBuilder;
+import org.springframework.context.annotation.Bean;
 
 import static java.lang.String.format;
 import static org.sonar.process.ProcessProperties.Property.HTTP_PROXY_PASSWORD;
@@ -43,28 +43,24 @@ import static org.sonar.process.ProcessProperties.Property.HTTP_PROXY_USER;
  */
 @ServerSide
 @ComputeEngineSide
-public class OkHttpClientProvider extends ProviderAdapter {
+public class OkHttpClientProvider {
 
   private static final int DEFAULT_CONNECT_TIMEOUT_IN_MS = 10_000;
   private static final int DEFAULT_READ_TIMEOUT_IN_MS = 10_000;
 
-  private okhttp3.OkHttpClient okHttpClient;
-
   /**
    * @return a {@link OkHttpClient} singleton
    */
+  @Bean("OkHttpClient")
   public OkHttpClient provide(Configuration config, SonarRuntime runtime) {
-    if (okHttpClient == null) {
-      OkHttpClientBuilder builder = new OkHttpClientBuilder();
-      builder.setConnectTimeoutMs(DEFAULT_CONNECT_TIMEOUT_IN_MS);
-      builder.setReadTimeoutMs(DEFAULT_READ_TIMEOUT_IN_MS);
-      // no need to define proxy URL as system-wide proxy is used and properly
-      // configured by bootstrap process.
-      builder.setProxyLogin(config.get(HTTP_PROXY_USER.getKey()).orElse(null));
-      builder.setProxyPassword(config.get(HTTP_PROXY_PASSWORD.getKey()).orElse(null));
-      builder.setUserAgent(format("SonarQube/%s", runtime.getApiVersion().toString()));
-      okHttpClient = builder.build();
-    }
-    return okHttpClient;
+    OkHttpClientBuilder builder = new OkHttpClientBuilder();
+    builder.setConnectTimeoutMs(DEFAULT_CONNECT_TIMEOUT_IN_MS);
+    builder.setReadTimeoutMs(DEFAULT_READ_TIMEOUT_IN_MS);
+    // no need to define proxy URL as system-wide proxy is used and properly
+    // configured by bootstrap process.
+    builder.setProxyLogin(config.get(HTTP_PROXY_USER.getKey()).orElse(null));
+    builder.setProxyPassword(config.get(HTTP_PROXY_PASSWORD.getKey()).orElse(null));
+    builder.setUserAgent(format("SonarQube/%s", runtime.getApiVersion().toString()));
+    return builder.build();
   }
 }
index a576ecaea83069f4b90e4145b6556298a256b2f4..07b97ad2c0d7285ac941064b1bd890b67615fa76 100644 (file)
 package org.sonar.server.util;
 
 import java.util.concurrent.ExecutorService;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 
 /**
- * ExecutorService that exposes a {@code stop} method which can be invoked by Pico container to shutdown properly
+ * ExecutorService that exposes a {@code stop} method which can be invoked by the ioc container to shutdown properly
  * the service.
  */
 public interface StoppableExecutorService extends ExecutorService, Startable {
index 4d16122024e3c0aba00ab85f16ce94b4d727e54e..a6cf185477a368e2c567561745281a75e0eb68c5 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.util;
 import java.util.concurrent.ScheduledExecutorService;
 
 /**
- * ScheduledExecutorService that exposes a {@code stop} method which can be invoked by Pico container to shutdown
+ * ScheduledExecutorService that exposes a {@code stop} method which can be invoked by the ioc container to shutdown
  * properly the service.
  */
 public interface StoppableScheduledExecutorService extends ScheduledExecutorService, StoppableExecutorService {
index 959488fd09b704cbfe147695a0b5cc7fff59b980..a4957a6b68b90d93f030d2064bd9740d2607eca6 100644 (file)
@@ -42,8 +42,6 @@ import static org.sonar.process.ProcessProperties.Property.SEARCH_HOST;
 import static org.sonar.process.ProcessProperties.Property.SEARCH_PORT;
 
 public class EsClientProviderTest {
-
-
   @Rule
   public LogTester logTester = new LogTester();
 
@@ -74,9 +72,6 @@ public class EsClientProviderTest {
     assertThat(node.getHost().getPort()).isEqualTo(9000);
 
     assertThat(logTester.logs(LoggerLevel.INFO)).has(new Condition<>(s -> s.contains("Connected to local Elasticsearch: [http://" + localhostHostname + ":9000]"), ""));
-
-    // keep in cache
-    assertThat(underTest.provide(settings.asConfig())).isSameAs(client);
   }
 
   @Test
@@ -99,9 +94,6 @@ public class EsClientProviderTest {
 
     assertThat(logTester.logs(LoggerLevel.INFO))
       .has(new Condition<>(s -> s.contains("Connected to remote Elasticsearch: [http://" + localhostHostname + ":8080, http://" + localhostHostname + ":8081]"), ""));
-
-    // keep in cache
-    assertThat(underTest.provide(settings.asConfig())).isSameAs(client);
   }
 
   @Test
@@ -147,8 +139,5 @@ public class EsClientProviderTest {
 
     assertThat(logTester.logs(LoggerLevel.INFO))
       .has(new Condition<>(s -> s.contains("Connected to remote Elasticsearch: [http://" + localhostHostname + ":9001, http://" + localhostHostname + ":8081]"), ""));
-
-    // keep in cache
-    assertThat(underTest.provide(settings.asConfig())).isSameAs(client);
   }
 }
diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/es/EsClientStopperTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/es/EsClientStopperTest.java
deleted file mode 100644 (file)
index 6787d21..0000000
+++ /dev/null
@@ -1,41 +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.server.es;
-
-import org.junit.Test;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-public class EsClientStopperTest {
-
-  private EsClient client = mock(EsClient.class);
-  private EsClientStopper underTest = new EsClientStopper(client);
-
-  @Test
-  public void stop_client() {
-    underTest.start();
-    verifyNoMoreInteractions(client);
-
-    underTest.stop();
-    verify(client).close();
-  }
-}
index c48c2d0bbbca3463e6794e5124fb4799befa04d0..3c4a5ebe4a723e2d28918b5186502e1df9fbbbf1 100644 (file)
 package org.sonar.server.es;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class EsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new EsModule().configure(container);
-    assertThat(container.size()).isEqualTo(2 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER);
+    assertThat(container.getAddedObjects()).hasSize(1);
   }
-
 }
index a316b2f46ae1ecda28854eaa87bf869be714a523..c000fe9ded9b1c65572664f6ed26e6c5770f6049 100644 (file)
@@ -21,17 +21,16 @@ package org.sonar.server.extension;
 
 import org.junit.Test;
 import org.sonar.api.platform.Server;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 public class CoreExtensionBootstraperTest {
-  private ComponentContainer componentContainer = new ComponentContainer();
-  private CoreExtensionBridge bridge = mock(CoreExtensionBridge.class);
-
-  private CoreExtensionBootstraper underTest = new CoreExtensionBootstraper(componentContainer);
+  private final SpringComponentContainer componentContainer = new SpringComponentContainer();
+  private final CoreExtensionBridge bridge = mock(CoreExtensionBridge.class);
+  private final CoreExtensionBootstraper underTest = new CoreExtensionBootstraper(componentContainer);
 
   @Test
   public void onServerStart_calls_startPlugin_if_Bridge_exists_in_container() {
@@ -47,6 +46,7 @@ public class CoreExtensionBootstraperTest {
 
   @Test
   public void onServerStart_does_not_call_startPlugin_if_Bridge_does_not_exist_in_container() {
+    componentContainer.startComponents();
     underTest.onServerStart(mock(Server.class));
 
     verifyNoMoreInteractions(bridge);
index c93913c2078e8c2ea30f8bb04f0da8215227f0d9..995e03a9b74dc0c8c443472ba98c38a4ae8a31fb 100644 (file)
 package org.sonar.server.extension;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 public class CoreExtensionStopperTest {
-  private ComponentContainer componentContainer = new ComponentContainer();
-  private CoreExtensionBridge bridge = mock(CoreExtensionBridge.class);
-
-  private CoreExtensionStopper underTest = new CoreExtensionStopper(componentContainer);
+  private final SpringComponentContainer componentContainer = new SpringComponentContainer();
+  private final CoreExtensionBridge bridge = mock(CoreExtensionBridge.class);
+  private final CoreExtensionStopper underTest = new CoreExtensionStopper(componentContainer);
 
   @Test
   public void stop_calls_stopPlugin_if_Bridge_exists_in_container() {
@@ -46,6 +45,7 @@ public class CoreExtensionStopperTest {
 
   @Test
   public void stop_does_not_call_stopPlugin_if_Bridge_does_not_exist_in_container() {
+    componentContainer.startComponents();
     underTest.stop();
 
     verifyNoMoreInteractions(bridge);
index 9bfc49467bd04e4159ec3b741a6621ef97ddabcd..66e7e3912f10f25768f62857143293d9789b3971 100644 (file)
 package org.sonar.server.issue.notification;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class IssuesChangesNotificationModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new IssuesChangesNotificationModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 7);
+    assertThat(container.getAddedObjects()).hasSize(7);
   }
 
 
index d6e54529be7fcb0c563f358687fea2fff11a26c1..e09a0ba882442e997082852b31c70814d08a8270 100644 (file)
@@ -26,6 +26,7 @@ import org.sonar.api.platform.Server;
 import org.sonar.api.platform.ServerStartHandler;
 import org.sonar.api.platform.ServerStopHandler;
 
+import static org.assertj.core.api.Assertions.assertThatNoException;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -52,7 +53,7 @@ public class ServerLifecycleNotifierTest {
    */
   @Test
   public void doNotNotifyWithTheStartMethod() {
-    ServerLifecycleNotifier notifier = new ServerLifecycleNotifier(server, new ServerStartHandler[]{start1, start2}, new ServerStopHandler[]{stop2});
+    ServerLifecycleNotifier notifier = new ServerLifecycleNotifier(server, new ServerStartHandler[] {start1, start2}, new ServerStopHandler[] {stop2});
     notifier.start();
 
     verify(start1, never()).onServerStart(server);
@@ -62,7 +63,7 @@ public class ServerLifecycleNotifierTest {
 
   @Test
   public void notifyOnStart() {
-    ServerLifecycleNotifier notifier = new ServerLifecycleNotifier(server, new ServerStartHandler[]{start1, start2}, new ServerStopHandler[]{stop2});
+    ServerLifecycleNotifier notifier = new ServerLifecycleNotifier(server, new ServerStartHandler[] {start1, start2}, new ServerStopHandler[] {stop2});
     notifier.notifyStart();
 
     verify(start1).onServerStart(server);
@@ -70,10 +71,9 @@ public class ServerLifecycleNotifierTest {
     verify(stop1, never()).onServerStop(server);
   }
 
-
   @Test
   public void notifyOnStop() {
-    ServerLifecycleNotifier notifier = new ServerLifecycleNotifier(server, new ServerStartHandler[]{start1, start2}, new ServerStopHandler[]{stop1, stop2});
+    ServerLifecycleNotifier notifier = new ServerLifecycleNotifier(server, new ServerStartHandler[] {start1, start2}, new ServerStopHandler[] {stop1, stop2});
     notifier.stop();
 
     verify(start1, never()).onServerStart(server);
@@ -81,6 +81,13 @@ public class ServerLifecycleNotifierTest {
     verify(stop1).onServerStop(server);
     verify(stop2).onServerStop(server);
   }
+
+  @Test
+  public void null_handler_param_wont_lead_to_NPE() {
+    ServerLifecycleNotifier notifier = new ServerLifecycleNotifier(server, null, null);
+    assertThatNoException().isThrownBy(notifier::notifyStart);
+    assertThatNoException().isThrownBy(notifier::stop);
+  }
 }
 
 class FakeServer extends Server {
index 724e54efda29ddf9a59fe7fa7cac602a59c3d88a..1b1eb7f902a5e448378d1f20338fd045b5042ae3 100644 (file)
@@ -34,21 +34,19 @@ import org.sonar.db.property.PropertyDto;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 import static org.sonar.api.utils.DateUtils.formatDateTime;
 
 public class StartupMetadataProviderTest {
-
   private static final long A_DATE = 1_500_000_000_000L;
 
-
   @Rule
   public DbTester dbTester = DbTester.create(System2.INSTANCE);
 
-  private StartupMetadataProvider underTest = new StartupMetadataProvider();
-  private System2 system = mock(System2.class);
-  private WebServer webServer = mock(WebServer.class);
+  private final StartupMetadataProvider underTest = new StartupMetadataProvider();
+  private final System2 system = mock(System2.class);
+  private final WebServer webServer = mock(WebServer.class);
 
   @Test
   public void generate_SERVER_STARTIME_but_do_not_persist_it_if_server_is_startup_leader() {
@@ -60,10 +58,6 @@ public class StartupMetadataProviderTest {
     assertThat(metadata.getStartedAt()).isEqualTo(A_DATE);
 
     assertNotPersistedProperty(CoreProperties.SERVER_STARTTIME);
-
-    // keep a cache
-    StartupMetadata secondMetadata = underTest.provide(system, runtime, webServer, dbTester.getDbClient());
-    assertThat(secondMetadata).isSameAs(metadata);
   }
 
   @Test
@@ -109,11 +103,7 @@ public class StartupMetadataProviderTest {
     // still in database
     assertPersistedProperty(CoreProperties.SERVER_STARTTIME, formatDateTime(A_DATE));
 
-    // keep a cache
-    StartupMetadata secondMetadata = underTest.provide(system, runtime, webServer, dbTester.getDbClient());
-    assertThat(secondMetadata).isSameAs(metadata);
-
-    verifyZeroInteractions(system);
+    verifyNoInteractions(system);
   }
 
   private void assertPersistedProperty(String propertyKey, String expectedValue) {
index 7ea17aeca909a9cf2d583896f810046d9b5aabfb..f8a82450dffa9dd9050e098847864d1f1d1aca72 100644 (file)
@@ -31,12 +31,10 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 public class TempFolderProviderTest {
-
-
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
-  TempFolderProvider underTest = new TempFolderProvider();
+  private final TempFolderProvider underTest = new TempFolderProvider();
 
   @Test
   public void existing_temp_dir() throws Exception {
index c8b3e0db11820e6722b8957e2304d4b0efaa0641..ce7004ea6cbb3951c799358e0efe35765c05fa28 100644 (file)
@@ -27,10 +27,11 @@ import org.sonar.api.Plugin;
 import org.sonar.api.SonarEdition;
 import org.sonar.api.SonarQubeSide;
 import org.sonar.api.SonarRuntime;
+import org.sonar.api.config.Configuration;
 import org.sonar.api.internal.SonarRuntimeImpl;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.Version;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 import org.sonar.core.platform.PluginInfo;
 import org.sonar.core.platform.PluginRepository;
 
@@ -42,7 +43,6 @@ import static org.mockito.Mockito.when;
 public class ServerExtensionInstallerTest {
   private SonarRuntime sonarRuntime = SonarRuntimeImpl.forSonarQube(Version.parse("8.0"), SonarQubeSide.SERVER, SonarEdition.COMMUNITY);
   private TestPluginRepository pluginRepository = new TestPluginRepository();
-
   private TestServerExtensionInstaller underTest = new TestServerExtensionInstaller(sonarRuntime, pluginRepository);
 
   @Test
@@ -50,11 +50,11 @@ public class ServerExtensionInstallerTest {
     PluginInfo fooPluginInfo = newPlugin("foo", "Foo");
     Plugin fooPlugin = mock(Plugin.class);
     pluginRepository.add(fooPluginInfo, fooPlugin);
-    ComponentContainer componentContainer = new ComponentContainer();
+    ListContainer componentContainer = new ListContainer();
 
     underTest.installExtensions(componentContainer);
 
-    assertThat(componentContainer.getPicoContainer().getComponents()).contains(fooPlugin);
+    assertThat(componentContainer.getAddedObjects()).contains(fooPlugin);
   }
 
   private static PluginInfo newPlugin(String key, String name) {
@@ -108,7 +108,7 @@ public class ServerExtensionInstallerTest {
   private static class TestServerExtensionInstaller extends ServerExtensionInstaller {
 
     protected TestServerExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository) {
-      super(sonarRuntime, pluginRepository, singleton(ServerSide.class));
+      super(mock(Configuration.class), sonarRuntime, pluginRepository, singleton(ServerSide.class));
     }
   }
 
index 729ac9654dc7f0beaf7d17f474f3617a725c4b5b..01879d1053a6d624a66810f2d41e5bdbf8bf9e54 100644 (file)
@@ -41,8 +41,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 public class OkHttpClientProviderTest {
 
-  private MapSettings settings = new MapSettings();
-  private SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.parse("6.2"), SonarQubeSide.SERVER, SonarEdition.COMMUNITY);
+  private final MapSettings settings = new MapSettings();
+  private final SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.parse("6.2"), SonarQubeSide.SERVER, SonarEdition.COMMUNITY);
   private final OkHttpClientProvider underTest = new OkHttpClientProvider();
 
   @Rule
@@ -74,13 +74,6 @@ public class OkHttpClientProviderTest {
     assertThat(request.header("Proxy-Authorization")).isEqualTo("Basic " + Base64.getEncoder().encodeToString("the-login:the-password".getBytes()));
   }
 
-  @Test
-  public void get_returns_a_singleton() {
-    OkHttpClient client1 = underTest.provide(settings.asConfig(), runtime);
-    OkHttpClient client2 = underTest.provide(settings.asConfig(), runtime);
-    assertThat(client2).isNotNull().isSameAs(client1);
-  }
-
   private RecordedRequest call(OkHttpClient client) throws IOException, InterruptedException {
     server.enqueue(new MockResponse().setBody("pong"));
     client.newCall(new Request.Builder().url(server.url("/ping")).build()).execute();
index f53ad77b45946c12bc80b79123837930927d2f60..20bd6df587e18ac5540d34bfef2b550adf2d00ad 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.webhook;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -30,10 +30,10 @@ public class WebhookModuleTest {
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    assertThat(container.size()).isNotZero();
+    assertThat(container.getAddedObjects().size()).isNotZero();
   }
 }
index 9a156bbc4fe8f84655f000bf9039c127a3a31a09..208827927e720438ab156234c65f285ab9f1d0ba 100644 (file)
  */
 package org.sonar.server.branch;
 
+import javax.annotation.Nullable;
+
 public class BranchFeatureProxyImpl implements BranchFeatureProxy {
 
   private final BranchFeatureExtension branchFeatureExtension;
 
-  public BranchFeatureProxyImpl() {
-    this.branchFeatureExtension = null;
-  }
-
-  public BranchFeatureProxyImpl(BranchFeatureExtension branchFeatureExtension) {
+  public BranchFeatureProxyImpl(@Nullable BranchFeatureExtension branchFeatureExtension) {
     this.branchFeatureExtension = branchFeatureExtension;
   }
 
index 90327ca6b605a35e94986306ee7cb847affa7125..2881354d7f69661864d6877ffbc771f38e7755a6 100644 (file)
  */
 package org.sonar.server.platform;
 
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 
 public interface Platform {
   void doStart();
 
   Status status();
 
-  ComponentContainer getContainer();
+  ExtensionContainer getContainer();
 
   enum Status {
     BOOTING, SAFEMODE, STARTING, UP
index 67388bab01af3051d41b214f1fe3304c45bb9270..c50fb1209dfab125359a007d371e83684a7e6072 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.plugins;
 
 import java.util.Optional;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.extension.PluginRiskConsent;
index eea3869e8fd18f8b0edcf167f1bc1de0a2f4e091..d1dc564756a0871652f5cf3542723a365daa6bff 100644 (file)
@@ -28,7 +28,7 @@ import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import org.apache.commons.io.FileUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.HttpDownloader;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
index 504fae1fba3bfb3dfe48fd82c8f9159e548f5df7..0f2eb7ccab9eaa99f5cd27da5b1f2970c4662549 100644 (file)
@@ -50,6 +50,8 @@ import static org.sonar.server.log.ServerProcessLogging.STARTUP_LOGGER_NAME;
 import static org.sonar.server.plugins.PluginType.BUNDLED;
 import static org.sonar.server.plugins.PluginType.EXTERNAL;
 
+import javax.inject.Inject;
+
 public class PluginJarLoader {
   private static final Logger LOG = Loggers.get(PluginJarLoader.class);
 
@@ -65,6 +67,7 @@ public class PluginJarLoader {
   private final SonarRuntime runtime;
   private final Set<String> blacklistedPluginKeys;
 
+  @Inject
   public PluginJarLoader(ServerFileSystem fs, SonarRuntime runtime) {
     this(fs, runtime, DEFAULT_BLACKLISTED_PLUGINS);
   }
index af64eb42f9b38deb57c3433b827805c87a9b4e21..c33155e39adb064e6d915d843d8284a5bbbf0180 100644 (file)
@@ -26,7 +26,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import org.apache.commons.io.FileUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.core.platform.PluginInfo;
index 36ec05cd55d785c6d3dbf74789ecf652d68feb1f..6f83c5839912dc8504d524f2083ee61549cb7bc3 100644 (file)
@@ -24,7 +24,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.Plugin;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
index b384b808fcf65e1d1e59f6fbc588b7a9c1735fc0..b25cd9b9644be7ff40372789c6832fb2803e028f 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.plugins;
 
 import org.sonar.api.SonarRuntime;
+import org.sonar.api.config.Configuration;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.platform.PluginRepository;
 
@@ -27,7 +28,7 @@ import static java.util.Collections.singleton;
 
 @ServerSide
 public class WebServerExtensionInstaller extends ServerExtensionInstaller {
-  public WebServerExtensionInstaller(SonarRuntime sonarRuntime, PluginRepository pluginRepository) {
-    super(sonarRuntime, pluginRepository, singleton(ServerSide.class));
+  public WebServerExtensionInstaller(Configuration configuration, SonarRuntime sonarRuntime, PluginRepository pluginRepository) {
+    super(configuration, sonarRuntime, pluginRepository, singleton(ServerSide.class));
   }
 }
index f752797d58034b871688a48f9490d14d05ff242f..89c69236aa06183873fe3b273c25195cd14c46d5 100644 (file)
@@ -24,6 +24,7 @@ import java.util.Set;
 import java.util.function.Consumer;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -33,15 +34,17 @@ public class ProjectLifeCycleListenersImpl implements ProjectLifeCycleListeners
   private final ProjectLifeCycleListener[] listeners;
 
   /**
-   * Used by Pico when there is no ProjectLifeCycleListener implementation in container.
+   * Used by the container when there is no ProjectLifeCycleListener implementation in container.
    */
+  @Autowired(required = false)
   public ProjectLifeCycleListenersImpl() {
     this.listeners = new ProjectLifeCycleListener[0];
   }
 
   /**
-   * Used by Pico when there is at least one ProjectLifeCycleListener implementation in container.
+   * Used by the container when there is at least one ProjectLifeCycleListener implementation in container.
    */
+  @Autowired(required = false)
   public ProjectLifeCycleListenersImpl(ProjectLifeCycleListener[] listeners) {
     this.listeners = listeners;
   }
index b08dadf5ea1648a40c914875cd3b756739e8d2ed..543a446e9359d238b9f3b2fb4310f44d211fdc69 100644 (file)
@@ -24,6 +24,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import javax.annotation.Nullable;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.rules.RuleType;
 import org.sonar.api.utils.log.Logger;
@@ -37,7 +38,7 @@ import static org.sonar.core.util.stream.MoreCollectors.toSet;
 
 /**
  * Broadcast a given collection of {@link QGChangeEvent} for a specific trigger to all the registered
- * {@link QGChangeEventListener} in Pico.
+ * {@link QGChangeEventListener} in the ioc container.
  *
  * This class ensures that an {@link Exception} occurring calling one of the {@link QGChangeEventListener} doesn't
  * prevent from calling the others.
@@ -47,15 +48,8 @@ public class QGChangeEventListenersImpl implements QGChangeEventListeners {
 
   private final QGChangeEventListener[] listeners;
 
-  /**
-   * Used by Pico when there is no QGChangeEventListener instance in container.
-   */
-  public QGChangeEventListenersImpl() {
-    this.listeners = new QGChangeEventListener[0];
-  }
-
-  public QGChangeEventListenersImpl(QGChangeEventListener[] listeners) {
-    this.listeners = listeners;
+  public QGChangeEventListenersImpl(@Nullable QGChangeEventListener[] listeners) {
+    this.listeners = listeners != null ? listeners : new QGChangeEventListener[0];
   }
 
   @Override
index 01c7a51a57fe5e276bb941ee990b71d7e9b3d4c3..41aaef46e0153940a1e1c80b974bf106cde6be2f 100644 (file)
@@ -23,16 +23,19 @@ import com.google.common.annotations.VisibleForTesting;
 import org.sonar.api.config.GlobalPropertyChangeHandler;
 
 import javax.annotation.Nullable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class SettingsChangeNotifier {
 
   @VisibleForTesting
   GlobalPropertyChangeHandler[] changeHandlers;
 
+  @Autowired(required = false)
   public SettingsChangeNotifier(GlobalPropertyChangeHandler[] changeHandlers) {
     this.changeHandlers = changeHandlers;
   }
 
+  @Autowired(required = false)
   public SettingsChangeNotifier() {
     this(new GlobalPropertyChangeHandler[0]);
   }
index 61c37f59fb40be1f7433b5f0635211f23e3f9a15..650ca6373a68294968b0e4c61b78308077b53c71 100644 (file)
@@ -31,7 +31,7 @@ public class BranchFeatureProxyImplTest {
 
   @Test
   public void return_false_when_no_extension() {
-    assertThat(new BranchFeatureProxyImpl().isEnabled()).isFalse();
+    assertThat(new BranchFeatureProxyImpl(null).isEnabled()).isFalse();
   }
 
   @Test
index ecbf74b275acf4ed052d6484af95a2eb0793a800..01fdf0140ab6b0eb3189a70da69ffbd6fbadaea4 100644 (file)
@@ -167,7 +167,7 @@ public class QGChangeEventListenersImplTest {
 
   @Test
   public void broadcastOnIssueChange_has_no_effect_when_no_listener() {
-    QGChangeEventListenersImpl underTest = new QGChangeEventListenersImpl();
+    QGChangeEventListenersImpl underTest = new QGChangeEventListenersImpl(null);
 
     underTest.broadcastOnIssueChange(oneIssueOnComponent1, singletonList(component1QGChangeEvent));
 
index d5a3a16963e66b6e89c270191e11ec19d76a1e11..a877b82a07799e589619bc3d34ad6262bdc61e06 100644 (file)
 package org.sonar.server.util;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class TypeValidationModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new TypeValidationModule().configure(container);
-    assertThat(container.size()).isEqualTo(11);
+    assertThat(container.getAddedObjects()).hasSize(9);
   }
 }
index ed4788ddc37bf377daaca780953c7c9148dc3682..bc5bef18587d06d904b92c860b6dd5229db4e4fd 100644 (file)
  */
 package org.sonar.server.authentication;
 
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Ordering;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
-import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import org.sonar.api.server.authentication.IdentityProvider;
 
 public class IdentityProviderRepository {
+  private static final Predicate<IdentityProvider> IS_ENABLED_FILTER = IdentityProvider::isEnabled;
+  private static final Function<IdentityProvider, String> TO_NAME = IdentityProvider::getName;
 
   protected final Map<String, IdentityProvider> providersByKey = new HashMap<>();
 
-  public IdentityProviderRepository(List<IdentityProvider> identityProviders) {
-    this.providersByKey.putAll(FluentIterable.from(identityProviders).uniqueIndex(ToKey.INSTANCE));
-  }
-
-  /**
-   * Used by pico when no identity provider available
-   */
-  public IdentityProviderRepository() {
-      // nothing to do
+  public IdentityProviderRepository(@Nullable List<IdentityProvider> identityProviders) {
+    Optional.ofNullable(identityProviders)
+      .ifPresent(list -> list.forEach(i -> providersByKey.put(i.getKey(), i)));
   }
 
   public IdentityProvider getEnabledByKey(String key) {
     IdentityProvider identityProvider = providersByKey.get(key);
-    if (identityProvider != null && IsEnabledFilter.INSTANCE.apply(identityProvider)) {
+    if (identityProvider != null && IS_ENABLED_FILTER.test(identityProvider)) {
       return identityProvider;
     }
     throw new IllegalArgumentException(String.format("Identity provider %s does not exist or is not enabled", key));
@@ -55,35 +51,9 @@ public class IdentityProviderRepository {
 
   public List<IdentityProvider> getAllEnabledAndSorted() {
     return providersByKey.values().stream()
-      .filter(IsEnabledFilter.INSTANCE)
-      .sorted(Ordering.natural().onResultOf(ToName.INSTANCE))
+      .filter(IS_ENABLED_FILTER)
+      .sorted(Comparator.comparing(TO_NAME))
       .collect(Collectors.toList());
   }
 
-  private enum IsEnabledFilter implements Predicate<IdentityProvider> {
-    INSTANCE;
-
-    @Override
-    public boolean apply(@Nonnull IdentityProvider input) {
-      return input.isEnabled();
-    }
-  }
-
-  private enum ToKey implements Function<IdentityProvider, String> {
-    INSTANCE;
-
-    @Override
-    public String apply(@Nonnull IdentityProvider input) {
-      return input.getKey();
-    }
-  }
-
-  private enum ToName implements Function<IdentityProvider, String> {
-    INSTANCE;
-
-    @Override
-    public String apply(@Nonnull IdentityProvider input) {
-      return input.getName();
-    }
-  }
 }
index ebf56285f5732092c8c187d933096475cdba8f54..6942d6abcef35c7ed9b27417ba57b094e3f72093 100644 (file)
@@ -24,20 +24,23 @@ import org.sonar.api.Startable;
 import org.sonar.api.platform.Server;
 import org.sonar.api.server.authentication.OAuth2IdentityProvider;
 import org.sonar.api.utils.log.Loggers;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class LogOAuthWarning implements Startable {
 
   private final Server server;
   private final OAuth2IdentityProvider[] providers;
 
+  @Autowired(required = false)
   public LogOAuthWarning(Server server, OAuth2IdentityProvider[] providers) {
     this.server = server;
     this.providers = providers;
   }
 
   /**
-   * Used by default by picocontainer when no OAuth2IdentityProvider are present
+   * Used by default by the ioc container when no OAuth2IdentityProvider are present
    */
+  @Autowired(required = false)
   public LogOAuthWarning(Server server) {
     this(server, new OAuth2IdentityProvider[0]);
   }
index 78c9a8761ff854e2b630d190dfdae8aec89da76f..4f7871f594a7a25edf0684aaa1374d39401224cb 100644 (file)
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.user.UserSession;
 import org.sonar.server.user.UserSessionFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class RequestAuthenticatorImpl implements RequestAuthenticator {
 
@@ -36,6 +37,7 @@ public class RequestAuthenticatorImpl implements RequestAuthenticator {
   private final UserSessionFactory userSessionFactory;
   private final List<CustomAuthentication> customAuthentications;
 
+  @Autowired(required = false)
   public RequestAuthenticatorImpl(JwtHttpHandler jwtHttpHandler, BasicAuthentication basicAuthentication, HttpHeadersAuthentication httpHeadersAuthentication,
     UserSessionFactory userSessionFactory, CustomAuthentication[] customAuthentications) {
     this.jwtHttpHandler = jwtHttpHandler;
@@ -45,6 +47,7 @@ public class RequestAuthenticatorImpl implements RequestAuthenticator {
     this.customAuthentications = Arrays.asList(customAuthentications);
   }
 
+  @Autowired(required = false)
   public RequestAuthenticatorImpl(JwtHttpHandler jwtHttpHandler, BasicAuthentication basicAuthentication, HttpHeadersAuthentication httpHeadersAuthentication,
     UserSessionFactory userSessionFactory) {
     this(jwtHttpHandler, basicAuthentication, httpHeadersAuthentication, userSessionFactory, new CustomAuthentication[0]);
index 9fd9aee4c463a9eaa0ffa384632fc6f262657071..c6cbc705e3f5c4ec54d84d3bc72f85cf7c9429ae 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.user;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.platform.NewUserHandler;
 import org.sonar.api.utils.log.Loggers;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * @since 3.2
@@ -29,12 +30,14 @@ import org.sonar.api.utils.log.Loggers;
 @ServerSide
 public class NewUserNotifier {
 
-  private NewUserHandler[] handlers;
+  private final NewUserHandler[] handlers;
 
+  @Autowired(required = false)
   public NewUserNotifier(NewUserHandler[] handlers) {
     this.handlers = handlers;
   }
 
+  @Autowired(required = false)
   public NewUserNotifier() {
     this(new NewUserHandler[0]);
   }
index 650423f4c79b2d76d09278869d82384089604b3f..1330478d0f31963fa161e1164dd36f069c2206ab 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.user;
 
 import javax.annotation.Nullable;
 import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.security.LoginPasswordAuthenticator;
@@ -33,6 +33,7 @@ import org.sonar.api.utils.log.Loggers;
 
 import static org.sonar.process.ProcessProperties.Property.SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE;
 import static org.sonar.process.ProcessProperties.Property.SONAR_SECURITY_REALM;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * @since 2.14
@@ -43,6 +44,7 @@ public class SecurityRealmFactory implements Startable {
   private final boolean ignoreStartupFailure;
   private final SecurityRealm realm;
 
+  @Autowired(required = false)
   public SecurityRealmFactory(Configuration config, SecurityRealm[] realms, LoginPasswordAuthenticator[] authenticators) {
     ignoreStartupFailure = config.getBoolean(SONAR_AUTHENTICATOR_IGNORE_STARTUP_FAILURE.getKey()).orElse(false);
     String realmName = config.get(SONAR_SECURITY_REALM.getKey()).orElse(null);
@@ -66,14 +68,17 @@ public class SecurityRealmFactory implements Startable {
     realm = selectedRealm;
   }
 
+  @Autowired(required = false)
   public SecurityRealmFactory(Configuration config, LoginPasswordAuthenticator[] authenticators) {
     this(config, new SecurityRealm[0], authenticators);
   }
 
+  @Autowired(required = false)
   public SecurityRealmFactory(Configuration config, SecurityRealm[] realms) {
     this(config, realms, new LoginPasswordAuthenticator[0]);
   }
 
+  @Autowired(required = false)
   public SecurityRealmFactory(Configuration config) {
     this(config, new SecurityRealm[0], new LoginPasswordAuthenticator[0]);
   }
index 33838f06444bb08fd4c2515cff8c31566d55fb51..d8d9fca10f380bbc0d35df14e8d910c01d075224 100644 (file)
@@ -29,6 +29,7 @@ import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 import javax.annotation.Nullable;
+import javax.inject.Inject;
 import org.apache.commons.lang.math.RandomUtils;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.platform.NewUserHandler;
@@ -78,20 +79,9 @@ public class UserUpdater {
   private final DefaultGroupFinder defaultGroupFinder;
   private final Configuration config;
   private final AuditPersister auditPersister;
-
   private final CredentialsLocalAuthentication localAuthentication;
 
-  public UserUpdater(NewUserNotifier newUserNotifier, DbClient dbClient, UserIndexer userIndexer, DefaultGroupFinder defaultGroupFinder, Configuration config,
-    CredentialsLocalAuthentication localAuthentication) {
-    this.newUserNotifier = newUserNotifier;
-    this.dbClient = dbClient;
-    this.userIndexer = userIndexer;
-    this.defaultGroupFinder = defaultGroupFinder;
-    this.config = config;
-    this.auditPersister = null;
-    this.localAuthentication = localAuthentication;
-  }
-
+  @Inject
   public UserUpdater(NewUserNotifier newUserNotifier, DbClient dbClient, UserIndexer userIndexer, DefaultGroupFinder defaultGroupFinder, Configuration config,
     AuditPersister auditPersister, CredentialsLocalAuthentication localAuthentication) {
     this.newUserNotifier = newUserNotifier;
@@ -265,9 +255,7 @@ public class UserUpdater {
     if (updateUser.isPasswordChanged() && validatePasswords(password, messages) && checkPasswordChangeAllowed(userDto, messages)) {
       localAuthentication.storeHashPassword(userDto, password);
       userDto.setResetPassword(false);
-      if (auditPersister != null) {
-        auditPersister.updateUserPassword(dbSession, new SecretNewValue("userLogin", userDto.getLogin()));
-      }
+      auditPersister.updateUserPassword(dbSession, new SecretNewValue("userLogin", userDto.getLogin()));
       return true;
     }
     return false;
index 77b133e1e09da78851226d7e09132a41530d6aff..7c2e2b5370ad11beabffbf7acd8d3f0fc83d134d 100644 (file)
 package org.sonar.server.authentication;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class AuthenticationModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new AuthenticationModule().configure(container);
-    assertThat(container.size()).isGreaterThan(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER);
+    assertThat(container.getAddedObjects()).isNotEmpty();
   }
-
 }
index ec689859ada56ed890eb1ad5ec5d44eff0afa7ea..442a911ddc480299a07bacaa6fb4674528ba6aee 100644 (file)
@@ -62,6 +62,15 @@ public class IdentityProviderRepositoryTest {
       .hasMessage("Identity provider disabled does not exist or is not enabled");
   }
 
+  @Test
+  public void fail_on_non_exist_provider() {
+    IdentityProviderRepository underTest = new IdentityProviderRepository(asList(GITHUB, BITBUCKET, DISABLED));
+
+    assertThatThrownBy(() -> underTest.getEnabledByKey("NotExist"))
+      .isInstanceOf(IllegalArgumentException.class)
+      .hasMessage("Identity provider NotExist does not exist or is not enabled");
+  }
+
   @Test
   public void return_all_enabled_providers() {
     IdentityProviderRepository underTest = new IdentityProviderRepository(asList(GITHUB, BITBUCKET, DISABLED));
@@ -80,7 +89,7 @@ public class IdentityProviderRepositoryTest {
 
   @Test
   public void return_nothing_when_no_identity_provider() {
-    IdentityProviderRepository underTest = new IdentityProviderRepository();
+    IdentityProviderRepository underTest = new IdentityProviderRepository(null);
 
     assertThat(underTest.getAllEnabledAndSorted()).isEmpty();
   }
index 77e8d741e52c44af6098fc7d58e6913182b720a8..563e316ab5c41defe1bd43ca4e84840e2e4fce99 100644 (file)
 package org.sonar.server.usertoken;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class UserTokenModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new UserTokenModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
+    assertThat(container.getAddedObjects()).hasSize(2);
   }
 }
index 16cdbeb333f6225891161a9bf2ea6364dbc60c04..840a099e613eaf259f2212545d915a7f760ad9d2 100644 (file)
@@ -26,6 +26,10 @@ import org.sonar.api.server.authentication.IdentityProvider;
 
 public class IdentityProviderRepositoryRule extends IdentityProviderRepository implements TestRule {
 
+  public IdentityProviderRepositoryRule() {
+    super(null);
+  }
+
   public IdentityProviderRepositoryRule addIdentityProvider(IdentityProvider identityProvider) {
     providersByKey.put(identityProvider.getKey(), identityProvider);
     return this;
index 9aba24d6f0c8a631af4217117d76584174d9a563..3c76f65098ef31d370ed69395528c11037ae50e6 100644 (file)
@@ -29,7 +29,6 @@ dependencies {
   compile 'org.apache.logging.log4j:log4j-api'
   compile 'org.apache.tomcat.embed:tomcat-embed-core'
   compile 'org.apache.commons:commons-dbcp2'
-  compile 'org.picocontainer:picocontainer'
   compile 'org.slf4j:jul-to-slf4j'
   compile 'org.slf4j:slf4j-api'
   compile 'org.sonarsource.update-center:sonar-update-center-common'
index 31311378be9c3d5570c766e032e160cf1cd2512b..7e5e9f2aadbcb738cee5bfb9282c74b4ed6190e0 100644 (file)
@@ -24,7 +24,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.Properties;
 import org.sonar.api.Property;
 import org.sonar.api.config.Configuration;
index 98731483b89bf3d0f538e725bed4bd59cfc09854..25a8e4c1ce005732bc51a738815498738c347552 100644 (file)
  */
 package org.sonar.server.platform;
 
-import javax.annotation.Nullable;
 import org.sonar.api.Startable;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.MessageException;
 
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+
 @ServerSide
 public class ClusterVerification implements Startable {
 
@@ -31,6 +33,7 @@ public class ClusterVerification implements Startable {
   @Nullable
   private final ClusterFeature feature;
 
+  @Inject
   public ClusterVerification(WebServer server, @Nullable ClusterFeature feature) {
     this.server = server;
     this.feature = feature;
index 060c8fee4ffc262ccbbc0060ec0e8b078cb61e75..350358dee545f97d9c46e9a84167f1701cf2856a 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.platform;
 
 import java.util.Optional;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.log.Logger;
index 432e55dc6945549f41c90b123b55d292e585f3d8..10755afccaa48c072563c277f49cd00ad08447c6 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.platform;
 import java.util.Optional;
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.platform.ServerUpgradeStatus;
 import org.sonar.process.ProcessProperties;
index b25aa42ea1fcc8e2cbae2d7421f01c87a5c79441..50140f61be24aeda04b7588db509e77dd37216ab 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.platform.db;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.platform.ServerUpgradeStatus;
 import org.sonar.server.platform.db.migration.charset.DatabaseCharsetChecker;
 
index a31e30d8493cf3f4b7039e92f9fa023298799af0..f53945274ed4f046475f7b4cd930f988a11ec8da 100644 (file)
@@ -25,7 +25,7 @@ import java.sql.DriverManager;
 import java.sql.SQLException;
 import org.h2.Driver;
 import org.h2.tools.Server;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.Logger;
index 255c5b744f4264f48d7c5d2ea7285afc808552dd..f052b57ad70e66c544fd5f8890568636d9aed7e6 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.platform.db;
 
 import com.google.common.annotations.VisibleForTesting;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.System2;
 
index 4c68c16faf9e8adf45c3806f555fd41466c8ec10..140f4f297b78902ccae9a21a1079860e92b6d1d6 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.platform.db.migration;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.server.platform.DefaultServerUpgradeStatus;
 import org.sonar.server.platform.db.migration.engine.MigrationEngine;
index ad2ee0118005831c801277b34dc89fdef8d5cba3..b5afeaff0e256aeb9e1bc4357f55444054032179 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.platform.monitoring;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.process.Jmx;
 import org.sonar.process.systeminfo.SystemInfoSection;
 
index 87052b55224e905e03299753e8f144f236113f0c..86ecd60809583d6e9b03561f97b27945feab3550 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.platform.serverid;
 
 import java.util.Optional;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.SonarQubeSide;
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.utils.log.Logger;
index c4373e7ad6ec0820ce32a1441c00edcba475c9ab..0bf0a72adf16ef3a87103dd561e79a589d3f6ae8 100644 (file)
@@ -25,7 +25,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
index a5c63e36b706f27e510c81e9b5c74f9c7ede4079..5309cbb697fce61af596b99798f324e98191f783 100644 (file)
@@ -37,7 +37,7 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import javax.annotation.Nullable;
 import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.RuleScope;
index 795100eb9212005e12da93e081890dbe95897870..c3571946f3124818f0aa67757c5c0223704ab084 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.rule;
 import org.sonar.api.server.rule.RulesDefinition;
 import org.sonar.api.impl.server.RulesDefinitionContext;
 import org.sonar.server.plugins.ServerPluginRepository;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Loads all instances of {@link RulesDefinition}. Used during server startup
@@ -33,6 +34,7 @@ public class RuleDefinitionsLoader {
   private final RulesDefinition[] pluginDefs;
   private final ServerPluginRepository serverPluginRepository;
 
+  @Autowired(required = false)
   public RuleDefinitionsLoader(CommonRuleDefinitions coreCommonDefs, ServerPluginRepository serverPluginRepository, RulesDefinition[] pluginDefs) {
     this.coreCommonDefs = coreCommonDefs;
     this.serverPluginRepository = serverPluginRepository;
@@ -42,6 +44,7 @@ public class RuleDefinitionsLoader {
   /**
    * Used when no definitions at all.
    */
+  @Autowired(required = false)
   public RuleDefinitionsLoader(CommonRuleDefinitions coreCommonDefs, ServerPluginRepository serverPluginRepository) {
     this(coreCommonDefs, serverPluginRepository, new RulesDefinition[0]);
   }
index 056a68d482fc156714bf0b7589dbb996da171670..96fe41c24b6202577723a64a829c51ee0311c801 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.startup;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.platform.Server;
 import org.sonar.api.utils.log.Loggers;
 
index 6a07999d5c14c7c70b43959125d0adce235d6b55..57122ba35b607e169c8292ad34778efae870a186 100644 (file)
@@ -23,7 +23,7 @@ import com.google.common.annotations.VisibleForTesting;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.measures.Metrics;
@@ -38,6 +38,7 @@ import org.sonar.server.metric.MetricToDto;
 
 import static com.google.common.collect.FluentIterable.concat;
 import static com.google.common.collect.Lists.newArrayList;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class RegisterMetrics implements Startable {
 
@@ -47,6 +48,7 @@ public class RegisterMetrics implements Startable {
   private final UuidFactory uuidFactory;
   private final Metrics[] metricsRepositories;
 
+  @Autowired(required = false)
   public RegisterMetrics(DbClient dbClient, UuidFactory uuidFactory, Metrics[] metricsRepositories) {
     this.dbClient = dbClient;
     this.uuidFactory = uuidFactory;
@@ -56,6 +58,7 @@ public class RegisterMetrics implements Startable {
   /**
    * Used when no plugin is defining Metrics
    */
+  @Autowired(required = false)
   public RegisterMetrics(DbClient dbClient, UuidFactory uuidFactory) {
     this(dbClient, uuidFactory, new Metrics[] {});
   }
index faf8d24af05c7182be1236a47020d75a9baf35a4..8a9732a738e4b108d4986e8f532f01401ac9d1bd 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.startup;
 
 import java.util.Date;
 import java.util.Optional;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.security.DefaultGroups;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.Logger;
index 05b41f6586712008162d2a114ca4877d40574797..fc7c89f216a8facfcab3f7fc11a6565f5d0f8588 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.startup;
 
 import com.google.common.base.Strings;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.utils.log.Loggers;
index 9d2497cc544832864f880260957a670ba66ffd90..414c6de5c36bcf821432c2bde75824cff034a1e1 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.startup;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.SonarEdition;
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.server.ServerSide;
index 89dbeaa01a41c3c64e6d5176ecf40496a725888f..8880b874b73620754332e38940f7319d846b6b12 100644 (file)
@@ -28,7 +28,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.System2;
index ab9ec5daaa623d4b356b99f4723d013a168beddd..8caa743ca169532e55d00a6672274b1fff7fe49a 100644 (file)
@@ -29,6 +29,7 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+import javax.inject.Inject;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.platform.Server;
 import org.sonar.api.server.ServerSide;
@@ -75,11 +76,7 @@ public class TelemetryDataLoaderImpl implements TelemetryDataLoader {
   @CheckForNull
   private final LicenseReader licenseReader;
 
-  public TelemetryDataLoaderImpl(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex,
-    PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration, DockerSupport dockerSupport) {
-    this(server, dbClient, pluginRepository, userIndex, projectMeasuresIndex, editionProvider, internalProperties, configuration, dockerSupport, null);
-  }
-
+  @Inject
   public TelemetryDataLoaderImpl(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex,
     PlatformEditionProvider editionProvider, InternalProperties internalProperties, Configuration configuration,
     DockerSupport dockerSupport, @Nullable LicenseReader licenseReader) {
index 537822c47dbaffe8aaa9051630ba21a7fbcad902..0bfece6f85065e330471f00e150988b91115bca6 100644 (file)
 package org.sonar.server.ce;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class CeModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new CeModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 3);
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
-
-
 }
index dc7bea410564df500575c419cc1267ef8a22e388..680768120e37233a99199496131059e584de0f0e 100644 (file)
 package org.sonar.server.notification;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class NotificationModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new NotificationModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5);
+    assertThat(container.getAddedObjects()).hasSize(5);
   }
 }
index 1d586a9ac43c9fec97a1a69d255e61e5c829678e..21f300bd07be753919cea64f3ac33bfa163e2769 100644 (file)
  */
 package org.sonar.server.platform;
 
-import java.util.Collection;
 import org.junit.Test;
-import org.picocontainer.ComponentAdapter;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class SystemInfoWriterModuleTest {
-  private WebServer webServer = mock(WebServer.class);
-  private SystemInfoWriterModule underTest = new SystemInfoWriterModule(webServer);
+  private final WebServer webServer = mock(WebServer.class);
+  private final SystemInfoWriterModule underTest = new SystemInfoWriterModule(webServer);
 
   @Test
   public void verify_system_info_configuration_in_cluster_mode() {
     when(webServer.isStandalone()).thenReturn(false);
-    ComponentContainer container = new ComponentContainer();
-
+    ListContainer container = new ListContainer();
     underTest.configure(container);
-
-    Collection<ComponentAdapter<?>> adapters = container.getPicoContainer().getComponentAdapters();
-    assertThat(adapters)
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 20);
+    assertThat(container.getAddedObjects()).hasSize(20);
   }
 
   @Test
   public void verify_system_info_configuration_in_standalone_mode() {
     when(webServer.isStandalone()).thenReturn(true);
-    ComponentContainer container = new ComponentContainer();
 
+    ListContainer container = new ListContainer();
     underTest.configure(container);
-
-    Collection<ComponentAdapter<?>> adapters = container.getPicoContainer().getComponentAdapters();
-    assertThat(adapters)
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 14);
+    assertThat(container.getAddedObjects()).hasSize(14);
   }
-
 }
index 58799305fa04ea6a2fa0a588d0a32a3770a15eea..0b4df5dcbf7c2f8359568c70dfa387ad0c429f55 100644 (file)
@@ -32,7 +32,7 @@ import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.extension.CoreExtension;
 import org.sonar.core.extension.CoreExtensionRepository;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -41,10 +41,9 @@ import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideF
 import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter;
 
 public class WebCoreExtensionsInstallerTest {
-  private SonarRuntime sonarRuntime = mock(SonarRuntime.class);
-  private CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class);
-
-  private WebCoreExtensionsInstaller underTest = new WebCoreExtensionsInstaller(sonarRuntime, coreExtensionRepository);
+  private final SonarRuntime sonarRuntime = mock(SonarRuntime.class);
+  private final CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class);
+  private final WebCoreExtensionsInstaller underTest = new WebCoreExtensionsInstaller(sonarRuntime, coreExtensionRepository);
 
   @Test
   public void install_only_adds_ServerSide_annotated_extension_to_container() {
@@ -61,14 +60,10 @@ public class WebCoreExtensionsInstallerTest {
             NoAnnotationClass.class, OtherAnnotationClass.class, MultipleAnnotationClass.class);
         }
       }));
-    ComponentContainer container = new ComponentContainer();
-
+    ListContainer container = new ListContainer();
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
-    assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
-    assertThat(container.getComponentByType(WebServerClass.class)).isNotNull();
-    assertThat(container.getComponentByType(MultipleAnnotationClass.class)).isNotNull();
+    assertThat(container.getAddedObjects()).containsOnly(WebServerClass.class, MultipleAnnotationClass.class);
   }
 
   @ComputeEngineSide
index 394f2c5669d67c118c9f82bc214dacb0a3a8050f..9bf681d74aaafa2de3afba3ae60dd945ca38766d 100644 (file)
 package org.sonar.server.platform.serverid;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class ServerIdModuleTest {
-  private ServerIdModule underTest = new ServerIdModule();
+  private final ServerIdModule underTest = new ServerIdModule();
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     underTest.configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
+    assertThat(container.getAddedObjects()).hasSize(4);
   }
-
 }
index 0036b24f104d7e7f9018dd55819a410955cc0f5a..ba1be304225a89e41e98292c5ff81feaf5e88fbb 100644 (file)
 package org.sonar.server.platform.web.requestid;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class HttpRequestIdModuleTest {
-  private HttpRequestIdModule underTest = new HttpRequestIdModule();
+  private final HttpRequestIdModule underTest = new HttpRequestIdModule();
 
   @Test
   public void count_components_in_module() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     underTest.configure(container);
-
-    assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 3);
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
 }
index f2f6e3a11dd7b7732308bab87967b1f75d066dc1..e2615268469d649013116f6a3d25ceca097b2f92 100644 (file)
 package org.sonar.server.qualitygate;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class ProjectsInWarningModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new ProjectsInWarningModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
+    assertThat(container.getAddedObjects()).hasSize(2);
   }
-
 }
index 0ba187b297152c52aca6ec6161aefd68ea56e173..1d3fac27fe6c9575ee826b0f4e42076443b3cbfc 100644 (file)
@@ -41,7 +41,6 @@ import org.sonar.server.measure.index.ProjectMeasuresIndexer;
 import org.sonar.server.platform.DockerSupport;
 import org.sonar.server.property.InternalProperties;
 import org.sonar.server.property.MapInternalProperties;
-import org.sonar.server.pushapi.sonarlint.SonarLintClientsRegistry;
 import org.sonar.server.user.index.UserIndex;
 import org.sonar.server.user.index.UserIndexer;
 import org.sonar.updatecenter.common.Version;
@@ -86,7 +85,7 @@ public class TelemetryDataLoaderImplTest {
   private final LicenseReader licenseReader = mock(LicenseReader.class);
 
   private final TelemetryDataLoader communityUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
-    new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, internalProperties, configuration, dockerSupport);
+    new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, internalProperties, configuration, dockerSupport, null);
   private final TelemetryDataLoader commercialUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
     new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, internalProperties, configuration, dockerSupport, licenseReader);
 
index 796d2eacd63e50ab0e154bddf02d46cfd79080c3..4f72c5df932ab31eb86e5bb1ca6589f7397dbf35 100644 (file)
 package org.sonar.server.updatecenter;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class UpdateCenterModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new UpdateCenterModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
+    assertThat(container.getAddedObjects()).hasSize(2);
   }
 }
index b458e009c75fd18d4c4d392694b9bb5580951d3e..2948713edcae798158e15e74df2baa838b5a0f38 100644 (file)
@@ -35,7 +35,7 @@ import org.elasticsearch.client.indices.CreateIndexResponse;
 import org.elasticsearch.client.indices.GetIndexRequest;
 import org.elasticsearch.cluster.health.ClusterHealthStatus;
 import org.elasticsearch.common.settings.Settings;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.log.Logger;
index f187218394858b3120002559d9065d1e109d0f03..0715da27abc1fd1fea55dc5d0e9f29e8cae1410b 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.es;
 
 import java.util.HashMap;
 import java.util.Map;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.server.ServerSide;
 import org.sonar.server.es.newindex.BuiltIndex;
index 3b570e90edbff068b2891ee3ed0b896fd6706266..0429f41f0caad48c481ef06f6ee14d7cd8b3885c 100644 (file)
@@ -43,6 +43,7 @@ import org.sonar.server.es.ProjectIndexer;
 
 import static java.util.Collections.emptyList;
 import static org.sonar.core.util.stream.MoreCollectors.toArrayList;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Populates the types "authorization" of each index requiring project
@@ -55,6 +56,7 @@ public class PermissionIndexer implements ProjectIndexer {
   private final Collection<AuthorizationScope> authorizationScopes;
   private final Map<String, IndexType> indexTypeByFormat;
 
+  @Autowired(required = false)
   public PermissionIndexer(DbClient dbClient, EsClient esClient, NeedAuthorizationIndexer... needAuthorizationIndexers) {
     this(dbClient, esClient, Arrays.stream(needAuthorizationIndexers)
       .map(NeedAuthorizationIndexer::getAuthorizationScope)
@@ -62,6 +64,7 @@ public class PermissionIndexer implements ProjectIndexer {
   }
 
   @VisibleForTesting
+  @Autowired(required = false)
   public PermissionIndexer(DbClient dbClient, EsClient esClient, Collection<AuthorizationScope> authorizationScopes) {
     this.dbClient = dbClient;
     this.esClient = esClient;
index 694f2c25b0ce02d39f3245149e320ca39142c32c..78fa109aa90389c0f593504e5b1ef8471908fa6d 100644 (file)
 package org.sonar.server.measure.index;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class ProjectsEsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new ProjectsEsModule().configure(container);
-    assertThat(container.size()).isEqualTo(3 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER);
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
 }
index 7935a8213ec85dff5c7014b04d1fc0f80a4140ce..e3878a6d58f1a5e3cbf28250d2edeaa7d8932826 100644 (file)
@@ -23,7 +23,7 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
index 11f5cfa5d6b71b4f393590b3d212db5da53adde5..9ef3dec04f21ae13c52482b0ee5d8c6b409ef267 100644 (file)
 package org.sonar.server.pushapi;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class ServerPushWsModuleTest {
-
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
-
+    ListContainer container = new ListContainer();
     new ServerPushWsModule().configure(container);
-
-    assertThat(container.size()).isPositive();
+    assertThat(container.getAddedObjects()).isNotEmpty();
   }
 }
 
index 279a84e4082440db93b6cbdcab00fe138b5eca17..26f896856efd8741d54493eb413023c68591048f 100644 (file)
@@ -29,7 +29,7 @@ import org.apache.commons.io.filefilter.FileFilterUtils;
 import org.apache.commons.io.filefilter.HiddenFileFilter;
 import org.apache.commons.lang.CharUtils;
 import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.server.ServerSide;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.platform.ServerFileSystem;
index 3c7e42d954ff577caf8358a89ab3beaa6087b17f..af8e1b3e547005bf15f71781bb0c0f51e062bef1 100644 (file)
@@ -41,13 +41,6 @@ public class BranchSupport {
   @CheckForNull
   private final BranchSupportDelegate delegate;
 
-  /**
-   * Constructor called by Pico when no implementation of {@link BranchSupportDelegate} is available.
-   */
-  public BranchSupport() {
-    this(null);
-  }
-
   public BranchSupport(@Nullable BranchSupportDelegate delegate) {
     this.delegate = delegate;
   }
index 9b2b7a7f2fc04fbe21c47bbc441bc0faff1aef3e..f150d5861548a9429e19992bac34419f05f7a4de 100644 (file)
@@ -20,7 +20,7 @@
 package org.sonar.server.ce.queue;
 
 import java.util.List;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.platform.ServerUpgradeStatus;
 import org.sonar.api.server.ServerSide;
index 356eb1b83e7324a22d7099bd9beb81743c02b1ab..3c0d3ae518550cd87bba71ea40601a69193ee88f 100644 (file)
@@ -20,6 +20,8 @@
 package org.sonar.server.ce.ws;
 
 import javax.annotation.Nullable;
+import javax.inject.Inject;
+
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
@@ -37,6 +39,7 @@ public class WorkerCountAction implements CeWsAction {
   private final UserSession userSession;
   private final WorkerCountProvider workerCountProvider;
 
+  @Inject
   public WorkerCountAction(UserSession userSession, @Nullable WorkerCountProvider workerCountProvider) {
     this.userSession = userSession;
     this.workerCountProvider = workerCountProvider;
index 78237518a571be88e0badf3d68c8303fcc73a3dd..5e3399ab4d19c62123563ef87f34d4588f9f5726 100644 (file)
 package org.sonar.server.duplication.ws;
 
 import com.google.common.annotations.VisibleForTesting;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
+import static java.util.Optional.ofNullable;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
@@ -36,12 +30,20 @@ import org.sonarqube.ws.Duplications;
 import org.sonarqube.ws.Duplications.Block;
 import org.sonarqube.ws.Duplications.ShowResponse;
 
-import static java.util.Optional.ofNullable;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 
 public class ShowResponseBuilder {
 
   private final ComponentDao componentDao;
 
+  @Inject
   public ShowResponseBuilder(DbClient dbClient) {
     this.componentDao = dbClient.componentDao();
   }
index 2fa39a1085c86da89604dddc80450ac542ba875c..96547b3ed53f5443b6074d2db666edad18fae0a8 100644 (file)
@@ -26,6 +26,7 @@ import javax.annotation.Nullable;
 import org.sonar.process.cluster.health.NodeHealth;
 import org.sonar.process.cluster.health.SharedHealthState;
 import org.sonar.server.platform.WebServer;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.ImmutableList.copyOf;
@@ -42,15 +43,17 @@ public class HealthCheckerImpl implements HealthChecker {
   private final SharedHealthState sharedHealthState;
 
   /**
-   * Constructor used by Pico in standalone mode and in safe mode.
+   * Constructor used by the ioc container in standalone mode and in safe mode.
    */
+  @Autowired(required = false)
   public HealthCheckerImpl(WebServer webServer, NodeHealthCheck[] nodeHealthChecks) {
     this(webServer, nodeHealthChecks, new ClusterHealthCheck[0], null);
   }
 
   /**
-   * Constructor used by Pico in cluster mode.
+   * Constructor used by the ioc container in cluster mode.
    */
+  @Autowired(required = false)
   public HealthCheckerImpl(WebServer webServer, NodeHealthCheck[] nodeHealthChecks, ClusterHealthCheck[] clusterHealthChecks,
     @Nullable SharedHealthState sharedHealthState) {
     this.webServer = webServer;
index c23d7e103f9919e6cd565f4476baf0e597ee81cf..a5c8e8e97cd913ca054be07e93c30cb5fd55c413 100644 (file)
@@ -21,20 +21,23 @@ package org.sonar.server.language;
 
 import java.util.Arrays;
 import java.util.stream.Collectors;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.resources.Language;
 import org.sonar.server.plugins.ServerPluginRepository;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class LanguageValidation implements Startable {
 
   private final ServerPluginRepository pluginRepository;
   private final Language[] languages;
 
+  @Autowired(required = false)
   public LanguageValidation(ServerPluginRepository pluginRepository) {
     this.pluginRepository = pluginRepository;
     this.languages = new Language[0];
   }
 
+  @Autowired(required = false)
   public LanguageValidation(ServerPluginRepository pluginRepository, Language... languages) {
     this.pluginRepository = pluginRepository;
     this.languages = languages;
index c98a90460f9fc7f0bcd2221390ac4a9ec91abdc9..70645e46f5a301762a2085ba587552b4b8b8bf84 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.notifications.NotificationChannel;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class NotificationCenter {
 
@@ -35,6 +36,7 @@ public class NotificationCenter {
   private final NotificationDispatcherMetadata[] dispatchersMetadata;
   private final NotificationChannel[] channels;
 
+  @Autowired(required = false)
   public NotificationCenter(NotificationDispatcherMetadata[] metadata, NotificationChannel[] channels) {
     this.dispatchersMetadata = metadata;
     this.channels = channels;
@@ -43,6 +45,7 @@ public class NotificationCenter {
   /**
    * Default constructor when no channels.
    */
+  @Autowired(required = false)
   public NotificationCenter(NotificationDispatcherMetadata[] metadata) {
     this(metadata, new NotificationChannel[0]);
     LOG.warn("There is no notification channel - no notification will be delivered!");
@@ -51,10 +54,12 @@ public class NotificationCenter {
   /**
    * Default constructor when no dispatcher metadata.
    */
+  @Autowired(required = false)
   public NotificationCenter(NotificationChannel[] channels) {
     this(new NotificationDispatcherMetadata[0], channels);
   }
 
+  @Autowired(required = false)
   public NotificationCenter() {
     this(new NotificationDispatcherMetadata[0], new NotificationChannel[0]);
     LOG.warn("There is no notification channel - no notification will be delivered!");
index 37ce04d406295dfc62aeb21ff9cc598e5ed6b8b0..a5f71f548cc4c65c74204f7a9e162db7705246cc 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.platform.ws;
 
+import javax.annotation.Nullable;
 import org.sonar.server.health.CeStatusNodeCheck;
 import org.sonar.server.health.DbConnectionNodeCheck;
 import org.sonar.server.health.EsStatusNodeCheck;
@@ -29,28 +30,18 @@ public class LivenessCheckerImpl implements LivenessChecker {
 
   private final DbConnectionNodeCheck dbConnectionNodeCheck;
   private final CeStatusNodeCheck ceStatusNodeCheck;
+  @Nullable
   private final EsStatusNodeCheck esStatusNodeCheck;
   private final WebServerStatusNodeCheck webServerStatusNodeCheck;
 
   public LivenessCheckerImpl(DbConnectionNodeCheck dbConnectionNodeCheck,
-    WebServerStatusNodeCheck webServerStatusNodeCheck, CeStatusNodeCheck ceStatusNodeCheck, EsStatusNodeCheck esStatusNodeCheck) {
+    WebServerStatusNodeCheck webServerStatusNodeCheck, CeStatusNodeCheck ceStatusNodeCheck, @Nullable EsStatusNodeCheck esStatusNodeCheck) {
     this.dbConnectionNodeCheck = dbConnectionNodeCheck;
     this.webServerStatusNodeCheck = webServerStatusNodeCheck;
     this.ceStatusNodeCheck = ceStatusNodeCheck;
     this.esStatusNodeCheck = esStatusNodeCheck;
   }
 
-  /**
-   * Constructor used by Pico Container on non-standalone mode, so on a DCE App Node, where EsStatusNodeCheck is not available
-   */
-  public LivenessCheckerImpl(DbConnectionNodeCheck dbConnectionNodeCheck,
-    WebServerStatusNodeCheck webServerStatusNodeCheck, CeStatusNodeCheck ceStatusNodeCheck) {
-    this.dbConnectionNodeCheck = dbConnectionNodeCheck;
-    this.webServerStatusNodeCheck = webServerStatusNodeCheck;
-    this.ceStatusNodeCheck = ceStatusNodeCheck;
-    this.esStatusNodeCheck = null;
-  }
-
   public boolean liveness() {
 
     if (!Health.Status.GREEN.equals(dbConnectionNodeCheck.check().getStatus())) {
index 9ec2ae9fde1c2e1a40359779f9bd635a2dd6b197..0b49f5c0908494da014d9d666e4b711df3fe139a 100644 (file)
@@ -25,7 +25,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import javax.annotation.CheckForNull;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
index 6659c0e7c804603c11fdf4223dc3ae026ef3811c..f39c742db22592105a9e5eb2801a0eb8d0db2434 100644 (file)
@@ -55,6 +55,7 @@ import org.sonar.db.qualityprofile.QProfileDto;
 import org.sonar.db.rule.RuleDefinitionDto;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static org.sonar.server.exceptions.BadRequestException.checkRequest;
 
@@ -67,6 +68,7 @@ public class QProfileExporters {
   private final ProfileExporter[] exporters;
   private final ProfileImporter[] importers;
 
+  @Autowired(required = false)
   public QProfileExporters(DbClient dbClient, RuleFinder ruleFinder, QProfileRules qProfileRules, ProfileExporter[] exporters, ProfileImporter[] importers) {
     this.dbClient = dbClient;
     this.ruleFinder = ruleFinder;
@@ -76,22 +78,25 @@ public class QProfileExporters {
   }
 
   /**
-   * Used by Pico if no {@link ProfileImporter} is found
+   * Used by the ioc container if no {@link ProfileImporter} is found
    */
+  @Autowired(required = false)
   public QProfileExporters(DbClient dbClient, RuleFinder ruleFinder, QProfileRules qProfileRules, ProfileExporter[] exporters) {
     this(dbClient, ruleFinder, qProfileRules, exporters, new ProfileImporter[0]);
   }
 
   /**
-   * Used by Pico if no {@link ProfileExporter} is found
+   * Used by the ioc container if no {@link ProfileExporter} is found
    */
+  @Autowired(required = false)
   public QProfileExporters(DbClient dbClient, RuleFinder ruleFinder, QProfileRules qProfileRules, ProfileImporter[] importers) {
     this(dbClient, ruleFinder, qProfileRules, new ProfileExporter[0], importers);
   }
 
   /**
-   * Used by Pico if no {@link ProfileImporter} nor {@link ProfileExporter} is found
+   * Used by the ioc container if no {@link ProfileImporter} nor {@link ProfileExporter} is found
    */
+  @Autowired(required = false)
   public QProfileExporters(DbClient dbClient, RuleFinder ruleFinder, QProfileRules qProfileRules) {
     this(dbClient, ruleFinder, qProfileRules, new ProfileExporter[0], new ProfileImporter[0]);
   }
index 8cc4762bd4ae4f3bf7528c4ef084f55fb779f922..7fbf4110563e90103ac472f022731ec7e18c0c9e 100644 (file)
@@ -27,7 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.Logger;
index f6d1215c066cfef59450307538eb135bbe802060..2e5aee0b85b2736dbe3cd65e56d53cc5a0e98385 100644 (file)
@@ -19,7 +19,7 @@
  */
 package org.sonar.server.qualityprofile.builtin;
 
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 
 /**
  * Startable added to {@link org.sonar.server.platform.platformlevel.PlatformLevelStartup} responsible for initializing
index 0da3b2531aba7c328e9c0a42c1a11b3f2f1a46a6..6573c0eec58617d0ddf0d1fc0d604c5fe4257d32 100644 (file)
@@ -47,6 +47,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.rule.DeprecatedRuleKeyDto;
 import org.sonar.db.rule.RuleDefinitionDto;
 import org.sonar.server.rule.ServerRuleFinder;
+import org.springframework.beans.factory.annotation.Autowired;
 
 import static com.google.common.base.Preconditions.checkState;
 
@@ -61,12 +62,14 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository
   private List<BuiltInQProfile> qProfiles;
 
   /**
-   * Requires for pico container when no {@link BuiltInQualityProfilesDefinition} is defined at all
+   * Used by the ioc container when no {@link BuiltInQualityProfilesDefinition} is defined at all
    */
+  @Autowired(required = false)
   public BuiltInQProfileRepositoryImpl(DbClient dbClient, ServerRuleFinder ruleFinder, Languages languages) {
     this(dbClient, ruleFinder, languages, new BuiltInQualityProfilesDefinition[0]);
   }
 
+  @Autowired(required = false)
   public BuiltInQProfileRepositoryImpl(DbClient dbClient, ServerRuleFinder ruleFinder, Languages languages, BuiltInQualityProfilesDefinition... definitions) {
     this.dbClient = dbClient;
     this.ruleFinder = ruleFinder;
index 16f1be265bbadd96b57f3f702b4bcc8ec28c1aad..74ce65995c977dcf50d2a7a324750d1576b41d41 100644 (file)
@@ -45,6 +45,7 @@ import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_CREATE;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_NAME;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class CreateAction implements QProfileWsAction {
 
@@ -59,6 +60,7 @@ public class CreateAction implements QProfileWsAction {
   private final UserSession userSession;
   private final ActiveRuleIndexer activeRuleIndexer;
 
+  @Autowired(required = false)
   public CreateAction(DbClient dbClient, QProfileFactory profileFactory, QProfileExporters exporters, Languages languages,
     UserSession userSession, ActiveRuleIndexer activeRuleIndexer, ProfileImporter... importers) {
     this.dbClient = dbClient;
@@ -70,6 +72,7 @@ public class CreateAction implements QProfileWsAction {
     this.importers = importers;
   }
 
+  @Autowired(required = false)
   public CreateAction(DbClient dbClient, QProfileFactory profileFactory, QProfileExporters exporters, Languages languages,
     UserSession userSession, ActiveRuleIndexer activeRuleIndexer) {
     this(dbClient, profileFactory, exporters, languages, userSession, activeRuleIndexer, new ProfileImporter[0]);
index 1ae2f73ee756ccb397a247aca84d2533a27a4f8a..dfc2517793847c326326d3f6782955cce995d478 100644 (file)
@@ -24,18 +24,21 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService.NewController;
 import org.sonar.api.utils.text.JsonWriter;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class ExportersAction implements QProfileWsAction {
 
-  private ProfileExporter[] exporters;
+  private final ProfileExporter[] exporters;
 
+  @Autowired(required = false)
   public ExportersAction(ProfileExporter[] exporters) {
     this.exporters = exporters;
   }
 
   /**
-   * Used by Pico if no {@link ProfileExporter} is found
+   * Used by the container if no {@link ProfileExporter} is found
    */
+  @Autowired(required = false)
   public ExportersAction() {
     this(new ProfileExporter[0]);
   }
index 8b8a6ae0e1b48447a611bd9c62a6797e9edd8dab..64d42824f0f363d2e2b7e44f08573de6600ed686 100644 (file)
@@ -24,15 +24,18 @@ import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.text.JsonWriter;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class ImportersAction implements QProfileWsAction {
 
   private final ProfileImporter[] importers;
 
+  @Autowired(required = false)
   public ImportersAction(ProfileImporter[] importers) {
     this.importers = importers;
   }
 
+  @Autowired(required = false)
   public ImportersAction() {
     this(new ProfileImporter[0]);
   }
index 24ab5b7876d79180c4f946ab4ef1903298ff3670..9e96c69f2171f44ee90eece53e473fac3c6337ac 100644 (file)
@@ -43,6 +43,7 @@ import static java.util.Objects.requireNonNull;
 import static org.sonar.api.web.page.Page.Scope.COMPONENT;
 import static org.sonar.api.web.page.Page.Scope.GLOBAL;
 import static org.sonar.core.util.stream.MoreCollectors.toList;
+import org.springframework.beans.factory.annotation.Autowired;
 
 @ServerSide
 public class PageRepository implements Startable {
@@ -53,8 +54,9 @@ public class PageRepository implements Startable {
   private List<Page> pages;
 
   /**
-   * Used by Pico when there is no {@link PageDefinition}.
+   * Used by the ioc container when there is no {@link PageDefinition}.
    */
+  @Autowired(required = false)
   public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository) {
     this.pluginRepository = pluginRepository;
     this.coreExtensionRepository = coreExtensionRepository;
@@ -64,10 +66,10 @@ public class PageRepository implements Startable {
   }
 
   /**
-   * Used by Pico when there is only {@link PageDefinition} provided both by Plugin(s).
+   * Used by the ioc container when there is only {@link PageDefinition} provided both by Plugin(s).
    */
-  public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository,
-    PageDefinition[] pageDefinitions) {
+  @Autowired(required = false)
+  public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository, PageDefinition[] pageDefinitions) {
     this.pluginRepository = pluginRepository;
     this.coreExtensionRepository = coreExtensionRepository;
     this.definitions = copyOf(pageDefinitions);
@@ -75,10 +77,10 @@ public class PageRepository implements Startable {
   }
 
   /**
-   * Used by Pico when there is only {@link PageDefinition} provided both by Core Extension(s).
+   * Used by the ioc container when there is only {@link PageDefinition} provided both by Core Extension(s).
    */
-  public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository,
-    CorePageDefinition[] corePageDefinitions) {
+  @Autowired(required = false)
+  public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository, CorePageDefinition[] corePageDefinitions) {
     this.pluginRepository = pluginRepository;
     this.coreExtensionRepository = coreExtensionRepository;
     this.definitions = emptyList();
@@ -86,8 +88,9 @@ public class PageRepository implements Startable {
   }
 
   /**
-   * Used by Pico when there is {@link PageDefinition} provided both by Core Extension(s) and Plugin(s).
+   * Used by the ioc container when there is {@link PageDefinition} provided both by Core Extension(s) and Plugin(s).
    */
+  @Autowired(required = false)
   public PageRepository(PluginRepository pluginRepository, CoreExtensionRepository coreExtensionRepository,
     PageDefinition[] pageDefinitions, CorePageDefinition[] corePageDefinitions) {
     this.pluginRepository = pluginRepository;
index e7ff70b68eee49cd3d6bf8994259d26aaeb7286b..d2d5b8e9501a31d6c80e7e9b2ea7e05913583da5 100644 (file)
@@ -32,16 +32,16 @@ public class WebAnalyticsLoaderImpl implements WebAnalyticsLoader {
   @Nullable
   private final WebAnalytics analytics;
 
-  public WebAnalyticsLoaderImpl(WebAnalytics[] analytics) {
-    if (analytics.length > 1) {
-      List<String> classes = Arrays.stream(analytics).map(a -> a.getClass().getName()).collect(Collectors.toList());
-      throw MessageException.of("Limited to only one web analytics plugin. Found multiple implementations: " + classes);
+  public WebAnalyticsLoaderImpl(@Nullable WebAnalytics[] analytics) {
+    if (analytics == null) {
+      this.analytics = null;
+    } else {
+      if (analytics.length > 1) {
+        List<String> classes = Arrays.stream(analytics).map(a -> a.getClass().getName()).collect(Collectors.toList());
+        throw MessageException.of("Limited to only one web analytics plugin. Found multiple implementations: " + classes);
+      }
+      this.analytics = analytics.length == 1 ? analytics[0] : null;
     }
-    this.analytics = analytics.length == 1 ? analytics[0] : null;
-  }
-
-  public WebAnalyticsLoaderImpl() {
-    this.analytics = null;
   }
 
   @Override
index 01228d957ac11b56f4e7b882bef66c439d0916dd..363701c2ddd1c42785f47a9179d0ab738d102530 100644 (file)
  */
 package org.sonar.server.user.ws;
 
-import org.sonar.api.config.Configuration;
 import org.sonar.core.platform.Module;
-import org.sonar.process.ProcessProperties;
 
 public class UsersWsModule extends Module {
-  private final Configuration configuration;
-
-  public UsersWsModule(Configuration configuration) {
-    this.configuration = configuration;
-  }
 
   @Override
   protected void configureModule() {
@@ -50,9 +43,5 @@ public class UsersWsModule extends Module {
       SetSettingAction.class,
       UpdateIdentityProviderAction.class);
 
-    if (configuration.getBoolean(ProcessProperties.Property.SONARCLOUD_ENABLED.getKey()).orElse(false)) {
-      // onboarding tutorial is available only in SonarCloud
-      add(SkipOnboardingTutorialAction.class);
-    }
   }
 }
index 39f77901458c402512cc7adb9eac0c90f3d2d131..8f39fff17e1acccaf752a3a789dc5ad17854fd42 100644 (file)
 package org.sonar.server.almintegration.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class AlmIntegrationsWSModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new AlmIntegrationsWSModule().configure(container);
-    assertThat(container.size()).isPositive();
+    assertThat(container.getAddedObjects()).isNotEmpty();
   }
-
 }
index ba25d5b43fec4e9d74fa07478061eed4faa186cc..36a6eca7a9083084d42c75c01730581d28fe19f3 100644 (file)
 package org.sonar.server.almsettings.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class AlmSettingsWsModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new AlmSettingsWsModule().configure(container);
-    assertThat(container.size()).isPositive();
+    assertThat(container.getAddedObjects()).isNotEmpty();
   }
-
 }
index fce5bf4927d52852a238f6f244bca468e9f1c3a5..fbeac758359f9bff1cb3bd967dbce20e9ef83e9b 100644 (file)
 package org.sonar.server.authentication.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class AuthenticationWsModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new AuthenticationWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
+    assertThat(container.getAddedObjects()).hasSize(4);
   }
 }
index e7b70d6095324e9679d6a6fab8252637db55a7d5..c331b750f416d3f711274dd2c1fd328fa9724559 100644 (file)
 package org.sonar.server.badge.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class ProjectBadgesWsModuleTest {
-
-  private final ComponentContainer container = new ComponentContainer();
   private final ProjectBadgesWsModule underTest = new ProjectBadgesWsModule();
 
   @Test
   public void verify_count_of_added_components() {
+    ListContainer container = new ListContainer();
     underTest.configure(container);
-
-    assertThat(container.size()).isPositive();
+    assertThat(container.getAddedObjects()).isNotEmpty();
   }
-
 }
index 7c671b435477247ff2cf9964b1cff308e97ee169..10b9a6d39be2f46a428360230a48fcf0c61a2630 100644 (file)
 package org.sonar.server.batch;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class BatchWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new BatchWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(9);
+    assertThat(container.getAddedObjects()).hasSize(7);
   }
 
 }
index 9f1e37bf7ab5d379f1884c23895927523ef0ff61..5439eaf98ec9643db2b67fc09280f7698d8bc6c3 100644 (file)
 package org.sonar.server.branch.pr.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class PullRequestWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new PullRequestWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 3);
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
 }
index 217146ff626729297a48a5868093c0de721daf1d..57bf8cdb7e04293957f169803b66212414719803 100644 (file)
 package org.sonar.server.branch.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class BranchWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new BranchWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5);
+    assertThat(container.getAddedObjects()).hasSize(5);
   }
 }
index 5e2fd45e13e8cea53728d59e48eae3c7c9b7a583..67b4cecdf88b65647d21bbf6b8cd3edced9dbe84 100644 (file)
@@ -45,7 +45,7 @@ public class BranchSupportTest {
   private static final Map<String, String> NO_CHARACTERISTICS = Collections.emptyMap();
 
   private final BranchSupportDelegate branchSupportDelegate = mock(BranchSupportDelegate.class);
-  private final BranchSupport underTestNoBranch = new BranchSupport();
+  private final BranchSupport underTestNoBranch = new BranchSupport(null);
   private final BranchSupport underTestWithBranch = new BranchSupport(branchSupportDelegate);
 
   @Test
index b73e12e34d6e9ec89d5770515e36644e448e4b0b..937a7072b80f7129a0f6267e8a285157aea9e2cf 100644 (file)
@@ -89,7 +89,7 @@ public class ReportSubmitterTest {
   private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
   private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService,
     new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory());
-  private final BranchSupport ossEditionBranchSupport = new BranchSupport();
+  private final BranchSupport ossEditionBranchSupport = new BranchSupport(null);
 
   private final ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), ossEditionBranchSupport,
     projectDefaultVisibility);
index 2d76e6109da3adc9e056ec8f9bc0a20f0ab42058..93667bf35df1e24534c039415328ea6a8badf7d0 100644 (file)
 package org.sonar.server.ce.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class CeWsModuleTest {
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new CeWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(20 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER);
+    assertThat(container.getAddedObjects()).hasSize(20);
   }
 }
index 969d09fa3b78541fdc5da21ad1114a60d95365a9..88d4fa1d289bf34819b475b5867fa2b19dad5796 100644 (file)
 package org.sonar.server.component.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class ComponentsWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new ComponentsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 7);
+    assertThat(container.getAddedObjects()).hasSize(7);
   }
 }
index 0797027d10f4eb51249d7354563854ad96c6c950..494b0ad06a317c10185356edf55716aaf55d73b6 100644 (file)
 package org.sonar.server.email.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class EmailsWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new EmailsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(2 + 2);
+    assertThat(container.getAddedObjects()).hasSize(2);
   }
 }
index ecc4faee84099d10ae98c6285eabf57105ce13aa..352897cab872a7bb194caf3a5c8cb14528620c9a 100644 (file)
 package org.sonar.server.favorite;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class FavoriteModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new FavoriteModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
+    assertThat(container.getAddedObjects()).hasSize(2);
   }
 }
index 74bb9cd273c30caca3fea6d65d43ac6317a927ef..ddd3842ab4a93023df979dd130277e0214372c20 100644 (file)
 package org.sonar.server.favorite.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class FavoriteWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new FavoriteWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
+    assertThat(container.getAddedObjects()).hasSize(4);
   }
-
-
 }
index ce38df223b8b24782f87ed32865853bc20f71f59..8abcb7e5f48bf02167e342ae2539d7139dde7d9d 100644 (file)
  */
 package org.sonar.server.health;
 
-import java.util.Collection;
 import java.util.Date;
-import java.util.List;
 import java.util.Random;
-import java.util.stream.Collectors;
 import org.junit.Test;
-import org.picocontainer.ComponentAdapter;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.platform.Server;
 import org.sonar.api.utils.System2;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.process.NetworkUtils;
 import org.sonar.process.cluster.health.SharedHealthStateImpl;
 import org.sonar.process.cluster.hz.HazelcastMember;
+import org.sonar.core.platform.ListContainer;
 
 import static java.lang.String.valueOf;
 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
@@ -41,13 +38,13 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 public class NodeHealthModuleTest {
-  private Random random = new Random();
-  private MapSettings mapSettings = new MapSettings();
-  private NodeHealthModule underTest = new NodeHealthModule();
+  private final Random random = new Random();
+  private final MapSettings mapSettings = new MapSettings();
+  private final NodeHealthModule underTest = new NodeHealthModule();
 
   @Test
   public void no_broken_dependencies() {
-    ComponentContainer container = new ComponentContainer();
+    SpringComponentContainer container = new SpringComponentContainer();
     Server server = mock(Server.class);
     NetworkUtils networkUtils = mock(NetworkUtils.class);
     // settings required by NodeHealthProvider
@@ -72,16 +69,10 @@ public class NodeHealthModuleTest {
 
   @Test
   public void provides_implementation_of_SharedHealthState() {
-    ComponentContainer container = new ComponentContainer();
-
+    ListContainer container = new ListContainer();
     underTest.configure(container);
 
-    assertThat(classesAddedToContainer(container))
+    assertThat(container.getAddedObjects())
       .contains(SharedHealthStateImpl.class);
   }
-
-  private List<Class<?>> classesAddedToContainer(ComponentContainer container) {
-    Collection<ComponentAdapter<?>> componentAdapters = container.getPicoContainer().getComponentAdapters();
-    return componentAdapters.stream().map(ComponentAdapter::getComponentImplementation).collect(Collectors.toList());
-  }
 }
index f96a975e844cd986ebbc04bd73ece084d4179e65..40d256ffb7f10a9cd3c056dc562b5f9c181b9e9f 100644 (file)
 package org.sonar.server.hotspot.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class HotspotsWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new HotspotsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 10);
+    assertThat(container.getAddedObjects()).hasSize(10);
   }
-
 }
index c62170db9541ef1aa2535cbd5b8fb56eb1f8c261..764d59008e0fa7395d3a6788f68806a96f5034f8 100644 (file)
 package org.sonar.server.issue.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class IssueWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new IssueWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 31);
+    assertThat(container.getAddedObjects()).hasSize(31);
   }
 }
 
index 0853c3063c4d5f261c6b47d12ec4f6e4386b0e10..b8ec7cc9df37e5dfcf16ef972a4e150489825d5d 100644 (file)
 package org.sonar.server.measure.live;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class LiveMeasureModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new LiveMeasureModule().configure(container);
-    assertThat(container.size()).isEqualTo(3 + 2);
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
-
-
 }
index 246f4c774fec49231aa0e1475fa8bd8aa02564c9..515980abfa3b0f432d1f889536f80edbfbf92bd6 100644 (file)
 package org.sonar.server.measure.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class MeasuresWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new MeasuresWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(5 + 2);
+    assertThat(container.getAddedObjects()).hasSize(5);
   }
 }
index 7d50d15605e37ee0d4fc4cb9c5cdcba727165517..c6866e47aa90d26038499597e2351b2655c0c269 100644 (file)
 package org.sonar.server.metric.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class MetricsWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new MetricsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(5);
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
 }
index cf2e618dae590538dec49ab2a5c88c2a8d6a8afe..8a0c2a692b766cc5dd3e662d49d5eb1b94def3f8 100644 (file)
 package org.sonar.server.monitoring;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class MonitoringWsModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new MonitoringWsModule().configure(container);
-    assertThat(container.size()).isPositive();
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
-
 }
index 256ea0c1d0289d2c00bea6faeb2dfd76d01204e8..f3b31a15f145016e5a986d3722fd5f70c4682cc6 100644 (file)
 package org.sonar.server.newcodeperiod.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class NewCodePeriodsWsModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new NewCodePeriodsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(7);
+    assertThat(container.getAddedObjects()).hasSize(5);
   }
-
 }
index f6b07471c0da323a1726e7e8748317a392a54efc..77eb7627ca0f07d6104862caacc9439c506ff2b8 100644 (file)
 package org.sonar.server.notification.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class NotificationWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new NotificationWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 7);
+    assertThat(container.getAddedObjects()).hasSize(7);
   }
 }
index 7d0f4a7e2647eaa032ee35af726766a343852627..94e48b8443276eaaaeea794a6d4b0107d6349a1a 100644 (file)
 package org.sonar.server.permission.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class PermissionsWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new PermissionsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 26);
+    assertThat(container.getAddedObjects()).hasSize(26);
   }
 }
index 54f420f3892e1beb8dc0ff0d9e09b3245aa02f2b..d3ae5836616b8844b09bf75f3ba70621ec46e2e5 100644 (file)
  */
 package org.sonar.server.platform.ws;
 
-import java.util.Collection;
 import org.junit.Test;
-import org.picocontainer.ComponentAdapter;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 import org.sonar.server.platform.WebServer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class ChangeLogLevelServiceModuleTest {
-  private WebServer webServer = mock(WebServer.class);
-  private ChangeLogLevelServiceModule underTest = new ChangeLogLevelServiceModule(webServer);
+  private final WebServer webServer = mock(WebServer.class);
+  private final ChangeLogLevelServiceModule underTest = new ChangeLogLevelServiceModule(webServer);
 
   @Test
   public void provide_returns_ChangeLogLevelClusterService_if_cluster_not_on_SonarCloud() {
     when(webServer.isStandalone()).thenReturn(false);
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    Collection<ComponentAdapter<?>> adapters = container.getPicoContainer().getComponentAdapters();
-    assertThat(adapters)
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 1)
-      .extracting(ComponentAdapter::getComponentKey)
-      .contains(ChangeLogLevelClusterService.class)
-      .doesNotContain(ChangeLogLevelStandaloneService.class);
+    assertThat(container.getAddedObjects()).containsOnly(ChangeLogLevelClusterService.class);
   }
 
   @Test
   public void provide_returns_ChangeLogLevelStandaloneService_if_SQ_standalone() {
     when(webServer.isStandalone()).thenReturn(true);
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
     verifyInStandaloneSQ(container);
   }
 
-  private void verifyInStandaloneSQ(ComponentContainer container) {
-    Collection<ComponentAdapter<?>> adapters = container.getPicoContainer().getComponentAdapters();
-    assertThat(adapters)
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 1)
-      .extracting(ComponentAdapter::getComponentKey)
-      .contains(ChangeLogLevelStandaloneService.class)
-      .doesNotContain(ChangeLogLevelClusterService.class);
+  private void verifyInStandaloneSQ(ListContainer container) {
+    assertThat(container.getAddedObjects()).containsOnly(ChangeLogLevelStandaloneService.class);
   }
-
 }
index 03597f2305931825bfbe03fc25ee81572448dae6..b91322ca303890808631db6870fa278c7d030ee3 100644 (file)
  */
 package org.sonar.server.platform.ws;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Random;
 import java.util.stream.Collectors;
 import org.junit.Test;
-import org.picocontainer.ComponentAdapter;
-import org.sonar.core.platform.ComponentContainer;
 import org.sonar.server.health.AppNodeClusterCheck;
 import org.sonar.server.health.CeStatusNodeCheck;
 import org.sonar.server.health.ClusterHealthCheck;
@@ -35,6 +32,7 @@ import org.sonar.server.health.EsStatusNodeCheck;
 import org.sonar.server.health.HealthCheckerImpl;
 import org.sonar.server.health.NodeHealthCheck;
 import org.sonar.server.health.WebServerStatusNodeCheck;
+import org.sonar.core.platform.ListContainer;
 import org.sonar.server.platform.WebServer;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -42,18 +40,18 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 public class HealthCheckerModuleTest {
-  private WebServer webServer = mock(WebServer.class);
-  private HealthCheckerModule underTest = new HealthCheckerModule(webServer);
+  private final WebServer webServer = mock(WebServer.class);
+  private final HealthCheckerModule underTest = new HealthCheckerModule(webServer);
 
   @Test
   public void verify_HealthChecker() {
     boolean standalone = new Random().nextBoolean();
     when(webServer.isStandalone()).thenReturn(standalone);
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    assertThat(classesAddedToContainer(container))
+    assertThat(container.getAddedObjects())
       .describedAs("Verifying action and HealthChecker with standalone=%s", standalone)
       .contains(HealthCheckerImpl.class)
       .doesNotContain(HealthActionSupport.class)
@@ -64,62 +62,56 @@ public class HealthCheckerModuleTest {
   @Test
   public void verify_installed_NodeHealthChecks_implementations_when_standalone() {
     when(webServer.isStandalone()).thenReturn(true);
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    List<Class<?>> checks = classesAddedToContainer(container).stream().filter(NodeHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
-    assertThat(checks)
-      .hasSize(4)
-      .contains(WebServerStatusNodeCheck.class)
-      .contains(DbConnectionNodeCheck.class)
-      .contains(EsStatusNodeCheck.class)
-      .contains(CeStatusNodeCheck.class);
+    List<Class<?>> checks = container.getAddedObjects().stream()
+      .filter(o -> o instanceof Class)
+      .map(o -> (Class<?>) o)
+      .filter(NodeHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
+    assertThat(checks).containsOnly(WebServerStatusNodeCheck.class, DbConnectionNodeCheck.class, EsStatusNodeCheck.class, CeStatusNodeCheck.class);
   }
 
   @Test
   public void verify_installed_NodeHealthChecks_implementations_when_clustered() {
     when(webServer.isStandalone()).thenReturn(false);
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    List<Class<?>> checks = classesAddedToContainer(container).stream().filter(NodeHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
-    assertThat(checks)
-      .hasSize(3)
-      .contains(WebServerStatusNodeCheck.class)
-      .contains(DbConnectionNodeCheck.class)
-      .contains(CeStatusNodeCheck.class)
-      .doesNotContain(EsStatusNodeCheck.class);
+    List<Class<?>> checks = container.getAddedObjects().stream()
+      .filter(o -> o instanceof Class)
+      .map(o -> (Class<?>) o)
+      .filter(NodeHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
+    assertThat(checks).containsOnly(WebServerStatusNodeCheck.class, DbConnectionNodeCheck.class, CeStatusNodeCheck.class);
   }
 
   @Test
   public void verify_installed_ClusterHealthChecks_implementations_in_standalone() {
     when(webServer.isStandalone()).thenReturn(true);
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    List<Class<?>> checks = classesAddedToContainer(container).stream().filter(ClusterHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
+    List<Class<?>> checks = container.getAddedObjects().stream()
+      .filter(o -> o instanceof Class<?>)
+      .map(o -> (Class<?>) o)
+      .filter(ClusterHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
     assertThat(checks).isEmpty();
   }
 
   @Test
   public void verify_installed_ClusterHealthChecks_implementations_in_clustering() {
     when(webServer.isStandalone()).thenReturn(false);
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    List<Class<?>> checks = classesAddedToContainer(container).stream().filter(ClusterHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
-    assertThat(checks)
-      .hasSize(2)
-      .contains(EsStatusClusterCheck.class)
-      .contains(AppNodeClusterCheck.class);
-  }
-
-  private List<Class<?>> classesAddedToContainer(ComponentContainer container) {
-    Collection<ComponentAdapter<?>> componentAdapters = container.getPicoContainer().getComponentAdapters();
-    return componentAdapters.stream().map(ComponentAdapter::getComponentImplementation).collect(Collectors.toList());
+    List<Class<?>> checks = container.getAddedObjects().stream()
+      .filter(o -> o instanceof Class<?>)
+      .map(o -> (Class<?>) o)
+      .filter(ClusterHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
+    assertThat(checks).containsOnly(EsStatusClusterCheck.class, AppNodeClusterCheck.class);
   }
 }
index e0c477b910edfadb62c44d30ed55c2b568929816..76d605c6403da7c471a2f4ed66838a8a2d0ff0b3 100644 (file)
@@ -40,7 +40,7 @@ public class LivenessCheckerImplTest {
   private final EsStatusNodeCheck esStatusNodeCheck = mock(EsStatusNodeCheck.class);
 
   LivenessCheckerImpl underTest = new LivenessCheckerImpl(dbConnectionNodeCheck, webServerStatusNodeCheck, ceStatusNodeCheck, esStatusNodeCheck);
-  LivenessCheckerImpl underTestDCE = new LivenessCheckerImpl(dbConnectionNodeCheck, webServerStatusNodeCheck, ceStatusNodeCheck);
+  LivenessCheckerImpl underTestDCE = new LivenessCheckerImpl(dbConnectionNodeCheck, webServerStatusNodeCheck, ceStatusNodeCheck, null);
 
   @Test
   public void fail_when_db_connection_check_fail() {
index 53c887f53224d94111c60d9d61294ae17628d5f1..958def4b4900c4eca67850ea8409eb1b5a668b20 100644 (file)
  */
 package org.sonar.server.platform.ws;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.junit.Test;
-import org.picocontainer.ComponentAdapter;
-import org.sonar.core.platform.ComponentContainer;
 import org.sonar.server.health.DbConnectionNodeCheck;
 import org.sonar.server.health.EsStatusNodeCheck;
 import org.sonar.server.health.HealthCheckerImpl;
 import org.sonar.server.health.NodeHealthCheck;
 import org.sonar.server.health.WebServerSafemodeNodeCheck;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SafeModeHealthCheckerModuleTest {
-  private SafeModeHealthCheckerModule underTest = new SafeModeHealthCheckerModule();
+  private final SafeModeHealthCheckerModule underTest = new SafeModeHealthCheckerModule();
 
   @Test
   public void verify_HealthChecker() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    assertThat(classesAddedToContainer(container))
+    assertThat(container.getAddedObjects())
       .contains(HealthCheckerImpl.class)
       .doesNotContain(HealthActionSupport.class)
       .doesNotContain(SafeModeHealthAction.class)
@@ -51,21 +49,15 @@ public class SafeModeHealthCheckerModuleTest {
 
   @Test
   public void verify_installed_HealthChecks_implementations() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.configure(container);
 
-    List<Class<?>> checks = classesAddedToContainer(container).stream().filter(NodeHealthCheck.class::isAssignableFrom).collect(Collectors.toList());
-    assertThat(checks)
-      .hasSize(3)
-      .contains(WebServerSafemodeNodeCheck.class)
-      .contains(DbConnectionNodeCheck.class)
-      .contains(EsStatusNodeCheck.class);
+    List<Class<?>> checks = container.getAddedObjects().stream()
+      .filter(o -> o instanceof Class)
+      .map(o -> (Class<?>) o)
+      .filter(NodeHealthCheck.class::isAssignableFrom)
+      .collect(Collectors.toList());
+    assertThat(checks).containsOnly(WebServerSafemodeNodeCheck.class, DbConnectionNodeCheck.class, EsStatusNodeCheck.class);
   }
-
-  private List<Class<?>> classesAddedToContainer(ComponentContainer container) {
-    Collection<ComponentAdapter<?>> componentAdapters = container.getPicoContainer().getComponentAdapters();
-    return componentAdapters.stream().map(ComponentAdapter::getComponentImplementation).collect(Collectors.toList());
-  }
-
 }
index f8b5cfaf491cc2db55f7c3e7c795143641508869..6973f35987c004444a34d8b2196cac30633130a3 100644 (file)
 package org.sonar.server.platform.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SafemodeSystemWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new SafemodeSystemWsModule().configure(container);
-    assertThat(container.size()).isPositive();
+    assertThat(container.getAddedObjects()).isNotEmpty();
   }
-
 }
index 4147f7f500a4e4128f9d66c839302d5626cc43d2..f0dfe1e8203fb10a3456477bbef1fc95d6037ea9 100644 (file)
 package org.sonar.server.platform.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class SystemWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new SystemWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 15);
+    assertThat(container.getAddedObjects()).hasSize(15);
   }
-
-
 }
index 861fd500ef549371cd9bebe6e46bfa234e39ffb6..ec6d1c4283bf7bc3c6156dc704ca5bbcc4405c07 100644 (file)
 package org.sonar.server.project.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class ProjectsWsModuleTest {
-
   @Test
   public void verify_count_of_added_components_on_SonarQube() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new ProjectsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 11);
+    assertThat(container.getAddedObjects()).hasSize(11);
   }
-
 }
index 4460d7507de8555ecc04448904a08ff017ad8deb..603b49222b39275533d81a9b3784c76c020b0c29 100644 (file)
 package org.sonar.server.projectanalysis.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class ProjectAnalysisWsModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new ProjectAnalysisWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 8);
+    assertThat(container.getAddedObjects()).hasSize(8);
   }
 }
index aca2e2717db0d4db4ca7b3d42c47a130b777af7a..2cb8b7cabd045bc109cd753d3cb40812092c4a3f 100644 (file)
 package org.sonar.server.projectlink.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class ProjectLinksWsModuleTest {
-
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new ProjectLinksModule().configure(container);
-    assertThat(container.size()).isEqualTo(2 + 4);
+    assertThat(container.getAddedObjects()).hasSize(4);
   }
 }
index 4b48a6d40349a4eae9001dd20d1e8c510e9140b6..85a7ad571939f76221e3b369de5c73534691fac0 100644 (file)
 package org.sonar.server.projecttag.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class ProjectTagsWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new ProjectTagsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
+    assertThat(container.getAddedObjects()).hasSize(4);
   }
 }
index 1b48997c67695acf61e046f927c65b4b1e4ee1da..dc4bb4646716f11127131cce38053bf64ec5c915 100644 (file)
 package org.sonar.server.qualitygate;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class QualityGateModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new QualityGateModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
+    assertThat(container.getAddedObjects()).hasSize(4);
   }
 }
index 15528559678d6096450c49f2ef952c77a50125f8..97f2f9420718c7cc5274795775db44c2d45030d9 100644 (file)
 package org.sonar.server.qualitygate.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class QualityGateWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new QualityGateWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 23);
+    assertThat(container.getAddedObjects()).hasSize(23);
   }
-
 }
index 7b17c5866e5c8cc88cd2f52c189700bbcd05c9e8..d41a7b8b59327c2a499e5c0ded07be9c093891d6 100644 (file)
 package org.sonar.server.qualityprofile.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class QProfilesWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new QProfilesWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(31 + 2);
+    assertThat(container.getAddedObjects()).hasSize(31);
   }
 }
index 474b46e8a24f014bd13b97a32da58e18fb77ce33..4f545125978aff4eb66fd5425a5b3a53f1b73580 100644 (file)
 package org.sonar.server.root.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class RootsWsModuleTest {
   private RootWsModule underTest = new RootWsModule();
 
   @Test
   public void verify_number_of_components_added_by_module() {
-    ComponentContainer container = new ComponentContainer();
-
+    ListContainer container = new ListContainer();
     underTest.configure(container);
-
-    assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
+    assertThat(container.getAddedObjects()).hasSize(4);
   }
 }
index 01aa16a0024847802cee5a4ab81c123a8ee00bd3..ad8181df85a92d963e91ea6af05ad9017ef92030 100644 (file)
 package org.sonar.server.setting.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SettingsWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new SettingsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(11 + 2);
+    assertThat(container.getAddedObjects()).hasSize(11);
   }
 }
index c614cb0de778de2de4c5f4276baa014b2d4f62fd..47bb519dc526eb3306ebcacd97ace1f963f8e37e 100644 (file)
 package org.sonar.server.source.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 import org.sonar.server.ws.WsAction;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SourceWsModuleTest {
-  private SourceWsModule underTest = new SourceWsModule();
+  private final SourceWsModule underTest = new SourceWsModule();
 
   @Test
   public void verify_count_of_actions() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     underTest.configure(container);
-    assertThat(container.getPicoContainer().getComponentAdapters(WsAction.class)).hasSize(6);
+    assertThat(container.getAddedObjects().stream().filter(o -> o instanceof Class && WsAction.class.isAssignableFrom((Class<?>) o)))
+      .hasSize(6);
   }
-
 }
index 449e2a1f9e18a4aaee8f6f61d550a547c8a24e6f..6bd16a7f2a9bf4f6866b33bb534d5928fc4dd881 100644 (file)
@@ -32,7 +32,7 @@ public class WebAnalyticsLoaderImplTest {
 
   @Test
   public void return_empty_if_no_analytics_plugin() {
-    assertThat(new WebAnalyticsLoaderImpl().getUrlPathToJs()).isEmpty();
+    assertThat(new WebAnalyticsLoaderImpl(null).getUrlPathToJs()).isEmpty();
     assertThat(new WebAnalyticsLoaderImpl(new WebAnalytics[0]).getUrlPathToJs()).isEmpty();
   }
 
index 36199d99fa3613f2b570ea454c81f9d5ec9fb976..1a67a8853bb73b342e9f665141e0246b58a0ae19 100644 (file)
 package org.sonar.server.ui.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class NavigationWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new NavigationWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5);
+    assertThat(container.getAddedObjects()).hasSize(5);
   }
 }
index 5c0ffda66aaf5b212266c98135d49bd8758102ff..e9d71f23928407f1e864a93f54d0650bd9df6e63 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Test;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.db.DbTester;
+import org.sonar.db.audit.NoOpAuditPersister;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.authentication.CredentialsLocalAuthentication;
 import org.sonar.server.es.EsTester;
@@ -59,7 +60,7 @@ public class ChangePasswordActionTest {
 
   private final UserUpdater userUpdater = new UserUpdater(mock(NewUserNotifier.class), db.getDbClient(),
     new UserIndexer(db.getDbClient(), es.client()), new DefaultGroupFinder(db.getDbClient()),
-    new MapSettings().asConfig(), null, localAuthentication);
+    new MapSettings().asConfig(), new NoOpAuditPersister(), localAuthentication);
 
   private final WsActionTester tester = new WsActionTester(new ChangePasswordAction(db.getDbClient(), userUpdater, userSessionRule, localAuthentication));
 
index 6f59b700c6e4fde5e5c34e63581525c89d59b3f5..c6d7d852d06d6a8eb5613c9d576e5a71d90082de 100644 (file)
@@ -29,6 +29,7 @@ import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
+import org.sonar.db.audit.NoOpAuditPersister;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.authentication.CredentialsLocalAuthentication;
@@ -77,7 +78,7 @@ public class CreateActionTest {
   private GroupDto defaultGroup;
   private final CredentialsLocalAuthentication localAuthentication = new CredentialsLocalAuthentication(db.getDbClient(), settings.asConfig());
   private final WsActionTester tester = new WsActionTester(new CreateAction(db.getDbClient(), new UserUpdater(mock(NewUserNotifier.class),
-    db.getDbClient(), userIndexer, new DefaultGroupFinder(db.getDbClient()), settings.asConfig(), null, localAuthentication), userSessionRule));
+    db.getDbClient(), userIndexer, new DefaultGroupFinder(db.getDbClient()), settings.asConfig(), new NoOpAuditPersister(), localAuthentication), userSessionRule));
 
   @Before
   public void setUp() {
index 95ae8fe2ce34dd3e09277c55e686964e8f34029f..01687a155daacddfa5a693212e3fabf98fa144ee 100644 (file)
 package org.sonar.server.user.ws;
 
 import org.junit.Test;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.process.ProcessProperties;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class UsersWsModuleTest {
-  private MapSettings settings = new MapSettings();
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
-    new UsersWsModule(new ConfigurationBridge(settings)).configure(container);
-    assertThat(container.size()).isEqualTo(2 + 16);
-  }
-
-  @Test
-  public void verify_count_of_added_components_in_sonarcloud() {
-    settings.setProperty(ProcessProperties.Property.SONARCLOUD_ENABLED.getKey(), true);
-
-    ComponentContainer container = new ComponentContainer();
-    new UsersWsModule(new ConfigurationBridge(settings)).configure(container);
-    assertThat(container.size()).isEqualTo(2 + 17);
+    ListContainer container = new ListContainer();
+    new UsersWsModule().configure(container);
+    assertThat(container.getAddedObjects()).hasSize(16);
   }
 }
index a9431a8509eed0d2d6bacae3a3ef251ba65a1162..e291b07a9a3e0d5e2d14fe0f58f840dc1d01abff 100644 (file)
 package org.sonar.server.usergroups.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class UserGroupsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new UserGroupsModule().configure(container);
-    assertThat(container.size()).isEqualTo(11);
+    assertThat(container.getAddedObjects()).hasSize(9);
   }
 }
index fbd1a3781227966ba6722e211015f39d82d15361..e8c1178d06bd0c228b95c71813db62243ed26f82 100644 (file)
 package org.sonar.server.usertoken.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 import org.sonar.server.usertoken.UserTokenModule;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 public class UserTokenWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new UserTokenModule().configure(container);
-    assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
+    assertThat(container.getAddedObjects()).hasSize(2);
   }
-
-
 }
index cf3547e4717cc48b5b26dfa0f7a39ccffc542667..09965cb0d2364a87a065295997e190bd802f4aee 100644 (file)
 package org.sonar.server.webhook.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class WebhooksWsModuleTest {
-
-  private WebhooksWsModule underTest = new WebhooksWsModule();
+  private final WebhooksWsModule underTest = new WebhooksWsModule();
 
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     underTest.configure(container);
-    assertThat(container.size()).isNotZero();
+    assertThat(container.getAddedObjects()).isNotEmpty();
   }
-
 }
index a293b75bb26b7e2a255f17af3a5f5fbbcb589c8c..2fae90411693e8cc21fa4a7486b573c1b5d1a8b9 100644 (file)
 package org.sonar.server.ws.ws;
 
 import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class WebServicesWsModuleTest {
   @Test
   public void verify_count_of_added_components() {
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     new WebServicesWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(3 + 2);
+    assertThat(container.getAddedObjects()).hasSize(3);
   }
 }
index 79b0e40b56adff169dedb943ec4b0caf32de46fc..aa0bd5ed8d16f28974602122402153668bcc8f36 100644 (file)
@@ -27,7 +27,7 @@ import java.util.Locale;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.apache.catalina.connector.ClientAbortException;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.impl.ws.ValidatingRequest;
 import org.sonar.api.server.ServerSide;
 import org.sonar.api.server.ws.LocalConnector;
index 3a20672967260d93ee2e23bd9a89fdc375200af2..f691b8e942b12fd35a36c429a25d77d13809a703 100644 (file)
  */
 package org.sonar.server.platform;
 
-import com.google.common.collect.Lists;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Properties;
-import java.util.function.Supplier;
 import javax.annotation.Nullable;
 import javax.servlet.ServletContext;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.server.app.ProcessCommandWrapper;
 import org.sonar.server.platform.db.migration.version.DatabaseVersion;
 import org.sonar.server.platform.platformlevel.PlatformLevel;
@@ -49,7 +49,6 @@ public class PlatformImpl implements Platform {
 
   private static final PlatformImpl INSTANCE = new PlatformImpl();
 
-  private final Supplier<AutoStarter> autoStarterSupplier;
   private AutoStarter autoStarter = null;
   private Properties properties;
   private ServletContext servletContext;
@@ -61,20 +60,9 @@ public class PlatformImpl implements Platform {
   private PlatformLevel currentLevel;
   private boolean dbConnected = false;
   private boolean started = false;
-  private final List<Object> level4AddedComponents = Lists.newArrayList();
+  private final List<Object> level4AddedComponents = new ArrayList<>();
   private final Profiler profiler = Profiler.createIfTrace(Loggers.get(PlatformImpl.class));
 
-  private PlatformImpl() {
-    this.autoStarterSupplier = () -> {
-      ProcessCommandWrapper processCommandWrapper = getContainer().getComponentByType(ProcessCommandWrapper.class);
-      return new AsynchronousAutoStarter(processCommandWrapper);
-    };
-  }
-
-  protected PlatformImpl(Supplier<AutoStarter> autoStarterSupplier) {
-    this.autoStarterSupplier = autoStarterSupplier;
-  }
-
   public static PlatformImpl getInstance() {
     return INSTANCE;
   }
@@ -90,13 +78,8 @@ public class PlatformImpl implements Platform {
     }
   }
 
-  // Platform is injected in Pico, so do not rename this method "start"
   @Override
   public void doStart() {
-    doStart(Startup.ALL);
-  }
-
-  protected void doStart(Startup startup) {
     if (started && !isInSafeMode()) {
       return;
     }
@@ -110,7 +93,7 @@ public class PlatformImpl implements Platform {
     if (dbRequiresMigration()) {
       LOGGER.info("Database needs to be migrated. Please refer to https://docs.sonarqube.org/latest/setup/upgrading");
     } else {
-      this.autoStarter = autoStarterSupplier.get();
+      this.autoStarter = createAutoStarter();
       this.autoStarter.execute(new AutoStarterRunnable(autoStarter) {
         @Override
         public void doRun() {
@@ -119,7 +102,7 @@ public class PlatformImpl implements Platform {
           }
           runIfNotAborted(PlatformImpl.this::startLevel34Containers);
 
-          runIfNotAborted(() -> executeStartupTasks(startup));
+          runIfNotAborted(PlatformImpl.this::executeStartupTasks);
           // switch current container last to avoid giving access to a partially initialized container
           runIfNotAborted(() -> {
             currentLevel = level4;
@@ -133,6 +116,11 @@ public class PlatformImpl implements Platform {
     }
   }
 
+  private AutoStarter createAutoStarter() {
+    ProcessCommandWrapper processCommandWrapper = getContainer().getComponentByType(ProcessCommandWrapper.class);
+    return new AsynchronousAutoStarter(processCommandWrapper);
+  }
+
   private boolean dbRequiresMigration() {
     return getDatabaseStatus() != DatabaseVersion.Status.UP_TO_DATE;
   }
@@ -187,18 +175,11 @@ public class PlatformImpl implements Platform {
     level4 = start(new PlatformLevel4(level3, level4AddedComponents));
   }
 
-  public void executeStartupTasks() {
-    executeStartupTasks(Startup.ALL);
-  }
-
-  private void executeStartupTasks(Startup startup) {
-    if (startup.ordinal() >= Startup.ALL.ordinal()) {
-      new PlatformLevelStartup(level4)
-        .configure()
-        .start()
-        .stop()
-        .destroy();
-    }
+  private void executeStartupTasks() {
+    new PlatformLevelStartup(level4)
+      .configure()
+      .start()
+      .stop();
   }
 
   private void startSafeModeContainer() {
@@ -230,7 +211,7 @@ public class PlatformImpl implements Platform {
    * Stops level 2, 3 and 4 containers cleanly if they exists.
    * Call this method before {@link #startLevel1Container()} to avoid duplicate attempt to stop safemode container
    * components (since calling stop on a container calls stop on its children too, see
-   * {@link ComponentContainer#stopComponents()}).
+   * {@link SpringComponentContainer#stopComponents()}).
    */
   private void stopLevel234Containers() {
     if (level2 != null) {
@@ -245,7 +226,7 @@ public class PlatformImpl implements Platform {
    * Stops safemode container cleanly if it exists.
    * Call this method before {@link #stopLevel234Containers()} and {@link #stopLevel1Container()} to avoid duplicate
    * attempt to stop safemode container components (since calling stop on a container calls stops on its children too,
-   * see {@link ComponentContainer#stopComponents()}).
+   * see {@link SpringComponentContainer#stopComponents()}).
    */
   private void stopSafeModeContainer() {
     if (levelSafeMode != null) {
@@ -259,7 +240,6 @@ public class PlatformImpl implements Platform {
     return version.getStatus();
   }
 
-  // Do not rename "stop"
   public void doStop() {
     try {
       stopAutoStarter();
@@ -286,18 +266,10 @@ public class PlatformImpl implements Platform {
   }
 
   @Override
-  public ComponentContainer getContainer() {
+  public ExtensionContainer getContainer() {
     return currentLevel.getContainer();
   }
 
-  public Object getComponent(Object key) {
-    return getContainer().getComponentByKey(key);
-  }
-
-  public enum Startup {
-    NO_STARTUP_TASKS, ALL
-  }
-
   public interface AutoStarter {
     /**
      * Let the autostarted execute the provided code.
index 8165c39056b3d23dd8b1f0c96db82d41bab2e3de..9d8bc2b26c2ac9f0aa4b19c7a6379d3b1df270f9 100644 (file)
 package org.sonar.server.platform.platformlevel;
 
 import java.util.Collection;
-import java.util.List;
 import java.util.Optional;
-import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.core.platform.Module;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.server.platform.WebServer;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -34,25 +31,25 @@ import static java.util.Objects.requireNonNull;
 public abstract class PlatformLevel {
   private final String name;
   @Nullable
-  private final PlatformLevel parent;
-  private final ComponentContainer container;
+  protected final PlatformLevel parent;
+  private final SpringComponentContainer container;
   private AddIfStartupLeader addIfStartupLeader;
   private AddIfCluster addIfCluster;
   private AddIfStandalone addIfStandalone;
 
-  public PlatformLevel(String name) {
+  protected PlatformLevel(String name) {
     this.name = name;
     this.parent = null;
     this.container = createContainer(null);
   }
 
-  public PlatformLevel(String name, @Nonnull PlatformLevel parent) {
+  protected PlatformLevel(String name, PlatformLevel parent) {
     this.name = checkNotNull(name);
     this.parent = checkNotNull(parent);
-    this.container = createContainer(parent.container);
+    this.container = createContainer(parent.getContainer());
   }
 
-  public ComponentContainer getContainer() {
+  public SpringComponentContainer getContainer() {
     return container;
   }
 
@@ -63,21 +60,15 @@ public abstract class PlatformLevel {
   /**
    * Intended to be override by subclasses if needed
    */
-  protected ComponentContainer createContainer(@Nullable ComponentContainer parent) {
+  protected SpringComponentContainer createContainer(@Nullable SpringComponentContainer parent) {
     if (parent == null) {
-      return new ComponentContainer();
+      return new SpringComponentContainer();
     }
     return parent.createChild();
   }
 
   public PlatformLevel configure() {
     configureLevel();
-
-    List<Module> modules = container.getComponentsByType(Module.class);
-    for (Module module : modules) {
-      module.configure(container);
-    }
-
     return this;
   }
 
@@ -88,7 +79,6 @@ public abstract class PlatformLevel {
    */
   public PlatformLevel start() {
     container.startComponents();
-
     return this;
   }
 
@@ -97,36 +87,21 @@ public abstract class PlatformLevel {
    */
   public PlatformLevel stop() {
     container.stopComponents();
-
-    return this;
-  }
-
-  /**
-   * Intended to be override by subclasses if needed
-   */
-  public PlatformLevel destroy() {
-    if (parent != null) {
-      parent.container.removeChild(container);
-    }
     return this;
   }
 
   protected <T> T get(Class<T> tClass) {
-    return requireNonNull(container.getComponentByType(tClass));
-  }
-
-  protected <T> List<T> getAll(Class<T> tClass) {
-    return container.getComponentsByType(tClass);
+    return container.getComponentByType(tClass);
   }
 
   protected <T> Optional<T> getOptional(Class<T> tClass) {
-    return Optional.ofNullable(container.getComponentByType(tClass));
+    return container.getOptionalComponentByType(tClass);
   }
 
   protected void add(Object... objects) {
     for (Object object : objects) {
       if (object != null) {
-        container.addComponent(object, true);
+        container.add(object);
       }
     }
   }
@@ -171,8 +146,10 @@ public abstract class PlatformLevel {
   }
 
   protected WebServer getWebServer() {
-    return getOptional(WebServer.class)
-      .orElseThrow(() -> new IllegalStateException("WebServer not available in Pico yet"));
+    return Optional.ofNullable(parent)
+      .flatMap(p -> p.getOptional(WebServer.class))
+      .or(() -> getOptional(WebServer.class))
+      .orElseThrow(() -> new IllegalStateException("WebServer not available in the container"));
   }
 
   protected abstract class AddIf {
index 2adc88219e2f73fbfc6aa492f71726ab5fbd552b..d576c3d585f1bb09faf9557eeb58ee6146d10c4a 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.platform.platformlevel;
 
 import java.time.Clock;
 import java.util.Properties;
-import javax.annotation.Nullable;
 import org.sonar.api.SonarEdition;
 import org.sonar.api.SonarQubeSide;
 import org.sonar.api.SonarQubeVersion;
@@ -29,13 +28,6 @@ import org.sonar.api.internal.MetadataLoader;
 import org.sonar.api.internal.SonarRuntimeImpl;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.Version;
-import org.sonar.db.audit.AuditPersister;
-import org.sonar.db.audit.NoOpAuditPersister;
-import org.sonar.server.issue.index.IssueIndexSyncProgressChecker;
-import org.sonar.server.platform.DockerSupportImpl;
-import org.sonar.server.util.GlobalLockManagerImpl;
-import org.sonar.server.util.Paths2Impl;
-import org.sonar.server.util.TempFolderCleaner;
 import org.sonar.core.config.CorePropertyDefinitions;
 import org.sonar.core.extension.CoreExtensionRepositoryImpl;
 import org.sonar.core.extension.CoreExtensionsLoader;
@@ -45,6 +37,8 @@ import org.sonar.db.DaoModule;
 import org.sonar.db.DbClient;
 import org.sonar.db.DefaultDatabase;
 import org.sonar.db.MyBatis;
+import org.sonar.db.audit.AuditPersister;
+import org.sonar.db.audit.NoOpAuditPersister;
 import org.sonar.db.purge.PurgeProfiler;
 import org.sonar.process.NetworkUtilsImpl;
 import org.sonar.process.logging.LogbackHelper;
@@ -54,7 +48,9 @@ import org.sonar.server.app.WebServerProcessLogging;
 import org.sonar.server.config.ConfigurationProvider;
 import org.sonar.server.es.EsModule;
 import org.sonar.server.issue.index.IssueIndex;
+import org.sonar.server.issue.index.IssueIndexSyncProgressChecker;
 import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
+import org.sonar.server.platform.DockerSupportImpl;
 import org.sonar.server.platform.LogServerVersion;
 import org.sonar.server.platform.Platform;
 import org.sonar.server.platform.ServerFileSystemImpl;
@@ -67,7 +63,10 @@ import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.setting.ThreadLocalSettings;
 import org.sonar.server.user.SystemPasscodeImpl;
 import org.sonar.server.user.ThreadLocalUserSession;
+import org.sonar.server.util.GlobalLockManagerImpl;
 import org.sonar.server.util.OkHttpClientProvider;
+import org.sonar.server.util.Paths2Impl;
+import org.sonar.server.util.TempFolderCleaner;
 
 import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter;
 import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel;
@@ -75,7 +74,6 @@ import static org.sonar.core.extension.PlatformLevelPredicates.hasPlatformLevel;
 public class PlatformLevel1 extends PlatformLevel {
   private final Platform platform;
   private final Properties properties;
-  @Nullable
   private final Object[] extraRootComponents;
 
   public PlatformLevel1(Platform platform, Properties properties, Object... extraRootComponents) {
@@ -96,7 +94,7 @@ public class PlatformLevel1 extends PlatformLevel {
       new SonarQubeVersion(apiVersion),
       SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SERVER, edition),
       ThreadLocalSettings.class,
-      new ConfigurationProvider(),
+      ConfigurationProvider.class,
       LogServerVersion.class,
       ProcessCommandWrapperImpl.class,
       RestartFlagHolderImpl.class,
@@ -124,11 +122,11 @@ public class PlatformLevel1 extends PlatformLevel {
       // DB
       DBSessionsImpl.class,
       DbClient.class,
-      DaoModule.class,
+      new DaoModule(),
 
       // Elasticsearch
       WebAuthorizationTypeSupport.class,
-      EsModule.class,
+      new EsModule(),
 
       // rules/qprofiles
       RuleIndex.class,
@@ -160,6 +158,7 @@ public class PlatformLevel1 extends PlatformLevel {
 
   @Override
   public PlatformLevel start() {
+    PlatformLevel start = super.start();
     get(CoreExtensionsLoader.class)
       .load();
     get(WebCoreExtensionsInstaller.class)
@@ -168,6 +167,6 @@ public class PlatformLevel1 extends PlatformLevel {
       add(NoOpAuditPersister.class);
     }
 
-    return super.start();
+    return start;
   }
 }
index fb39bd30744fbbf755529609fe7e0a5d6aa93b05..b1dbde2980dceb807ea49c20b498bdf6f29f3617 100644 (file)
@@ -21,9 +21,9 @@ package org.sonar.server.platform.platformlevel;
 
 import org.sonar.api.utils.Durations;
 import org.sonar.core.extension.CoreExtensionsInstaller;
-import org.sonar.core.platform.ComponentContainer;
 import org.sonar.core.platform.PluginClassLoader;
 import org.sonar.core.platform.PluginClassloaderFactory;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.server.es.MigrationEsClientImpl;
 import org.sonar.server.l18n.ServerI18n;
 import org.sonar.server.platform.DatabaseServerCompatibility;
@@ -36,8 +36,6 @@ import org.sonar.server.platform.db.migration.DatabaseMigrationExecutorServiceIm
 import org.sonar.server.platform.db.migration.DatabaseMigrationStateImpl;
 import org.sonar.server.platform.db.migration.MigrationConfigurationModule;
 import org.sonar.server.platform.db.migration.charset.DatabaseCharsetChecker;
-import org.sonar.server.platform.db.migration.history.MigrationHistoryTable;
-import org.sonar.server.platform.db.migration.history.MigrationHistoryTableImpl;
 import org.sonar.server.platform.db.migration.version.DatabaseVersion;
 import org.sonar.server.platform.web.WebPagesCache;
 import org.sonar.server.plugins.InstalledPluginReferentialFactory;
@@ -59,7 +57,7 @@ public class PlatformLevel2 extends PlatformLevel {
   @Override
   protected void configureLevel() {
     add(
-      MigrationConfigurationModule.class,
+      new MigrationConfigurationModule(),
       DatabaseVersion.class,
       DatabaseServerCompatibility.class,
       MigrationEsClientImpl.class,
@@ -90,7 +88,6 @@ public class PlatformLevel2 extends PlatformLevel {
     // Migration state must be kept at level2 to survive moving in and then out of safe mode
     // ExecutorService must be kept at level2 because stopping it when stopping safe mode level causes error making SQ fail
     add(
-      MigrationHistoryTableImpl.class,
       DatabaseMigrationStateImpl.class,
       DatabaseMigrationExecutorServiceImpl.class);
 
@@ -101,11 +98,8 @@ public class PlatformLevel2 extends PlatformLevel {
 
   @Override
   public PlatformLevel start() {
-    // ensuring the HistoryTable exists must be the first thing done when this level is started
-    getOptional(MigrationHistoryTable.class).ifPresent(MigrationHistoryTable::start);
-
-    ComponentContainer container = getContainer();
-    CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class);
+    SpringComponentContainer container = getContainer();
+    CoreExtensionsInstaller coreExtensionsInstaller = parent.get(WebCoreExtensionsInstaller.class);
     coreExtensionsInstaller.install(container, hasPlatformLevel(2), noAdditionalSideFilter());
 
     return super.start();
index 105a2f5597a2b7f5c9bc4d942563d3780f78904e..e4194cd02353840c147d3ba78a6f77e90ac80d46 100644 (file)
@@ -21,7 +21,7 @@ package org.sonar.server.platform.platformlevel;
 
 import org.sonar.api.utils.UriReader;
 import org.sonar.core.extension.CoreExtensionsInstaller;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.core.util.DefaultHttpDownloader;
 import org.sonar.server.async.AsyncExecutionModule;
 import org.sonar.server.platform.ServerImpl;
@@ -48,19 +48,19 @@ public class PlatformLevel3 extends PlatformLevel {
       DetectPluginChange.class);
     add(
       NoopDatabaseMigrationImpl.class,
-      ServerIdModule.class,
+      new ServerIdModule(),
       ServerImpl.class,
       DatabaseSettingLoader.class,
       DatabaseSettingsEnabler.class,
       UriReader.class,
       DefaultHttpDownloader.class,
-      AsyncExecutionModule.class);
+      new AsyncExecutionModule());
   }
 
   @Override
   public PlatformLevel start() {
-    ComponentContainer container = getContainer();
-    CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class);
+    SpringComponentContainer container = getContainer();
+    CoreExtensionsInstaller coreExtensionsInstaller = parent.get(WebCoreExtensionsInstaller.class);
     coreExtensionsInstaller.install(container, hasPlatformLevel(3), noAdditionalSideFilter());
 
     return super.start();
index 9a89c83b8e0b348fe80f57b272e1e29f5b1e6982..25dcbf24c63b585fc8b63444f572ea3002b6660a 100644 (file)
@@ -35,7 +35,6 @@ import org.sonar.alm.client.gitlab.GitlabGlobalSettingsValidator;
 import org.sonar.alm.client.gitlab.GitlabHttpClient;
 import org.sonar.api.profiles.XMLProfileParser;
 import org.sonar.api.profiles.XMLProfileSerializer;
-import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.ResourceTypes;
 import org.sonar.api.rules.AnnotationRuleParser;
 import org.sonar.api.server.rule.RulesDefinitionXmlLoader;
@@ -51,8 +50,9 @@ import org.sonar.ce.task.projectanalysis.taskprocessor.ReportTaskProcessor;
 import org.sonar.ce.task.projectexport.taskprocessor.ProjectExportTaskProcessor;
 import org.sonar.core.component.DefaultResourceTypes;
 import org.sonar.core.extension.CoreExtensionsInstaller;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.language.LanguagesProvider;
 import org.sonar.core.platform.PlatformEditionProvider;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.server.almintegration.ws.AlmIntegrationsWSModule;
 import org.sonar.server.almintegration.ws.CredentialsEncoderHelper;
 import org.sonar.server.almintegration.ws.ImportHelper;
@@ -275,7 +275,7 @@ public class PlatformLevel4 extends PlatformLevel {
       MetadataIndexImpl.class,
       EsDbCompatibilityImpl.class);
 
-    addIfCluster(NodeHealthModule.class);
+    addIfCluster(new NodeHealthModule());
 
     addIfCluster(DistributedRuleActivatorEventsDistributor.class);
     addIfStandalone(StandaloneRuleActivatorEventsDistributor.class);
@@ -293,13 +293,13 @@ public class PlatformLevel4 extends PlatformLevel {
       ServerWs.class,
       IndexDefinitions.class,
       WebAnalyticsLoaderImpl.class,
-      MonitoringWsModule.class,
+      new MonitoringWsModule(),
 
       // batch
-      BatchWsModule.class,
+      new BatchWsModule(),
 
       // update center
-      UpdateCenterModule.class,
+      new UpdateCenterModule(),
 
       // quality profile
       BuiltInQProfileRepositoryImpl.class,
@@ -317,7 +317,7 @@ public class PlatformLevel4 extends PlatformLevel {
       QProfileBackuperImpl.class,
       QProfileParser.class,
       QProfileResetImpl.class,
-      QProfilesWsModule.class,
+      new QProfilesWsModule(),
 
       // rule
       RuleIndexDefinition.class,
@@ -345,24 +345,24 @@ public class PlatformLevel4 extends PlatformLevel {
       org.sonar.server.rule.ws.AppAction.class,
 
       // languages
-      Languages.class,
+      LanguagesProvider.class,
       LanguageWs.class,
       LanguageValidation.class,
       org.sonar.server.language.ws.ListAction.class,
 
       // measure
-      MetricsWsModule.class,
-      MeasuresWsModule.class,
+      new MetricsWsModule(),
+      new MeasuresWsModule(),
       MetricFinder.class,
       UnanalyzedLanguageMetrics.class,
 
-      QualityGateModule.class,
-      ProjectsInWarningModule.class,
-      QualityGateWsModule.class,
+      new QualityGateModule(),
+      new ProjectsInWarningModule(),
+      new QualityGateWsModule(),
 
       // web services
       WebServiceEngine.class,
-      WebServicesWsModule.class,
+      new WebServicesWsModule(),
       SonarLintConnectionFilter.class,
       WebServiceFilter.class,
       WebServiceReroutingFilter.class,
@@ -372,13 +372,13 @@ public class PlatformLevel4 extends PlatformLevel {
       org.sonar.server.platform.ws.IndexAction.class,
 
       // authentication
-      AuthenticationModule.class,
-      AuthenticationWsModule.class,
-      BitbucketModule.class,
-      GitHubModule.class,
-      GitLabModule.class,
-      LdapModule.class,
-      SamlModule.class,
+      new AuthenticationModule(),
+      new AuthenticationWsModule(),
+      new BitbucketModule(),
+      new GitHubModule(),
+      new GitLabModule(),
+      new LdapModule(),
+      new SamlModule(),
       DefaultAdminCredentialsVerifierImpl.class,
       DefaultAdminCredentialsVerifierNotificationTemplate.class,
       DefaultAdminCredentialsVerifierNotificationHandler.class,
@@ -391,29 +391,29 @@ public class PlatformLevel4 extends PlatformLevel {
       UserIndexer.class,
       UserIndex.class,
       UserUpdater.class,
-      UsersWsModule.class,
-      UserTokenModule.class,
-      UserTokenWsModule.class,
+      new UsersWsModule(),
+      new UserTokenModule(),
+      new UserTokenWsModule(),
 
       // groups
-      UserGroupsModule.class,
+      new UserGroupsModule(),
       DefaultGroupFinder.class,
 
       // permissions
       DefaultTemplatesResolverImpl.class,
-      PermissionsWsModule.class,
+      new PermissionsWsModule(),
       PermissionTemplateService.class,
       PermissionUpdater.class,
       UserPermissionChanger.class,
       GroupPermissionChanger.class,
 
       // components
-      BranchWsModule.class,
-      PullRequestWsModule.class,
-      ProjectsWsModule.class,
-      ProjectsEsModule.class,
-      ProjectTagsWsModule.class,
-      ComponentsWsModule.class,
+      new BranchWsModule(),
+      new PullRequestWsModule(),
+      new ProjectsWsModule(),
+      new ProjectsEsModule(),
+      new ProjectTagsWsModule(),
+      new ComponentsWsModule(),
       ComponentService.class,
       ComponentUpdater.class,
       ComponentFinder.class,
@@ -423,13 +423,13 @@ public class PlatformLevel4 extends PlatformLevel {
       ComponentIndexDefinition.class,
       ComponentIndex.class,
       ComponentIndexer.class,
-      LiveMeasureModule.class,
+      new LiveMeasureModule(),
       ComponentViewerJsonWriter.class,
 
-      DevelopersWsModule.class,
+      new DevelopersWsModule(),
 
-      FavoriteModule.class,
-      FavoriteWsModule.class,
+      new FavoriteModule(),
+      new FavoriteWsModule(),
 
       // views
       ViewIndexDefinition.class,
@@ -442,10 +442,10 @@ public class PlatformLevel4 extends PlatformLevel {
       IssueIndexer.class,
       IssueIteratorFactory.class,
       PermissionIndexer.class,
-      IssueWsModule.class,
+      new IssueWsModule(),
       NewIssuesEmailTemplate.class,
       MyNewIssuesEmailTemplate.class,
-      IssuesChangesNotificationModule.class,
+      new IssuesChangesNotificationModule(),
       NewIssuesNotificationHandler.class,
       NewIssuesNotificationHandler.newMetadata(),
       MyNewIssuesNotificationHandler.class,
@@ -462,10 +462,10 @@ public class PlatformLevel4 extends PlatformLevel {
       IssueChangePostProcessorImpl.class,
 
       // hotspots
-      HotspotsWsModule.class,
+      new HotspotsWsModule(),
 
       // source
-      SourceWsModule.class,
+      new SourceWsModule(),
 
       // Duplications
       DuplicationsParser.class,
@@ -482,31 +482,31 @@ public class PlatformLevel4 extends PlatformLevel {
       BuiltInQPChangeNotificationTemplate.class,
       BuiltInQPChangeNotificationHandler.class,
 
-      NotificationModule.class,
-      NotificationWsModule.class,
-      EmailsWsModule.class,
+      new NotificationModule(),
+      new NotificationWsModule(),
+      new EmailsWsModule(),
 
       // Settings
       ProjectConfigurationLoaderImpl.class,
       PersistentSettings.class,
-      SettingsWsModule.class,
+      new SettingsWsModule(),
 
-      TypeValidationModule.class,
+      new TypeValidationModule(),
 
       // New Code Periods
-      NewCodePeriodsWsModule.class,
+      new NewCodePeriodsWsModule(),
 
       // Project Links
-      ProjectLinksModule.class,
+      new ProjectLinksModule(),
 
       // Project Analyses
-      ProjectAnalysisWsModule.class,
+      new ProjectAnalysisWsModule(),
 
       // System
       ServerLogging.class,
-      ChangeLogLevelServiceModule.class,
-      HealthCheckerModule.class,
-      SystemWsModule.class,
+      new ChangeLogLevelServiceModule(getWebServer()),
+      new HealthCheckerModule(getWebServer()),
+      new SystemWsModule(),
 
       // Plugins WS
       PluginUpdateAggregator.class,
@@ -532,7 +532,7 @@ public class PlatformLevel4 extends PlatformLevel {
       BitbucketCloudRestClient.class,
       GitlabHttpClient.class,
       AzureDevOpsHttpClient.class,
-      AlmIntegrationsWSModule.class,
+      new AlmIntegrationsWSModule(),
       BitbucketCloudValidator.class,
       BitbucketServerSettingsValidator.class,
       GithubGlobalSettingsValidator.class,
@@ -540,16 +540,16 @@ public class PlatformLevel4 extends PlatformLevel {
       AzureDevOpsValidator.class,
 
       // ALM settings
-      AlmSettingsWsModule.class,
+      new AlmSettingsWsModule(),
 
       // Project export
-      ProjectExportWsModule.class,
+      new ProjectExportWsModule(),
 
       // Branch
       BranchFeatureProxyImpl.class,
 
       // Project badges
-      ProjectBadgesWsModule.class,
+      new ProjectBadgesWsModule(),
 
       // Core Extensions
       CoreExtensionBootstraper.class,
@@ -558,12 +558,12 @@ public class PlatformLevel4 extends PlatformLevel {
       MultipleAlmFeatureProvider.class,
 
       // ServerPush endpoints
-      ServerPushWsModule.class,
+      new ServerPushWsModule(),
 
       // Compute engine (must be after Views and Developer Cockpit)
-      ReportAnalysisFailureNotificationModule.class,
-      CeModule.class,
-      CeWsModule.class,
+      new ReportAnalysisFailureNotificationModule(),
+      new CeModule(),
+      new CeWsModule(),
       ReportTaskProcessor.class,
       IssueSyncTaskProcessor.class,
       AuditPurgeTaskProcessor.class,
@@ -575,18 +575,18 @@ public class PlatformLevel4 extends PlatformLevel {
       InternalPropertiesImpl.class,
 
       // UI
-      NavigationWsModule.class,
+      new NavigationWsModule(),
 
       // root
-      RootWsModule.class,
+      new RootWsModule(),
 
       // webhooks
       WebhookQGChangeEventListener.class,
-      WebhookModule.class,
-      WebhooksWsModule.class,
+      new WebhookModule(),
+      new WebhooksWsModule(),
 
       // Http Request ID
-      HttpRequestIdModule.class,
+      new HttpRequestIdModule(),
 
       RecoveryIndexer.class,
       ProjectIndexersImpl.class,
@@ -620,21 +620,23 @@ public class PlatformLevel4 extends PlatformLevel {
     );
 
     // system info
-    add(SystemInfoWriterModule.class);
+    add(new SystemInfoWriterModule(getWebServer()));
 
     addAll(level4AddedComponents);
   }
 
   @Override
   public PlatformLevel start() {
-    ComponentContainer container = getContainer();
-    CoreExtensionsInstaller coreExtensionsInstaller = get(WebCoreExtensionsInstaller.class);
+    SpringComponentContainer container = getContainer();
+    CoreExtensionsInstaller coreExtensionsInstaller = parent.get(WebCoreExtensionsInstaller.class);
     coreExtensionsInstaller.install(container, hasPlatformLevel4OrNone(), noAdditionalSideFilter());
-    ServerExtensionInstaller extensionInstaller = get(ServerExtensionInstaller.class);
+
+    ServerExtensionInstaller extensionInstaller = parent.get(ServerExtensionInstaller.class);
     extensionInstaller.installExtensions(container);
 
     super.start();
 
     return this;
   }
+
 }
index b18851b0898f974bab234bb230924743ad7749b6..cd3a77f83599f842bb39e3621355212eed733fcd 100644 (file)
@@ -49,11 +49,11 @@ public class PlatformLevelSafeMode extends PlatformLevel {
       IndexAction.class,
 
       // Server WS
-      SafeModeHealthCheckerModule.class,
-      SafemodeSystemWsModule.class,
+      new SafeModeHealthCheckerModule(),
+      new SafemodeSystemWsModule(),
 
       // Listing WS
-      WebServicesWsModule.class,
+      new WebServicesWsModule(),
 
       // WS engine
       SafeModeUserSession.class,
@@ -64,7 +64,7 @@ public class PlatformLevelSafeMode extends PlatformLevel {
       ServerMonitoringMetrics.class);
     addIfStartupLeader(
       DatabaseMigrationImpl.class,
-      MigrationEngineModule.class,
+      new MigrationEngineModule(),
       AutoDbMigration.class)
         .otherwiseAdd(NoopDatabaseMigrationImpl.class);
   }
index 7aec25a435449fdb79ced7d41e71cfd7dc2cf222..eb4f64bd212e95efa6c7a23ba75d02612fe596d0 100644 (file)
@@ -100,9 +100,9 @@ public class PlatformLevelStartup extends PlatformLevel {
   }
 
   private boolean anyPluginChanged() {
-    return getOptional(DetectPluginChange.class)
+    return parent.getOptional(DetectPluginChange.class)
       .map(DetectPluginChange::anyPluginChanged)
-      .orElseThrow(() -> new IllegalStateException("DetectPluginChange not available in Pico yet"));
+      .orElseThrow(() -> new IllegalStateException("DetectPluginChange not available in the container yet"));
   }
 
   public final class AddIfStartupLeaderAndPluginsChanged extends AddIf {
@@ -113,7 +113,7 @@ public class PlatformLevelStartup extends PlatformLevel {
 
   @Override
   public PlatformLevel start() {
-    DoPrivileged.execute(new DoPrivileged.Task(get(ThreadLocalUserSession.class)) {
+    DoPrivileged.execute(new DoPrivileged.Task(parent.get(ThreadLocalUserSession.class)) {
       @Override
       protected void doPrivileged() {
         PlatformLevelStartup.super.start();
index a278da715a8b47f3d074812729b8483a3a35cd65..715727a4a05f31639727ff633fb7996029a4c014 100644 (file)
@@ -57,7 +57,7 @@ public class MasterServletFilter implements Filter {
 
   @Override
   public void init(FilterConfig config) {
-    // Filters are already available in picocontainer unless a database migration is required. See
+    // Filters are already available in the container unless a database migration is required. See
     // org.sonar.server.startup.RegisterServletFilters.
     init(config, PlatformImpl.getInstance().getContainer().getComponentsByType(ServletFilter.class));
   }
index 1cd479220d816e0e383b3be9f375976e71e63aad..9a44903a94e9e21f3960de21f37a0042398c68c4 100644 (file)
@@ -20,8 +20,9 @@
 package org.sonar.server.platform.web;
 
 import java.util.Arrays;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.web.ServletFilter;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * @since 3.5
@@ -29,10 +30,12 @@ import org.sonar.api.web.ServletFilter;
 public class RegisterServletFilters implements Startable {
   private final ServletFilter[] filters;
 
+  @Autowired(required = false)
   public RegisterServletFilters(ServletFilter[] filters) {
     this.filters = filters;
   }
 
+  @Autowired(required = false)
   public RegisterServletFilters() {
     this(new ServletFilter[0]);
   }
index 0db1fcf534adf81910115abd99358373692abc03..7728736c1991e76512df059688b467fad821016b 100644 (file)
@@ -55,12 +55,12 @@ public class RequestIdFilter implements Filter {
 
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
-    RequestIdGenerator requestIdGenerator = platform.getContainer().getComponentByType(RequestIdGenerator.class);
+    var requestIdGenerator = platform.getContainer().getOptionalComponentByType(RequestIdGenerator.class);
 
-    if (requestIdGenerator == null) {
+    if (requestIdGenerator.isEmpty()) {
       chain.doFilter(request, response);
     } else {
-      String requestId = requestIdGenerator.generate();
+      String requestId = requestIdGenerator.get().generate();
       try (RequestIdMDCStorage mdcStorage = new RequestIdMDCStorage(requestId)) {
         request.setAttribute("ID", requestId);
         chain.doFilter(request, response);
index 63ae20874cd197111d4064f55e33eb3a0eadaced..074443d0e2aedc28bd21e2f2fec984bea3b5b5b5 100644 (file)
@@ -58,7 +58,7 @@ public class UserSessionFilter implements Filter {
 
     DBSessions dbSessions = platform.getContainer().getComponentByType(DBSessions.class);
     ThreadLocalSettings settings = platform.getContainer().getComponentByType(ThreadLocalSettings.class);
-    UserSessionInitializer userSessionInitializer = platform.getContainer().getComponentByType(UserSessionInitializer.class);
+    UserSessionInitializer userSessionInitializer = platform.getContainer().getOptionalComponentByType(UserSessionInitializer.class).orElse(null);
 
     LOG.trace("{} serves {}", Thread.currentThread(), request.getRequestURI());
     dbSessions.enableCaching();
index 4ad93fbf274cf5e405e4066c6fd2c152562005d9..1f9041f33e4aedb0888508edcc44f139e5092a4a 100644 (file)
@@ -21,10 +21,7 @@ package org.sonar.server.platform.platformlevel;
 
 import java.util.Properties;
 import org.junit.Test;
-import org.sonar.api.config.PropertyDefinition;
-import org.sonar.api.utils.System2;
 import org.sonar.server.platform.Platform;
-import org.sonar.server.platform.WebServer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -32,14 +29,12 @@ import static org.mockito.Mockito.mock;
 
 public class PlatformLevel1Test {
 
-  private PlatformLevel1 underTest = new PlatformLevel1(mock(Platform.class), new Properties());
+  private final PlatformLevel1 underTest = new PlatformLevel1(mock(Platform.class), new Properties());
 
   @Test
   public void no_missing_dependencies_between_components() {
     underTest.configureLevel();
 
-    assertThat(underTest.getAll(PropertyDefinition.class)).isNotEmpty();
-    assertThat(underTest.getOptional(WebServer.class)).isPresent();
-    assertThat(underTest.getOptional(System2.class)).isPresent();
+    assertThat(underTest.getContainer().context().getBeanDefinitionNames()).isNotEmpty();
   }
 }
index efc9935052e4dc5c3d87660db05338ce000f1cc3..145a1f9e6febd6f05fa94dfd083ad7930b4f0db3 100644 (file)
  */
 package org.sonar.server.platform.platformlevel;
 
+import java.util.Optional;
 import java.util.Properties;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
-import org.sonar.api.utils.System2;
-import org.sonar.core.platform.PluginRepository;
-import org.sonar.server.platform.Platform;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.server.platform.WebServer;
 import org.sonar.server.platform.db.migration.charset.DatabaseCharsetChecker;
+import org.sonar.server.plugins.ServerPluginRepository;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 import static org.sonar.process.ProcessProperties.Property.PATH_DATA;
 import static org.sonar.process.ProcessProperties.Property.PATH_HOME;
 import static org.sonar.process.ProcessProperties.Property.PATH_TEMP;
@@ -53,38 +57,45 @@ public class PlatformLevel2Test {
 
   @Test
   public void add_all_components_by_default() {
-    PlatformLevel1 level1 = new PlatformLevel1(mock(Platform.class), props);
-    level1.configure();
-
-    PlatformLevel2 underTest = new PlatformLevel2(level1);
+    var parentContainer = mock(SpringComponentContainer.class);
+    var container = mock(SpringComponentContainer.class);
+    var platform = mock(PlatformLevel.class);
+    var webserver = mock(WebServer.class);
+
+    when(parentContainer.createChild()).thenReturn(container);
+    when(platform.getContainer()).thenReturn(parentContainer);
+    when(parentContainer.getOptionalComponentByType(any())).thenReturn(Optional.empty());
+    when(container.getOptionalComponentByType(WebServer.class)).thenReturn(Optional.of(webserver));
+    when(webserver.isStartupLeader()).thenReturn(true);
+
+    PlatformLevel2 underTest = new PlatformLevel2(platform);
     underTest.configure();
 
-    // some level1 components
-    assertThat(underTest.getOptional(WebServer.class)).isPresent();
-    assertThat(underTest.getOptional(System2.class)).isPresent();
-
-    // level2 component that does not depend on cluster state
-    assertThat(underTest.getOptional(PluginRepository.class)).isPresent();
-
-    // level2 component that is injected only on "startup leaders"
-    assertThat(underTest.getOptional(DatabaseCharsetChecker.class)).isPresent();
+    verify(container).add(ServerPluginRepository.class);
+    verify(container).add(DatabaseCharsetChecker.class);
+    verify(container, times(23)).add(any());
   }
 
   @Test
   public void do_not_add_all_components_when_startup_follower() {
-    props.setProperty("sonar.cluster.enabled", "true");
-    PlatformLevel1 level1 = new PlatformLevel1(mock(Platform.class), props);
-    level1.configure();
-
-    PlatformLevel2 underTest = new PlatformLevel2(level1);
+    var parentContainer = mock(SpringComponentContainer.class);
+    var container = mock(SpringComponentContainer.class);
+    var platform = mock(PlatformLevel.class);
+    var webserver = mock(WebServer.class);
+
+    when(parentContainer.createChild()).thenReturn(container);
+    when(platform.getContainer()).thenReturn(parentContainer);
+    when(parentContainer.getOptionalComponentByType(any())).thenReturn(Optional.empty());
+    when(container.getOptionalComponentByType(WebServer.class)).thenReturn(Optional.of(webserver));
+    when(webserver.isStartupLeader()).thenReturn(false);
+
+    PlatformLevel2 underTest = new PlatformLevel2(platform);
     underTest.configure();
 
-    assertThat(underTest.get(WebServer.class).isStartupLeader()).isFalse();
+    verify(container).add(ServerPluginRepository.class);
+    verify(container, never()).add(DatabaseCharsetChecker.class);
+    verify(container, times(21)).add(any());
+  }
 
-    // level2 component that does not depend on cluster state
-    assertThat(underTest.getOptional(PluginRepository.class)).isPresent();
 
-    // level2 component that is injected only on "startup leaders"
-    assertThat(underTest.getOptional(DatabaseCharsetChecker.class)).isNotPresent();
-  }
 }
index 321bb080b218e39e19a6a4017a5fdfa80cf9a04d..3908150d902fcb16fcf7e35d75373a6fc049d254 100644 (file)
@@ -21,8 +21,11 @@ package org.sonar.server.platform.platformlevel;
 
 import java.util.Random;
 import java.util.stream.IntStream;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
+import static org.mockito.Mockito.mock;
 import org.sonar.server.platform.WebServer;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -30,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 public class PlatformLevelTest {
 
-  private PlatformLevel underTest = new PlatformLevel("name") {
+  private final PlatformLevel underTest = new PlatformLevel("name") {
 
     @Override
     protected void configureLevel() {
@@ -38,16 +41,27 @@ public class PlatformLevelTest {
     }
   };
 
+  @Before
+  public void setUp() {
+    underTest.start();
+  }
+
+  @After
+  public void tearDown() {
+    // clean up for next test
+    underTest.stop();
+  }
+
   @Test
   public void addIfStartupLeader_throws_ISE_if_container_does_not_have_WebServer_object() {
-    assertThatThrownBy(() -> underTest.addIfStartupLeader())
+    assertThatThrownBy(underTest::addIfStartupLeader)
       .isInstanceOf(IllegalStateException.class)
-      .hasMessageContaining("WebServer not available in Pico yet");
+      .hasMessageContaining("WebServer not available in the container");
   }
 
   @Test
   public void addIfStartupLeader_always_returns_the_same_instance() {
-    underTest.add(Mockito.mock(WebServer.class));
+    underTest.add(mock(WebServer.class));
 
     PlatformLevel.AddIfStartupLeader addIfStartupLeader = underTest.addIfStartupLeader();
     IntStream.range(0, 1 + new Random().nextInt(4)).forEach(i -> assertThat(underTest.addIfStartupLeader()).isSameAs(addIfStartupLeader));
@@ -55,14 +69,14 @@ public class PlatformLevelTest {
 
   @Test
   public void addIfCluster_throws_ISE_if_container_does_not_have_WebServer_object() {
-    assertThatThrownBy(() -> underTest.addIfCluster())
+    assertThatThrownBy(underTest::addIfCluster)
       .isInstanceOf(IllegalStateException.class)
-      .hasMessageContaining("WebServer not available in Pico yet");
+      .hasMessageContaining("WebServer not available in the container");
   }
 
   @Test
   public void addIfCluster_always_returns_the_same_instance() {
-    underTest.add(Mockito.mock(WebServer.class));
+    underTest.add(mock(WebServer.class));
 
     PlatformLevel.AddIfCluster addIfCluster = underTest.addIfCluster();
     IntStream.range(0, 1 + new Random().nextInt(4)).forEach(i -> assertThat(underTest.addIfCluster()).isSameAs(addIfCluster));
@@ -70,14 +84,14 @@ public class PlatformLevelTest {
 
   @Test
   public void addIfStandalone_throws_ISE_if_container_does_not_have_WebServer_object() {
-    assertThatThrownBy(() -> underTest.addIfCluster())
+    assertThatThrownBy(underTest::addIfCluster)
       .isInstanceOf(IllegalStateException.class)
-      .hasMessageContaining("WebServer not available in Pico yet");
+      .hasMessageContaining("WebServer not available in the container");
   }
 
   @Test
   public void addIfStandalone_always_returns_the_same_instance() {
-    underTest.add(Mockito.mock(WebServer.class));
+    underTest.add(mock(WebServer.class));
 
     PlatformLevel.AddIfCluster addIfCluster = underTest.addIfCluster();
     IntStream.range(0, 1 + new Random().nextInt(4)).forEach(i -> assertThat(underTest.addIfCluster()).isSameAs(addIfCluster));
index 0996d7e231c116c271cd94b2102db0d27efc4393..e49f84e616cc80f13aecb25e8ffab5681154df5b 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.platform.web;
 
 import java.io.IOException;
+import java.util.Optional;
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
@@ -27,7 +28,7 @@ import javax.servlet.ServletResponse;
 import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.MDC;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 import org.sonar.server.platform.Platform;
 import org.sonar.server.platform.web.requestid.RequestIdGenerator;
 
@@ -41,17 +42,17 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 public class RequestIdFilterTest {
-  private Platform platform = mock(Platform.class);
-  private RequestIdGenerator requestIdGenerator = mock(RequestIdGenerator.class);
-  private ServletRequest servletRequest = mock(ServletRequest.class);
-  private ServletResponse servletResponse = mock(ServletResponse.class);
-  private FilterChain filterChain = mock(FilterChain.class);
-  private RequestIdFilter underTest = new RequestIdFilter(platform);
+  private final Platform platform = mock(Platform.class);
+  private final RequestIdGenerator requestIdGenerator = mock(RequestIdGenerator.class);
+  private final ServletRequest servletRequest = mock(ServletRequest.class);
+  private final ServletResponse servletResponse = mock(ServletResponse.class);
+  private final FilterChain filterChain = mock(FilterChain.class);
+  private final RequestIdFilter underTest = new RequestIdFilter(platform);
 
   @Before
   public void setUp() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(requestIdGenerator);
+    ExtensionContainer container = mock(ExtensionContainer.class);
+    when(container.getOptionalComponentByType(RequestIdGenerator.class)).thenReturn(Optional.of(requestIdGenerator));
     when(platform.getContainer()).thenReturn(container);
   }
 
@@ -102,8 +103,9 @@ public class RequestIdFilterTest {
 
   @Test
   public void filter_does_not_fail_when_there_is_no_RequestIdGenerator_in_container() throws IOException, ServletException {
-    Platform platform = mock(Platform.class);
-    when(platform.getContainer()).thenReturn(new ComponentContainer());
+    ExtensionContainer container = mock(ExtensionContainer.class);
+    when(container.getOptionalComponentByType(RequestIdGenerator.class)).thenReturn(Optional.empty());
+    when(platform.getContainer()).thenReturn(container);
     RequestIdFilter underTest = new RequestIdFilter(platform);
 
     underTest.doFilter(servletRequest, servletResponse, filterChain);
@@ -111,8 +113,9 @@ public class RequestIdFilterTest {
 
   @Test
   public void filter_does_not_add_requestId_to_request_passed_on_to_chain_when_there_is_no_RequestIdGenerator_in_container() throws IOException, ServletException {
-    Platform platform = mock(Platform.class);
-    when(platform.getContainer()).thenReturn(new ComponentContainer());
+    ExtensionContainer container = mock(ExtensionContainer.class);
+    when(container.getOptionalComponentByType(RequestIdGenerator.class)).thenReturn(Optional.empty());
+    when(platform.getContainer()).thenReturn(container);
     RequestIdFilter underTest = new RequestIdFilter(platform);
 
     underTest.doFilter(servletRequest, servletResponse, filterChain);
index 33741bb3c5cd3b6a0ebf245b898ddddc439f9ed3..7dba44294743fc7563b963f679f45df73e41459f 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.platform.web;
 
 import java.io.IOException;
+import java.util.Optional;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
@@ -28,7 +29,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.InOrder;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 import org.sonar.db.DBSessions;
 import org.sonar.server.authentication.UserSessionInitializer;
 import org.sonar.server.platform.Platform;
@@ -46,19 +47,21 @@ import static org.mockito.Mockito.when;
 
 public class UserSessionFilterTest {
 
-  private UserSessionInitializer userSessionInitializer = mock(UserSessionInitializer.class);
-  private ComponentContainer container = new ComponentContainer();
-  private Platform platform = mock(Platform.class);
-  private HttpServletRequest request = mock(HttpServletRequest.class);
-  private HttpServletResponse response = mock(HttpServletResponse.class);
-  private FilterChain chain = mock(FilterChain.class);
-  private DBSessions dbSessions = mock(DBSessions.class);
-  private ThreadLocalSettings settings = mock(ThreadLocalSettings.class);
-  private UserSessionFilter underTest = new UserSessionFilter(platform);
+  private final UserSessionInitializer userSessionInitializer = mock(UserSessionInitializer.class);
+  private final ExtensionContainer container = mock(ExtensionContainer.class);
+  private final Platform platform = mock(Platform.class);
+  private final HttpServletRequest request = mock(HttpServletRequest.class);
+  private final HttpServletResponse response = mock(HttpServletResponse.class);
+  private final FilterChain chain = mock(FilterChain.class);
+  private final DBSessions dbSessions = mock(DBSessions.class);
+  private final ThreadLocalSettings settings = mock(ThreadLocalSettings.class);
+  private final UserSessionFilter underTest = new UserSessionFilter(platform);
 
   @Before
   public void setUp() {
-    container.add(dbSessions, settings);
+    when(container.getComponentByType(DBSessions.class)).thenReturn(dbSessions);
+    when(container.getComponentByType(ThreadLocalSettings.class)).thenReturn(settings);
+    when(container.getOptionalComponentByType(UserSessionInitializer.class)).thenReturn(Optional.empty());
     when(platform.getContainer()).thenReturn(container);
   }
 
@@ -158,12 +161,12 @@ public class UserSessionFilterTest {
   }
 
   private void mockUserSessionInitializer(boolean value) {
-    container.add(userSessionInitializer);
+    when(container.getOptionalComponentByType(UserSessionInitializer.class)).thenReturn(Optional.of(userSessionInitializer));
     when(userSessionInitializer.initUserSession(request, response)).thenReturn(value);
   }
 
   private RuntimeException mockUserSessionInitializerRemoveUserSessionFailing() {
-    container.add(userSessionInitializer);
+    when(container.getOptionalComponentByType(UserSessionInitializer.class)).thenReturn(Optional.of(userSessionInitializer));
     RuntimeException thrown = new RuntimeException("Faking UserSessionInitializer.removeUserSession failing");
     doThrow(thrown)
       .when(userSessionInitializer)
index 3141d504391a47ea3c3a24cb1c9130386c8e095d..153eb788ec291dcd7c9a81227bb4a70bb6f26586 100644 (file)
@@ -16,9 +16,9 @@ dependencies {
   compile 'commons-codec:commons-codec'
   compile 'commons-io:commons-io'
   compile 'commons-lang:commons-lang'
+  compile 'javax.annotation:javax.annotation-api'
   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'
index bae7811e1601168e670f04517913d060e2387370..cc436fbc0d4ccb5721429abd3ccfddebebbaa11b 100644 (file)
@@ -79,8 +79,7 @@ public abstract class CoreExtensionsInstaller {
     }
   }
 
-  private void addDeclaredExtensions(ExtensionContainer container, Predicate<Object> extensionFilter,
-    Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
+  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);
   }
index ad64a703f3fecfe221e3efb07e2065177da6823c..cfa5ac20de98ece3bf9e2a2b58dcc8dbbc60fdff 100644 (file)
@@ -40,7 +40,7 @@ import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.apache.commons.io.IOUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
 import org.sonar.api.utils.SonarException;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.Logger;
diff --git a/sonar-core/src/main/java/org/sonar/core/language/LanguagesProvider.java b/sonar-core/src/main/java/org/sonar/core/language/LanguagesProvider.java
new file mode 100644 (file)
index 0000000..811cd62
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.language;
+
+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.isPresent()) {
+      return new Languages(languages.get().toArray(new Language[0]));
+    } else {
+      return new Languages();
+    }
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/ClassDerivedBeanDefinition.java b/sonar-core/src/main/java/org/sonar/core/platform/ClassDerivedBeanDefinition.java
new file mode 100644 (file)
index 0000000..7ea1639
--- /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.core.platform;
+
+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.
+ * The goal is to support multiple constructors when adding extensions for plugins when no annotations are present.
+ * Spring will pick the constructor with the highest number of arguments that it can inject.
+ */
+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);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java
deleted file mode 100644 (file)
index b8d7c56..0000000
+++ /dev/null
@@ -1,339 +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.core.platform;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.picocontainer.Characteristics;
-import org.picocontainer.ComponentAdapter;
-import org.picocontainer.ComponentFactory;
-import org.picocontainer.ComponentMonitor;
-import org.picocontainer.DefaultPicoContainer;
-import org.picocontainer.LifecycleStrategy;
-import org.picocontainer.MutablePicoContainer;
-import org.picocontainer.PicoContainer;
-import org.picocontainer.behaviors.OptInCaching;
-import org.picocontainer.monitors.NullComponentMonitor;
-import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.scanner.ScannerSide;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.utils.System2;
-
-import static com.google.common.collect.ImmutableList.copyOf;
-import static java.util.Objects.requireNonNull;
-import static java.util.Optional.ofNullable;
-
-@ScannerSide
-@ServerSide
-@ComputeEngineSide
-public class ComponentContainer implements ExtensionContainer {
-  public static final int COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER = 2;
-
-  private static final class ExtendedDefaultPicoContainer extends DefaultPicoContainer {
-    private ExtendedDefaultPicoContainer(ComponentFactory componentFactory, LifecycleStrategy lifecycleStrategy,
-      @Nullable PicoContainer parent, ComponentMonitor componentMonitor) {
-      super(componentFactory, lifecycleStrategy, parent, componentMonitor);
-    }
-
-    @Override
-    public Object getComponent(final Object componentKeyOrType, final Class<? extends Annotation> annotation) {
-      try {
-        return super.getComponent(componentKeyOrType, annotation);
-      } catch (Throwable t) {
-        throw new IllegalStateException("Unable to load component " + componentKeyOrType, t);
-      }
-    }
-
-    @Override
-    public MutablePicoContainer makeChildContainer() {
-      DefaultPicoContainer pc = new ExtendedDefaultPicoContainer(componentFactory, lifecycleStrategy, this, componentMonitor);
-      addChildContainer(pc);
-      return pc;
-    }
-  }
-
-  private ComponentContainer parent;
-  private final List<ComponentContainer> children = new ArrayList<>();
-  private MutablePicoContainer pico;
-  private PropertyDefinitions propertyDefinitions;
-  private ComponentKeys componentKeys;
-
-  /**
-   * Create root container
-   */
-  public ComponentContainer() {
-    this(createPicoContainer());
-  }
-
-  protected ComponentContainer(MutablePicoContainer picoContainer) {
-    this(picoContainer, new PropertyDefinitions(System2.INSTANCE));
-  }
-
-  protected ComponentContainer(MutablePicoContainer picoContainer, PropertyDefinitions propertyDefinitions) {
-    requireNonNull(propertyDefinitions, "PropertyDefinitions can not be null");
-    this.parent = null;
-    this.pico = picoContainer;
-    this.componentKeys = new ComponentKeys();
-    this.propertyDefinitions = propertyDefinitions;
-    addSingleton(propertyDefinitions);
-    addSingleton(this);
-  }
-
-  /**
-   * Create child container
-   */
-  protected ComponentContainer(ComponentContainer parent) {
-    this.parent = parent;
-    this.pico = parent.pico.makeChildContainer();
-    this.parent.children.add(this);
-    this.propertyDefinitions = parent.propertyDefinitions;
-    this.componentKeys = new ComponentKeys();
-    addSingleton(this);
-  }
-
-  protected void setParent(ComponentContainer parent) {
-    this.parent = parent;
-  }
-
-  public void execute() {
-    try {
-      startComponents();
-    } finally {
-      stopComponents();
-    }
-  }
-
-  /**
-   * This method MUST NOT be renamed start() because the container is registered itself in picocontainer. Starting
-   * a component twice is not authorized.
-   */
-  public ComponentContainer startComponents() {
-    try {
-      doBeforeStart();
-      pico.start();
-      doAfterStart();
-      return this;
-    } catch (Exception e) {
-      throw PicoUtils.propagate(e);
-    }
-  }
-
-  /**
-   * This method aims to be overridden
-   */
-  protected void doBeforeStart() {
-    // nothing
-  }
-
-  /**
-   * This method aims to be overridden
-   */
-  protected void doAfterStart() {
-    // nothing
-  }
-
-  /**
-   * This method MUST NOT be renamed stop() because the container is registered itself in picocontainer. Starting
-   * a component twice is not authorized.
-   */
-  public ComponentContainer stopComponents() {
-    try {
-      stopChildren();
-      if (pico.getLifecycleState().isStarted()) {
-        pico.stop();
-      }
-      pico.dispose();
-    } finally {
-      if (parent != null) {
-        parent.removeChild(this);
-      }
-    }
-    return this;
-  }
-
-  private void stopChildren() {
-    // loop over a copy of list of children in reverse order, both to stop last added child first and because children
-    // remove themselves from the list of children of their parent (ie. changing this.children)
-    Lists.reverse(new ArrayList<>(this.children))
-      .forEach(ComponentContainer::stopComponents);
-  }
-
-  /**
-   * @since 3.5
-   */
-  @Override
-  public ComponentContainer add(Object... objects) {
-    for (Object object : objects) {
-      if (object instanceof ComponentAdapter) {
-        addPicoAdapter((ComponentAdapter) object);
-      } else if (object instanceof Iterable) {
-        add(Iterables.toArray((Iterable) object, Object.class));
-      } else {
-        addSingleton(object);
-      }
-    }
-    return this;
-  }
-
-  public void addIfMissing(Object object, Class<?> objectType) {
-    if (getComponentByType(objectType) == null) {
-      add(object);
-    }
-  }
-
-  @Override
-  public ComponentContainer addSingletons(Iterable<?> components) {
-    for (Object component : components) {
-      addSingleton(component);
-    }
-    return this;
-  }
-
-  public ComponentContainer addSingleton(Object component) {
-    return addComponent(component, true);
-  }
-
-  /**
-   * @param singleton return always the same instance if true, else a new instance
-   *                  is returned each time the component is requested
-   */
-  public ComponentContainer addComponent(Object component, boolean singleton) {
-    Object key = componentKeys.of(component);
-    if (component instanceof ComponentAdapter) {
-      pico.addAdapter((ComponentAdapter) component);
-    } else {
-      try {
-        pico.as(singleton ? Characteristics.CACHE : Characteristics.NO_CACHE).addComponent(key, component);
-      } catch (Throwable t) {
-        throw new IllegalStateException("Unable to register component " + getName(component), t);
-      }
-      declareExtension("", component);
-    }
-    return this;
-  }
-
-  @Override
-  public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) {
-    Object key = componentKeys.of(extension);
-    try {
-      pico.as(Characteristics.CACHE).addComponent(key, extension);
-    } catch (Throwable t) {
-      throw new IllegalStateException("Unable to register extension " + getName(extension) + (pluginInfo != null ? (" from plugin '" + pluginInfo.getKey() + "'") : ""), t);
-    }
-    declareExtension(pluginInfo, extension);
-    return this;
-  }
-
-  @Override
-  public ComponentContainer addExtension(@Nullable String defaultCategory, Object extension) {
-    Object key = componentKeys.of(extension);
-    try {
-      pico.as(Characteristics.CACHE).addComponent(key, extension);
-    } catch (Throwable t) {
-      throw new IllegalStateException("Unable to register extension " + getName(extension), t);
-    }
-    declareExtension(defaultCategory, extension);
-    return this;
-  }
-
-  private static String getName(Object extension) {
-    if (extension instanceof Class) {
-      return ((Class<?>) extension).getName();
-    }
-    return getName(extension.getClass());
-  }
-
-  @Override
-  public ComponentContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
-    declareExtension(pluginInfo != null ? pluginInfo.getName() : "", extension);
-    return this;
-  }
-
-  @Override
-  public ComponentContainer declareExtension(@Nullable String defaultCategory, Object extension) {
-    propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse(""));
-    return this;
-  }
-
-  public ComponentContainer addPicoAdapter(ComponentAdapter<?> adapter) {
-    pico.addAdapter(adapter);
-    return this;
-  }
-
-  @Override
-  public <T> T getComponentByType(Class<T> type) {
-    return pico.getComponent(type);
-  }
-
-  public Object getComponentByKey(Object key) {
-    return pico.getComponent(key);
-  }
-
-  @Override
-  public <T> List<T> getComponentsByType(Class<T> tClass) {
-    return pico.getComponents(tClass);
-  }
-
-  public ComponentContainer removeChild(ComponentContainer childToBeRemoved) {
-    requireNonNull(childToBeRemoved);
-    Iterator<ComponentContainer> childrenIterator = children.iterator();
-    while (childrenIterator.hasNext()) {
-      ComponentContainer child = childrenIterator.next();
-      if (child == childToBeRemoved) {
-        if (pico.removeChildContainer(child.pico)) {
-          childrenIterator.remove();
-        }
-        break;
-      }
-    }
-    return this;
-  }
-
-  public ComponentContainer createChild() {
-    return new ComponentContainer(this);
-  }
-
-  public static MutablePicoContainer createPicoContainer() {
-    return new ExtendedDefaultPicoContainer(new OptInCaching(), new StartableCloseableSafeLifecyleStrategy(), null, new NullComponentMonitor());
-  }
-
-  public ComponentContainer getParent() {
-    return parent;
-  }
-
-  public List<ComponentContainer> getChildren() {
-    return copyOf(children);
-  }
-
-  public MutablePicoContainer getPicoContainer() {
-    return pico;
-  }
-
-  public int size() {
-    return pico.getComponentAdapters().size();
-  }
-
-}
index e7a9963623dce61fdcf82288610529a91b426641..eb9b03789ff67c5cea9bc427ea4cc81ad1144550 100644 (file)
 package org.sonar.core.platform;
 
 import java.util.List;
+import java.util.Optional;
 
 public interface Container {
   Container add(Object... objects);
 
-  Container addSingletons(Iterable<?> components);
-
   <T> T getComponentByType(Class<T> type);
 
+  <T> Optional<T> getOptionalComponentByType(Class<T> type);
+
   <T> List<T> getComponentsByType(Class<T> type);
 
   Container getParent();
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/LazyStrategy.java b/sonar-core/src/main/java/org/sonar/core/platform/LazyStrategy.java
new file mode 100644 (file)
index 0000000..85c3f4d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.Nullable;
+import org.springframework.beans.factory.config.BeanDefinition;
+
+public class LazyStrategy extends SpringInitStrategy {
+  @Override
+  protected boolean isLazyInit(BeanDefinition beanDefinition, @Nullable Class<?> clazz) {
+    return true;
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/LazyUnlessStartableStrategy.java b/sonar-core/src/main/java/org/sonar/core/platform/LazyUnlessStartableStrategy.java
new file mode 100644 (file)
index 0000000..307881a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 org.sonar.api.Startable;
+import org.springframework.beans.factory.config.BeanDefinition;
+
+import javax.annotation.Nullable;
+
+public class LazyUnlessStartableStrategy extends SpringInitStrategy {
+  @Override
+  protected boolean isLazyInit(BeanDefinition beanDefinition, @Nullable Class<?> clazz) {
+    return clazz == null || !Startable.class.isAssignableFrom(clazz);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/ListContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/ListContainer.java
new file mode 100644 (file)
index 0000000..eaf8a16
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 com.google.common.collect.Iterables;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.Nullable;
+
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * Intended to be used in tests
+ */
+public class ListContainer implements ExtensionContainer {
+  private final List<Object> objects = new ArrayList<>();
+
+  @Override
+  public Container add(Object... objects) {
+    for (Object o : objects) {
+      if (o instanceof Module) {
+        ((Module) o).configure(this);
+      } else if (o instanceof Iterable) {
+        add(Iterables.toArray((Iterable<?>) o, Object.class));
+      } else {
+        this.objects.add(o);
+      }
+    }
+    return this;
+  }
+
+  public List<Object> getAddedObjects() {
+    return unmodifiableList(new ArrayList<>(objects));
+  }
+
+  @Override
+  public <T> T getComponentByType(Class<T> type) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public <T> Optional<T> getOptionalComponentByType(Class<T> type) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public <T> List<T> getComponentsByType(Class<T> type) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public ExtensionContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+    add(extension);
+    return this;
+  }
+
+  @Override
+  public ExtensionContainer addExtension(@Nullable String defaultCategory, Object extension) {
+    add(extension);
+    return this;
+  }
+
+  @Override
+  public ExtensionContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+    return this;
+  }
+
+  @Override
+  public ExtensionContainer declareExtension(@Nullable String defaultCategory, Object extension) {
+    return this;
+  }
+
+  @Override
+  public ExtensionContainer getParent() {
+    throw new UnsupportedOperationException();
+  }
+}
index 2e94f28c50ef2b662ad58e5a81cd9f7f8e38c36c..383aa6be3e23be4ba5be57584c3e563c641773ed 100644 (file)
@@ -24,13 +24,11 @@ import javax.annotation.Nullable;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 public abstract class Module {
-  private ComponentContainer container;
+  private Container container;
 
-  public Module configure(ComponentContainer container) {
+  public Module configure(Container container) {
     this.container = checkNotNull(container);
-
     configureModule();
-
     return this;
   }
 
@@ -43,7 +41,7 @@ public abstract class Module {
 
     for (Object object : objects) {
       if (object != null) {
-        container.addComponent(object, true);
+        container.add(object);
       }
     }
   }
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/PicoUtils.java b/sonar-core/src/main/java/org/sonar/core/platform/PicoUtils.java
deleted file mode 100644 (file)
index c73bb07..0000000
+++ /dev/null
@@ -1,47 +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.core.platform;
-
-import com.google.common.base.Throwables;
-import org.picocontainer.PicoLifecycleException;
-
-class PicoUtils {
-
-  private PicoUtils() {
-    // only static methods
-  }
-
-  static Throwable sanitize(Throwable t) {
-    Throwable result = t;
-    Throwable cause = t.getCause();
-    if (t instanceof PicoLifecycleException && cause != null) {
-      if ("wrapper".equals(cause.getMessage()) && cause.getCause() != null) {
-        result = cause.getCause();
-      } else {
-        result = cause;
-      }
-    }
-    return result;
-  }
-
-  static RuntimeException propagate(Throwable t) {
-    throw Throwables.propagate(sanitize(t));
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/PriorityBeanFactory.java b/sonar-core/src/main/java/org/sonar/core/platform/PriorityBeanFactory.java
new file mode 100644 (file)
index 0000000..a6af0bb
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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.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.BeanWrapper;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+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.toList());
+
+    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;
+  }
+
+  /**
+   * A common mistake when migrating from Pico Container to Spring is to forget to add @Inject or @Autowire annotations to classes that have multiple constructors.
+   * Spring will fail if there is no default no-arg constructor, but it will silently use the no-arg constructor if there is one, never calling the other constructors.
+   * We override this method to fail fast if a class has multiple constructors.
+   */
+  @Override
+  protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
+    if (mbd.hasBeanClass() && mbd.getBeanClass().getConstructors().length > 1) {
+      throw new IllegalStateException("Constructor annotations missing in: " + mbd.getBeanClass());
+    }
+    return super.instantiateBean(beanName, mbd);
+  }
+
+  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 {
+    @CheckForNull
+    Integer classify(Bean candidate);
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/SpringComponentContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/SpringComponentContainer.java
new file mode 100644 (file)
index 0000000..44f0db9
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * 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 com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Supplier;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.System2;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+import static java.util.Collections.emptyList;
+import static java.util.Optional.ofNullable;
+
+public class SpringComponentContainer implements StartableContainer {
+  protected final AnnotationConfigApplicationContext context;
+  @Nullable
+  protected final SpringComponentContainer parent;
+  protected final List<SpringComponentContainer> children = new ArrayList<>();
+
+  private final PropertyDefinitions propertyDefinitions;
+  private final ComponentKeys componentKeys = new ComponentKeys();
+
+  public SpringComponentContainer() {
+    this(null, new PropertyDefinitions(System2.INSTANCE), emptyList(), new LazyUnlessStartableStrategy());
+  }
+
+  protected SpringComponentContainer(List<?> externalExtensions) {
+    this(null, new PropertyDefinitions(System2.INSTANCE), externalExtensions, new LazyUnlessStartableStrategy());
+  }
+
+  protected SpringComponentContainer(SpringComponentContainer parent) {
+    this(parent, parent.propertyDefinitions, emptyList(), new LazyUnlessStartableStrategy());
+  }
+
+  protected SpringComponentContainer(SpringComponentContainer parent, SpringInitStrategy initStrategy) {
+    this(parent, parent.propertyDefinitions, emptyList(), initStrategy);
+  }
+
+  protected SpringComponentContainer(@Nullable SpringComponentContainer parent, PropertyDefinitions propertyDefs, List<?> externalExtensions, SpringInitStrategy initStrategy) {
+    this.parent = parent;
+    this.propertyDefinitions = propertyDefs;
+    this.context = new AnnotationConfigApplicationContext(new PriorityBeanFactory());
+    this.context.setAllowBeanDefinitionOverriding(false);
+    ((AbstractAutowireCapableBeanFactory) context.getBeanFactory()).setParameterNameDiscoverer(null);
+    if (parent != null) {
+      context.setParent(parent.context);
+      parent.children.add(this);
+    }
+    add(initStrategy);
+    add(this);
+    add(new StartableBeanPostProcessor());
+    add(externalExtensions);
+    add(propertyDefs);
+  }
+
+  /**
+   * Beans need to have a unique name, otherwise they'll override each other.
+   * The strategy is:
+   * - For classes, use the classloader + fully qualified class name as the name of the bean
+   * - For instances, use the Classloader + 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;
+        if (Module.class.isAssignableFrom(clazz)) {
+          throw new IllegalStateException("Modules should be added as instances");
+        }
+        context.registerBean(componentKeys.ofClass(clazz), clazz);
+        declareExtension("", o);
+      } else if (o instanceof Module) {
+        ((Module) o).configure(this);
+      } else if (o instanceof Iterable) {
+        add(Iterables.toArray((Iterable<?>) o, Object.class));
+      } else {
+        registerInstance(o);
+        declareExtension("", 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);
+  }
+
+  /**
+   * 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(componentKeys.ofClass(clazz), bd);
+    } else if (o instanceof Iterable) {
+      ((Iterable<?>) o).forEach(this::addExtension);
+    } else {
+      registerInstance(o);
+    }
+    return this;
+  }
+
+  @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> Optional<T> getOptionalComponentByType(Class<T> type) {
+    try {
+      return Optional.of(context.getBean(type));
+    } catch (NoSuchBeanDefinitionException t) {
+      return Optional.empty();
+    }
+  }
+
+  @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 AnnotationConfigApplicationContext context() {
+    return context;
+  }
+
+  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;
+    }
+  }
+
+  @Override
+  public SpringComponentContainer startComponents() {
+    doBeforeStart();
+    context.refresh();
+    doAfterStart();
+    return this;
+  }
+
+  public SpringComponentContainer stopComponents() {
+    try {
+      stopChildren();
+      if (context.isActive()) {
+        context.close();
+      }
+    } finally {
+      if (parent != null) {
+        parent.children.remove(this);
+      }
+    }
+    return this;
+  }
+
+  private void stopChildren() {
+    // loop over a copy of list of children in reverse order
+    Lists.reverse(new ArrayList<>(this.children)).forEach(SpringComponentContainer::stopComponents);
+  }
+
+  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-core/src/main/java/org/sonar/core/platform/SpringInitStrategy.java b/sonar-core/src/main/java/org/sonar/core/platform/SpringInitStrategy.java
new file mode 100644 (file)
index 0000000..107c387
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.Nullable;
+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 abstract class SpringInitStrategy implements BeanFactoryPostProcessor {
+  @Override
+  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+    for (String beanName : beanFactory.getBeanDefinitionNames()) {
+      BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+      Class<?> rawClass = beanDefinition.getResolvableType().getRawClass();
+      beanDefinition.setLazyInit(isLazyInit(beanDefinition, rawClass));
+    }
+  }
+
+  protected abstract boolean isLazyInit(BeanDefinition beanDefinition, @Nullable Class<?> clazz);
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/StartableBeanPostProcessor.java b/sonar-core/src/main/java/org/sonar/core/platform/StartableBeanPostProcessor.java
new file mode 100644 (file)
index 0000000..a4aa6ea
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 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();
+    }
+    return bean;
+  }
+
+  @Override
+  public boolean requiresDestruction(Object bean) {
+    return bean instanceof Startable;
+  }
+
+  @Override
+  public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
+    try {
+      // note: Spring will call close() on AutoCloseable beans.
+      if (bean instanceof Startable) {
+        ((Startable) bean).stop();
+      }
+    } catch (Exception e) {
+      Loggers.get(StartableBeanPostProcessor.class)
+        .warn("Dispose of component {} failed", bean.getClass().getCanonicalName(), e);
+    }
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/StartableCloseableSafeLifecyleStrategy.java b/sonar-core/src/main/java/org/sonar/core/platform/StartableCloseableSafeLifecyleStrategy.java
deleted file mode 100644 (file)
index 9549af8..0000000
+++ /dev/null
@@ -1,105 +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.core.platform;
-
-import java.io.Closeable;
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.stream.Stream;
-import org.picocontainer.ComponentAdapter;
-import org.picocontainer.LifecycleStrategy;
-import org.picocontainer.Startable;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-public class StartableCloseableSafeLifecyleStrategy implements LifecycleStrategy, Serializable {
-  private static final Class<?>[] TYPES_WITH_LIFECYCLE = new Class[] {Startable.class, org.sonar.api.Startable.class, Closeable.class, AutoCloseable.class};
-
-  private static final Logger LOG = Loggers.get(StartableCloseableSafeLifecyleStrategy.class);
-
-  @Override
-  public void start(Object component) {
-    if (component instanceof Startable) {
-      ((Startable) component).start();
-    } else if (component instanceof org.sonar.api.Startable) {
-      ((org.sonar.api.Startable) component).start();
-    }
-  }
-
-  @Override
-  public void stop(Object component) {
-    try {
-      if (component instanceof Startable) {
-        ((Startable) component).stop();
-      } else if (component instanceof org.sonar.api.Startable) {
-        ((org.sonar.api.Startable) component).stop();
-      }
-    } catch (RuntimeException | Error e) {
-      Loggers.get(StartableCloseableSafeLifecyleStrategy.class)
-        .warn("Stopping of component {} failed", component.getClass().getCanonicalName(), e);
-    }
-  }
-
-  @Override
-  public void dispose(Object component) {
-    try {
-      if (component instanceof Closeable) {
-        ((Closeable) component).close();
-      } else if (component instanceof AutoCloseable) {
-        ((AutoCloseable) component).close();
-      }
-    } catch (Exception e) {
-      Loggers.get(StartableCloseableSafeLifecyleStrategy.class)
-        .warn("Dispose of component {} failed", component.getClass().getCanonicalName(), e);
-    }
-  }
-
-  @Override
-  public boolean hasLifecycle(Class<?> type) {
-    if (Arrays.stream(TYPES_WITH_LIFECYCLE).anyMatch(t1 -> t1.isAssignableFrom(type))) {
-      return true;
-    }
-
-    if (Stream.of("start", "stop").anyMatch(t -> hasMethod(type, t))) {
-      LOG.warn("Component of type {} defines methods start() and/or stop(). Neither will be invoked to start/stop the component." +
-        " Please implement either {} or {}",
-        type, Startable.class.getName(), org.sonar.api.Startable.class.getName());
-    }
-    if (hasMethod(type, "close")) {
-      LOG.warn("Component of type {} defines method close(). It won't be invoked to dispose the component." +
-        " Please implement either {} or {}",
-        type, Closeable.class.getName(), AutoCloseable.class.getName());
-    }
-    return false;
-  }
-
-  private static boolean hasMethod(Class<?> type, String methodName) {
-    try {
-      return type.getMethod(methodName) != null;
-    } catch (NoSuchMethodException e) {
-      return false;
-    }
-  }
-
-  @Override
-  public boolean isLazy(ComponentAdapter<?> adapter) {
-    return false;
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/StartableContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/StartableContainer.java
new file mode 100644 (file)
index 0000000..2cf7b83
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public interface StartableContainer extends ExtensionContainer {
+  StartableContainer startComponents();
+}
index 45272778ea639e03948f0ba5a6ee5e226644d7c9..1257dd4b48564119cd4fe41e153aa0206b5a32b8 100644 (file)
@@ -27,7 +27,7 @@ public enum UuidFactoryImpl implements UuidFactory {
 
   /**
    * Should be removed as long {@link Uuids} is not used anymore. {@code UuidFactoryImpl}
-   * should be built by picocontainer through a public constructor.
+   * should be injected by the ioc container through a public constructor.
    */
   INSTANCE;
 
index 35bdea07ffdde5cba8930855addcf8d4e4bfb561..094d165573338481cbd36765ef6d4be5860abb11 100644 (file)
@@ -39,42 +39,39 @@ import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mockito;
-import org.picocontainer.ComponentAdapter;
 import org.sonar.api.Property;
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.config.Configuration;
 import org.sonar.api.config.PropertyDefinition;
-import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.config.internal.MapSettings;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideFilter;
 import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
 
 @RunWith(DataProviderRunner.class)
 public class CoreExtensionsInstallerTest {
-  private SonarRuntime sonarRuntime = mock(SonarRuntime.class);
-  private CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class);
-  private CoreExtensionsInstaller underTest = new CoreExtensionsInstaller(sonarRuntime, coreExtensionRepository, WestSide.class) {
+  private final SonarRuntime sonarRuntime = mock(SonarRuntime.class);
+  private final CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class);
+  private final CoreExtensionsInstaller underTest = new CoreExtensionsInstaller(sonarRuntime, coreExtensionRepository, WestSide.class) {
 
   };
 
-  private ArgumentCaptor<CoreExtension.Context> contextCaptor = ArgumentCaptor.forClass(CoreExtension.Context.class);
+  private final ArgumentCaptor<CoreExtension.Context> contextCaptor = ArgumentCaptor.forClass(CoreExtension.Context.class);
   private static int name_counter = 0;
 
   @Test
   public void install_has_no_effect_if_CoreExtensionRepository_has_no_loaded_CoreExtension() {
-    ComponentContainer container = new ComponentContainer();
-
+    ListContainer container = new ListContainer();
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
-
     assertAddedExtensions(container, 0);
   }
 
@@ -87,7 +84,7 @@ public class CoreExtensionsInstallerTest {
     List<CoreExtension> coreExtensions = ImmutableList.of(coreExtension1, coreExtension2, coreExtension3, coreExtension4);
     InOrder inOrder = Mockito.inOrder(coreExtension1, coreExtension2, coreExtension3, coreExtension4);
     when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(coreExtensions.stream());
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
@@ -105,7 +102,7 @@ public class CoreExtensionsInstallerTest {
     CoreExtension coreExtension1 = newCoreExtension();
     CoreExtension coreExtension2 = newCoreExtension();
     when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension1, coreExtension2));
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
@@ -121,7 +118,7 @@ public class CoreExtensionsInstallerTest {
     CoreExtension coreExtension1 = newCoreExtension();
     CoreExtension coreExtension2 = newCoreExtension();
     when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension1, coreExtension2));
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
@@ -138,9 +135,8 @@ public class CoreExtensionsInstallerTest {
     CoreExtension coreExtension2 = newCoreExtension();
     when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension1, coreExtension2));
     Configuration configuration = new MapSettings().asConfig();
-    ComponentContainer container = new ComponentContainer();
-    container.add(configuration);
-
+    ExtensionContainer container = mock(ExtensionContainer.class);
+    when(container.getComponentByType(Configuration.class)).thenReturn(configuration);
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
     verify(coreExtension1).load(contextCaptor.capture());
@@ -156,12 +152,15 @@ public class CoreExtensionsInstallerTest {
     List<Object> extensions = ImmutableList.of(WestSideClass.class, EastSideClass.class, OtherSideClass.class, Latitude.class);
     CoreExtension coreExtension = newCoreExtension(context -> extensionAdder.accept(context, extensions));
     when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension));
-    ComponentContainer container = new ComponentContainer();
+    ExtensionContainer container = mock(ExtensionContainer.class);
 
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
-    assertAddedExtensions(container, WestSideClass.class, Latitude.class);
-    assertPropertyDefinitions(container);
+    verify(container).addExtension(coreExtension.getName(), WestSideClass.class);
+    verify(container).declareExtension(coreExtension.getName(), OtherSideClass.class);
+    verify(container).declareExtension(coreExtension.getName(), EastSideClass.class);
+    verify(container).addExtension(coreExtension.getName(), Latitude.class);
+    verifyNoMoreInteractions(container);
   }
 
   @Test
@@ -170,42 +169,15 @@ public class CoreExtensionsInstallerTest {
     List<Object> extensions = ImmutableList.of(WestSideClass.class, EastSideClass.class, OtherSideClass.class, Latitude.class);
     CoreExtension coreExtension = newCoreExtension(context -> extensionAdder.accept(context, extensions));
     when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension));
-    ComponentContainer container = new ComponentContainer();
+    ExtensionContainer container = mock(ExtensionContainer.class);
 
     underTest.install(container, noExtensionFilter(), t -> t != Latitude.class);
 
-    assertAddedExtensions(container, WestSideClass.class);
-    assertPropertyDefinitions(container);
-  }
-
-  @Test
-  @UseDataProvider("allMethodsToAddExtension")
-  public void install_adds_PropertyDefinition_from_annotation_no_matter_annotations(BiConsumer<CoreExtension.Context, Collection<Object>> extensionAdder) {
-    List<Object> extensions = ImmutableList.of(WestSidePropertyDefinition.class, EastSidePropertyDefinition.class,
-      OtherSidePropertyDefinition.class, LatitudePropertyDefinition.class, BlankPropertyDefinition.class);
-    CoreExtension coreExtension = newCoreExtension(context -> extensionAdder.accept(context, extensions));
-    when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension));
-    ComponentContainer container = new ComponentContainer();
-
-    underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
-
-    assertAddedExtensions(container, WestSidePropertyDefinition.class, LatitudePropertyDefinition.class);
-    assertPropertyDefinitions(container, "westKey", "eastKey", "otherKey", "latitudeKey", "blankKey");
-  }
-
-  @Test
-  @UseDataProvider("allMethodsToAddExtension")
-  public void install_adds_PropertyDefinition_from_annotation_no_matter_annotations_even_if_filtered_out(BiConsumer<CoreExtension.Context, Collection<Object>> extensionAdder) {
-    List<Object> extensions = ImmutableList.of(WestSidePropertyDefinition.class, EastSidePropertyDefinition.class,
-      OtherSidePropertyDefinition.class, LatitudePropertyDefinition.class, BlankPropertyDefinition.class);
-    CoreExtension coreExtension = newCoreExtension(context -> extensionAdder.accept(context, extensions));
-    when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension));
-    ComponentContainer container = new ComponentContainer();
-
-    underTest.install(container, noExtensionFilter(), t -> false);
-
-    assertAddedExtensions(container, 0);
-    assertPropertyDefinitions(container, "westKey", "eastKey", "otherKey", "latitudeKey", "blankKey");
+    verify(container).addExtension(coreExtension.getName(), WestSideClass.class);
+    verify(container).declareExtension(coreExtension.getName(), OtherSideClass.class);
+    verify(container).declareExtension(coreExtension.getName(), EastSideClass.class);
+    verify(container).declareExtension(coreExtension.getName(), Latitude.class);
+    verifyNoMoreInteractions(container);
   }
 
   @Test
@@ -216,12 +188,13 @@ public class CoreExtensionsInstallerTest {
     List<Object> extensions = ImmutableList.of(propertyDefinitionNoCategory, propertyDefinitionWithCategory);
     CoreExtension coreExtension = newCoreExtension(context -> extensionAdder.accept(context, extensions));
     when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension));
-    ComponentContainer container = new ComponentContainer();
+    ExtensionContainer container = mock(ExtensionContainer.class);
 
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
-    assertAddedExtensions(container, 0);
-    assertPropertyDefinitions(container, coreExtension, propertyDefinitionNoCategory, propertyDefinitionWithCategory);
+    verify(container).declareExtension(coreExtension.getName(), propertyDefinitionNoCategory);
+    verify(container).declareExtension(coreExtension.getName(), propertyDefinitionWithCategory);
+    verifyNoMoreInteractions(container);
   }
 
   @DataProvider
@@ -244,46 +217,10 @@ public class CoreExtensionsInstallerTest {
     };
   }
 
-  private static void assertAddedExtensions(ComponentContainer container, int addedExtensions) {
-    Collection<ComponentAdapter<?>> adapters = container.getPicoContainer().getComponentAdapters();
-    assertThat(adapters)
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + addedExtensions);
-  }
-
-  private static void assertAddedExtensions(ComponentContainer container, Class... classes) {
-    Collection<ComponentAdapter<?>> adapters = container.getPicoContainer().getComponentAdapters();
+  private static void assertAddedExtensions(ListContainer container, int addedExtensions) {
+    List<Object> adapters = container.getAddedObjects();
     assertThat(adapters)
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + classes.length);
-
-    Stream<Class> installedExtensions = adapters.stream()
-      .map(t -> (Class) t.getComponentImplementation())
-      .filter(t -> !PropertyDefinitions.class.isAssignableFrom(t) && t != ComponentContainer.class);
-    assertThat(installedExtensions)
-      .contains(classes)
-      .hasSize(classes.length);
-  }
-
-  private void assertPropertyDefinitions(ComponentContainer container, String... keys) {
-    PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
-    if (keys.length == 0) {
-      assertThat(propertyDefinitions.getAll()).isEmpty();
-    } else {
-      for (String key : keys) {
-        assertThat(propertyDefinitions.get(key)).isNotNull();
-      }
-    }
-  }
-
-  private void assertPropertyDefinitions(ComponentContainer container, CoreExtension coreExtension, PropertyDefinition... definitions) {
-    PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
-    if (definitions.length == 0) {
-      assertThat(propertyDefinitions.getAll()).isEmpty();
-    } else {
-      for (PropertyDefinition definition : definitions) {
-        PropertyDefinition actual = propertyDefinitions.get(definition.key());
-        assertThat(actual.category()).isEqualTo(definition.category() == null ? coreExtension.getName() : definition.category());
-      }
-    }
+      .hasSize(addedExtensions);
   }
 
   private static CoreExtension newCoreExtension() {
@@ -342,12 +279,6 @@ public class CoreExtensionsInstallerTest {
 
   }
 
-  @Property(key = "westKey", name = "westName")
-  @WestSide
-  public static class WestSidePropertyDefinition {
-
-  }
-
   @Property(key = "eastKey", name = "eastName")
   @EastSide
   public static class EastSidePropertyDefinition {
@@ -360,13 +291,6 @@ public class CoreExtensionsInstallerTest {
 
   }
 
-  @Property(key = "latitudeKey", name = "latitudeName")
-  @WestSide
-  @EastSide
-  public static class LatitudePropertyDefinition {
-
-  }
-
   @Property(key = "blankKey", name = "blankName")
   public static class BlankPropertyDefinition {
 
diff --git a/sonar-core/src/test/java/org/sonar/core/language/LanguagesProviderTest.java b/sonar-core/src/test/java/org/sonar/core/language/LanguagesProviderTest.java
new file mode 100644 (file)
index 0000000..8bb931f
--- /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.core.language;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.Test;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+public class LanguagesProviderTest {
+
+  @Test
+  public void should_provide_default_instance_when_no_language() {
+    LanguagesProvider provider = new LanguagesProvider();
+    Languages languages = provider.provide(Optional.empty());
+
+    assertThat(languages).isNotNull();
+    assertThat(languages.all()).isEmpty();
+  }
+
+  @Test
+  public void should_provide_instance_when_languages() {
+    Language A = mock(Language.class);
+    when(A.getKey()).thenReturn("a");
+    Language B = mock(Language.class);
+    when(B.getKey()).thenReturn("b");
+
+    LanguagesProvider provider = new LanguagesProvider();
+    List<Language> languageList = Arrays.asList(A, B);
+    Languages languages = provider.provide(Optional.of(languageList));
+
+    assertThat(languages).isNotNull();
+    assertThat(languages.all())
+      .hasSize(2)
+      .contains(A, B);
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/ComponentContainerTest.java b/sonar-core/src/test/java/org/sonar/core/platform/ComponentContainerTest.java
deleted file mode 100644 (file)
index 4351938..0000000
+++ /dev/null
@@ -1,584 +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.core.platform;
-
-import java.io.Closeable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import org.junit.Test;
-import org.picocontainer.Startable;
-import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.Property;
-import org.sonar.api.config.PropertyDefinitions;
-
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-public class ComponentContainerTest {
-
-
-  @Test
-  public void shouldRegisterItself() {
-    ComponentContainer container = new ComponentContainer();
-    assertThat(container.getComponentByType(ComponentContainer.class)).isSameAs(container);
-  }
-
-  @Test
-  public void should_start_and_stop_component_extending_pico_Startable() {
-    ComponentContainer container = spy(new ComponentContainer());
-    container.addSingleton(StartableStoppableComponent.class);
-    container.startComponents();
-
-    assertThat(container.getComponentByType(StartableStoppableComponent.class).started).isTrue();
-    assertThat(container.getComponentByType(StartableStoppableComponent.class).stopped).isFalse();
-    verify(container).doBeforeStart();
-    verify(container).doAfterStart();
-
-    container.stopComponents();
-    assertThat(container.getComponentByType(StartableStoppableComponent.class).stopped).isTrue();
-  }
-
-  @Test
-  public void should_start_and_stop_component_extending_API_Startable() {
-    ComponentContainer container = spy(new ComponentContainer());
-    container.addSingleton(StartableStoppableApiComponent.class);
-    container.startComponents();
-
-    assertThat(container.getComponentByType(StartableStoppableApiComponent.class).started).isTrue();
-    assertThat(container.getComponentByType(StartableStoppableApiComponent.class).stopped).isFalse();
-    verify(container).doBeforeStart();
-    verify(container).doAfterStart();
-
-    container.stopComponents();
-    assertThat(container.getComponentByType(StartableStoppableApiComponent.class).stopped).isTrue();
-  }
-
-  @Test
-  public void should_not_start_and_stop_component_just_having_start_and_stop_method() {
-    ComponentContainer container = spy(new ComponentContainer());
-    container.addSingleton(ReflectionStartableStoppableComponent.class);
-    container.startComponents();
-
-    assertThat(container.getComponentByType(ReflectionStartableStoppableComponent.class).started).isFalse();
-    assertThat(container.getComponentByType(ReflectionStartableStoppableComponent.class).stopped).isFalse();
-    verify(container).doBeforeStart();
-    verify(container).doAfterStart();
-
-    container.stopComponents();
-    assertThat(container.getComponentByType(ReflectionStartableStoppableComponent.class).started).isFalse();
-    assertThat(container.getComponentByType(ReflectionStartableStoppableComponent.class).stopped).isFalse();
-  }
-
-  @Test
-  public void should_start_and_stop_hierarchy_of_containers() {
-    StartableStoppableComponent parentComponent = new StartableStoppableComponent();
-    final StartableStoppableComponent childComponent = new StartableStoppableComponent();
-    ComponentContainer parentContainer = new ComponentContainer() {
-      @Override
-      public void doAfterStart() {
-        ComponentContainer childContainer = new ComponentContainer(this);
-        childContainer.add(childComponent);
-        childContainer.execute();
-      }
-    };
-    parentContainer.add(parentComponent);
-    parentContainer.execute();
-    assertThat(parentComponent.started).isTrue();
-    assertThat(parentComponent.stopped).isTrue();
-    assertThat(childComponent.started).isTrue();
-    assertThat(childComponent.stopped).isTrue();
-  }
-
-  @Test
-  public void should_stop_hierarchy_of_containers_on_failure() {
-    StartableStoppableComponent parentComponent = new StartableStoppableComponent();
-    final StartableStoppableComponent childComponent1 = new StartableStoppableComponent();
-    final UnstartableComponent childComponent2 = new UnstartableComponent();
-    ComponentContainer parentContainer = new ComponentContainer() {
-      @Override
-      public void doAfterStart() {
-        ComponentContainer childContainer = new ComponentContainer(this);
-        childContainer.add(childComponent1);
-        childContainer.add(childComponent2);
-        childContainer.execute();
-      }
-    };
-    parentContainer.add(parentComponent);
-    try {
-      parentContainer.execute();
-      fail();
-    } catch (Exception e) {
-      assertThat(parentComponent.started).isTrue();
-      assertThat(parentComponent.stopped).isTrue();
-      assertThat(childComponent1.started).isTrue();
-      assertThat(childComponent1.stopped).isTrue();
-    }
-  }
-
-  @Test
-  public void testChild() {
-    ComponentContainer parent = new ComponentContainer();
-    parent.startComponents();
-
-    ComponentContainer child = parent.createChild();
-    child.addSingleton(StartableStoppableComponent.class);
-    child.startComponents();
-
-    assertThat(child.getParent()).isSameAs(parent);
-    assertThat(parent.getChildren()).containsOnly(child);
-    assertThat(child.getComponentByType(ComponentContainer.class)).isSameAs(child);
-    assertThat(parent.getComponentByType(ComponentContainer.class)).isSameAs(parent);
-    assertThat(child.getComponentByType(StartableStoppableComponent.class)).isNotNull();
-    assertThat(parent.getComponentByType(StartableStoppableComponent.class)).isNull();
-
-    parent.stopComponents();
-  }
-
-  @Test
-  public void testRemoveChild() {
-    ComponentContainer parent = new ComponentContainer();
-    parent.startComponents();
-
-    ComponentContainer child = parent.createChild();
-    assertThat(parent.getChildren()).containsOnly(child);
-
-    parent.removeChild(child);
-    assertThat(parent.getChildren()).isEmpty();
-  }
-
-  @Test
-  public void support_multiple_children() {
-    ComponentContainer parent = new ComponentContainer();
-    parent.startComponents();
-    ComponentContainer child1 = parent.createChild();
-    child1.startComponents();
-    ComponentContainer child2 = parent.createChild();
-    child2.startComponents();
-    assertThat(parent.getChildren()).containsOnly(child1, child2);
-
-    child1.stopComponents();
-    assertThat(parent.getChildren()).containsOnly(child2);
-
-    parent.stopComponents();
-    assertThat(parent.getChildren()).isEmpty();
-  }
-
-  @Test
-  public void shouldForwardStartAndStopToDescendants() {
-    ComponentContainer grandParent = new ComponentContainer();
-    ComponentContainer parent = grandParent.createChild();
-    ComponentContainer child = parent.createChild();
-    child.addSingleton(StartableStoppableComponent.class);
-
-    grandParent.startComponents();
-
-    StartableStoppableComponent component = child.getComponentByType(StartableStoppableComponent.class);
-    assertTrue(component.started);
-
-    parent.stopComponents();
-    assertTrue(component.stopped);
-  }
-
-  @Test
-  public void shouldDeclareComponentProperties() {
-    ComponentContainer container = new ComponentContainer();
-    container.addSingleton(ComponentWithProperty.class);
-
-    PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
-    assertThat(propertyDefinitions.get("foo")).isNotNull();
-    assertThat(propertyDefinitions.get("foo").defaultValue()).isEqualTo("bar");
-  }
-
-  @Test
-  public void shouldDeclareExtensionWithoutAddingIt() {
-    ComponentContainer container = new ComponentContainer();
-    PluginInfo plugin = mock(PluginInfo.class);
-    container.declareExtension(plugin, ComponentWithProperty.class);
-
-    PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
-    assertThat(propertyDefinitions.get("foo")).isNotNull();
-    assertThat(container.getComponentByType(ComponentWithProperty.class)).isNull();
-  }
-
-  @Test
-  public void shouldDeclareExtensionWhenAdding() {
-    ComponentContainer container = new ComponentContainer();
-    PluginInfo plugin = mock(PluginInfo.class);
-    container.addExtension(plugin, ComponentWithProperty.class);
-
-    PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
-    assertThat(propertyDefinitions.get("foo")).isNotNull();
-    assertThat(container.getComponentByType(ComponentWithProperty.class)).isNotNull();
-    assertThat(container.getComponentByKey(ComponentWithProperty.class)).isNotNull();
-  }
-
-  @Test
-  public void test_add_class() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(ComponentWithProperty.class, SimpleComponent.class);
-    assertThat(container.getComponentByType(ComponentWithProperty.class)).isNotNull();
-    assertThat(container.getComponentByType(SimpleComponent.class)).isNotNull();
-  }
-
-  @Test
-  public void test_add_collection() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(Arrays.asList(ComponentWithProperty.class, SimpleComponent.class));
-    assertThat(container.getComponentByType(ComponentWithProperty.class)).isNotNull();
-    assertThat(container.getComponentByType(SimpleComponent.class)).isNotNull();
-  }
-
-  @Test
-  public void test_add_adapter() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(new SimpleComponentProvider());
-    assertThat(container.getComponentByType(SimpleComponent.class)).isNotNull();
-  }
-
-  @Test
-  public void should_sanitize_pico_exception_on_start_failure() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(UnstartableComponent.class);
-
-    // do not expect a PicoException
-    assertThatThrownBy(container::startComponents)
-      .isInstanceOf(IllegalStateException.class);
-  }
-
-  @Test
-  public void display_plugin_name_when_failing_to_add_extension() {
-    ComponentContainer container = new ComponentContainer();
-    PluginInfo plugin = mock(PluginInfo.class);
-
-    container.startComponents();
-
-    assertThatThrownBy(() -> container.addExtension(plugin, UnstartableComponent.class))
-      .isInstanceOf(IllegalStateException.class)
-      .hasMessageContaining("Unable to register extension org.sonar.core.platform.ComponentContainerTest$UnstartableComponent");
-  }
-
-  @Test
-  public void test_start_failure() {
-    ComponentContainer container = new ComponentContainer();
-    StartableStoppableComponent startable = new StartableStoppableComponent();
-    container.add(startable, UnstartableComponent.class);
-
-    try {
-      container.execute();
-      fail();
-    } catch (Exception e) {
-      assertThat(startable.started).isTrue();
-
-      // container stops the components that have already been started
-      assertThat(startable.stopped).isTrue();
-    }
-  }
-
-  @Test
-  public void stop_container_does_not_fail_and_all_stoppable_components_are_stopped_even_if_one_or_more_stop_method_call_fail() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(FailingStopWithISEComponent.class, FailingStopWithISEComponent2.class, FailingStopWithErrorComponent.class, FailingStopWithErrorComponent2.class);
-    container.startComponents();
-    StartableStoppableComponent[] components = {
-      container.getComponentByType(FailingStopWithISEComponent.class),
-      container.getComponentByType(FailingStopWithISEComponent2.class),
-      container.getComponentByType(FailingStopWithErrorComponent.class),
-      container.getComponentByType(FailingStopWithErrorComponent2.class)
-    };
-
-    container.stopComponents();
-
-    Arrays.stream(components).forEach(startableComponent -> assertThat(startableComponent.stopped).isTrue());
-  }
-
-  @Test
-  public void stop_container_stops_all_stoppable_components_even_in_case_of_OOM_in_any_stop_method() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(FailingStopWithOOMComponent.class, FailingStopWithOOMComponent2.class);
-    container.startComponents();
-    StartableStoppableComponent[] components = {
-      container.getComponentByType(FailingStopWithOOMComponent.class),
-      container.getComponentByType(FailingStopWithOOMComponent2.class)
-    };
-
-    container.stopComponents();
-
-    assertThat(container.getPicoContainer().getLifecycleState().isDisposed()).isTrue();
-    Arrays.stream(components).forEach(cpt -> assertThat(cpt.stopped).isTrue());
-  }
-
-  @Test
-  public void stop_exception_should_not_hide_start_exception() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(UnstartableComponent.class, FailingStopWithISEComponent.class);
-
-    assertThatThrownBy(container::execute)
-      .isInstanceOf(IllegalStateException.class)
-      .hasMessage("Fail to start");
-  }
-
-  @Test
-  public void stop_exceptionin_API_component_should_not_hide_start_exception() {
-    ComponentContainer container = new ComponentContainer();
-    container.add(UnstartableApiComponent.class, FailingStopWithISEComponent.class);
-
-    assertThatThrownBy(container::execute)
-      .isInstanceOf(IllegalStateException.class)
-      .hasMessage("Fail to start");
-  }
-
-  @Test
-  public void should_execute_components() {
-    ComponentContainer container = new ComponentContainer();
-    StartableStoppableComponent component = new StartableStoppableComponent();
-    container.add(component);
-
-    container.execute();
-
-    assertThat(component.started).isTrue();
-    assertThat(component.stopped).isTrue();
-  }
-
-  /**
-   * Method close() must be called even if the methods start() or stop()
-   * are not defined.
-   */
-  @Test
-  public void should_close_components_without_lifecycle() {
-    ComponentContainer container = new ComponentContainer();
-    CloseableComponent component = new CloseableComponent();
-    container.add(component);
-
-    container.execute();
-
-    assertThat(component.isClosed).isTrue();
-  }
-
-  /**
-   * Method close() must be executed after stop()
-   */
-  @Test
-  public void should_close_Closeable_components_with_lifecycle() {
-    ComponentContainer container = new ComponentContainer();
-    StartableCloseableComponent component = new StartableCloseableComponent();
-    container.add(component);
-
-    container.execute();
-
-    assertThat(component.isStopped).isTrue();
-    assertThat(component.isClosed).isTrue();
-    assertThat(component.isClosedAfterStop).isTrue();
-  }
-
-  /**
-   * Method close() must be executed after stop()
-   */
-  @Test
-  public void should_close_AutoCloseable_components_with_lifecycle() {
-    ComponentContainer container = new ComponentContainer();
-    StartableAutoCloseableComponent component = new StartableAutoCloseableComponent();
-    container.add(component);
-
-    container.execute();
-
-    assertThat(component.isStopped).isTrue();
-    assertThat(component.isClosed).isTrue();
-    assertThat(component.isClosedAfterStop).isTrue();
-  }
-
-  public static class StartableStoppableComponent implements Startable {
-    public boolean started = false;
-    public boolean stopped = false;
-
-    @Override
-    public void start() {
-      started = true;
-    }
-
-    @Override
-    public void stop() {
-      stopped = true;
-    }
-  }
-
-  public static class StartableStoppableApiComponent implements org.sonar.api.Startable {
-    public boolean started = false;
-    public boolean stopped = false;
-
-    @Override
-    public void start() {
-      started = true;
-    }
-
-    @Override
-    public void stop() {
-      stopped = true;
-    }
-  }
-
-  public static class ReflectionStartableStoppableComponent {
-    public boolean started = false;
-    public boolean stopped = false;
-
-    public void start() {
-      started = true;
-    }
-
-    public void stop() {
-      stopped = true;
-    }
-  }
-
-  public static class UnstartableComponent implements Startable {
-    @Override
-    public void start() {
-      throw new IllegalStateException("Fail to start");
-    }
-
-    @Override
-    public void stop() {
-
-    }
-  }
-
-  public static class UnstartableApiComponent implements org.sonar.api.Startable {
-    @Override
-    public void start() {
-      throw new IllegalStateException("Fail to start");
-    }
-
-    @Override
-    public void stop() {
-
-    }
-  }
-
-  public static class FailingStopWithISEComponent extends StartableStoppableComponent {
-    public void stop() {
-      super.stop();
-      throw new IllegalStateException("Faking IllegalStateException thrown by stop method of " + getClass().getSimpleName());
-    }
-  }
-
-  public static class FailingStopWithISEComponent2 extends FailingStopWithErrorComponent {
-  }
-
-  public static class FailingStopWithErrorComponent extends StartableStoppableComponent {
-    public void stop() {
-      super.stop();
-      throw new Error("Faking Error thrown by stop method of " + getClass().getSimpleName());
-    }
-  }
-
-  public static class FailingStopWithErrorComponent2 extends FailingStopWithErrorComponent {
-  }
-
-  public static class FailingStopWithOOMComponent extends StartableStoppableComponent {
-    public void stop() {
-      super.stop();
-      consumeAvailableMemory();
-    }
-
-    private static List<Object> consumeAvailableMemory() {
-      List<Object> holder = new ArrayList<>();
-      while (true) {
-        holder.add(new byte[128 * 1024]);
-      }
-    }
-  }
-
-  public static class FailingStopWithOOMComponent2 extends FailingStopWithOOMComponent {
-
-  }
-
-  @Property(key = "foo", defaultValue = "bar", name = "Foo")
-  public static class ComponentWithProperty {
-
-  }
-
-  public static class SimpleComponent {
-
-  }
-
-  public static class SimpleComponentProvider extends ProviderAdapter {
-    public SimpleComponent provide() {
-      return new SimpleComponent();
-    }
-  }
-
-  public static class CloseableComponent implements AutoCloseable {
-    public boolean isClosed = false;
-
-    @Override
-    public void close() {
-      isClosed = true;
-    }
-  }
-
-  public static class StartableAutoCloseableComponent implements Startable,AutoCloseable {
-    public boolean isClosed = false;
-    public boolean isStopped = false;
-    public boolean isClosedAfterStop = false;
-
-    @Override
-    public void start() {
-      // nothing to do
-    }
-
-    @Override
-    public void stop() {
-      isStopped = true;
-    }
-
-    @Override
-    public void close() {
-      isClosed = true;
-      isClosedAfterStop = isStopped;
-    }
-  }
-
-  public static class StartableCloseableComponent implements Startable, Closeable {
-    public boolean isClosed = false;
-    public boolean isStopped = false;
-    public boolean isClosedAfterStop = false;
-
-    @Override
-    public void start() {
-      // nothing to do
-    }
-
-    @Override
-    public void stop() {
-      isStopped = true;
-    }
-
-    @Override
-    public void close() {
-      isClosed = true;
-      isClosedAfterStop = isStopped;
-    }
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/LazyUnlessStartableStrategyTest.java b/sonar-core/src/test/java/org/sonar/core/platform/LazyUnlessStartableStrategyTest.java
new file mode 100644 (file)
index 0000000..8279e94
--- /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.core.platform;
+
+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 LazyUnlessStartableStrategyTest {
+  private final LazyUnlessStartableStrategy postProcessor = new LazyUnlessStartableStrategy();
+
+  @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();
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/ListContainerTest.java b/sonar-core/src/test/java/org/sonar/core/platform/ListContainerTest.java
new file mode 100644 (file)
index 0000000..00741c8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.Arrays;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+public class ListContainerTest {
+
+  @Test
+  public void register_beans() {
+    ListContainer container = new ListContainer();
+    container.add(
+      A.class,
+      new VirtualModule(),
+      Arrays.asList(C.class, D.class)
+    );
+    assertThat(container.getAddedObjects()).contains(A.class, B.class, C.class, D.class);
+  }
+
+  @Test
+  public void addExtension_register_beans() {
+    ListContainer container = new ListContainer();
+    container
+      .addExtension("A", A.class)
+      .addExtension("B", B.class);
+    assertThat(container.getAddedObjects()).contains(A.class, B.class);
+  }
+
+  @Test
+  public void declareExtension_does_nothing() {
+    ListContainer container = new ListContainer();
+    assertThatNoException().isThrownBy(() -> container
+      .declareExtension("A", A.class)
+      .declareExtension(mock(PluginInfo.class), B.class));
+  }
+
+  @Test
+  public void unsupported_method_should_throw_exception() {
+    ListContainer container = new ListContainer();
+    container.add(A.class);
+    assertThatThrownBy(() -> container.getComponentByType(A.class)).isInstanceOf(UnsupportedOperationException.class);
+    assertThatThrownBy(() -> container.getOptionalComponentByType(A.class)).isInstanceOf(UnsupportedOperationException.class);
+    assertThatThrownBy(() -> container.getComponentsByType(A.class)).isInstanceOf(UnsupportedOperationException.class);
+    assertThatThrownBy(container::getParent).isInstanceOf(UnsupportedOperationException.class);
+  }
+
+  class A {
+  }
+
+  class B {
+  }
+
+  class C {
+  }
+
+  class D {
+  }
+
+  class VirtualModule extends Module {
+
+    @Override protected void configureModule() {
+      add(B.class);
+    }
+  }
+
+}
index df50374a0cd4ddb1bfa2d73ecbc826f9150ff410..9a2bdaf24264dc99d11a14f3e704df7c7e132850 100644 (file)
@@ -24,8 +24,7 @@ import org.junit.Test;
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class ModuleTest {
-  ComponentContainer container = new ComponentContainer();
-  int initialSize = sizeOf(container);
+  private final ListContainer container = new ListContainer();
 
   @Test(expected = NullPointerException.class)
   public void configure_throws_NPE_if_container_is_empty() {
@@ -46,7 +45,7 @@ public class ModuleTest {
       }
     }.configure(container);
 
-    assertThat(sizeOf(container)).isSameAs(initialSize);
+    assertThat(container.getAddedObjects()).isEmpty();
   }
 
   @Test
@@ -58,7 +57,7 @@ public class ModuleTest {
       }
     }.configure(container);
 
-    assertThat(sizeOf(container)).isEqualTo(initialSize);
+    assertThat(container.getAddedObjects()).isEmpty();
   }
 
   @Test
@@ -70,10 +69,10 @@ public class ModuleTest {
       }
     }.configure(container);
 
-    assertThat(sizeOf(container)).isEqualTo(initialSize + 2);
+    assertThat(container.getAddedObjects()).hasSize(2);
   }
 
-  private static int sizeOf(ComponentContainer container) {
-    return container.getPicoContainer().getComponentAdapters().size();
+  private static int sizeOf(SpringComponentContainer container) {
+    return container.context.getBeanDefinitionCount();
   }
 }
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/PicoUtilsTest.java b/sonar-core/src/test/java/org/sonar/core/platform/PicoUtilsTest.java
deleted file mode 100644 (file)
index e21dd7a..0000000
+++ /dev/null
@@ -1,100 +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.core.platform;
-
-import java.lang.reflect.Method;
-import org.junit.Test;
-import org.picocontainer.Characteristics;
-import org.picocontainer.MutablePicoContainer;
-import org.picocontainer.PicoLifecycleException;
-import org.picocontainer.Startable;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-
-public class PicoUtilsTest {
-
-  @Test
-  public void shouldSanitizePicoLifecycleException() throws NoSuchMethodException {
-    UncheckedFailureComponent instance = new UncheckedFailureComponent();
-    Method method = UncheckedFailureComponent.class.getMethod("start");
-    try {
-      instance.start();
-      fail("Start should have thrown a IllegalStateException");
-    }
-    catch (IllegalStateException e) {
-      Throwable th = PicoUtils.sanitize(new PicoLifecycleException(method, instance, e));
-
-      assertThat(th).isInstanceOf(IllegalStateException.class);
-      assertThat(th.getMessage()).isEqualTo("A good reason to fail");
-    }
-  }
-
-  @Test
-  public void shouldSanitizePicoLifecycleException_no_wrapper_message() {
-    Throwable th = PicoUtils.sanitize(new PicoLifecycleException(null, null, new IllegalStateException("msg")));
-
-    assertThat(th).isInstanceOf(IllegalStateException.class);
-    assertThat(th.getMessage()).isEqualTo("msg");
-  }
-
-  @Test
-  public void shouldNotSanitizeOtherExceptions() {
-    Throwable th = PicoUtils.sanitize(new IllegalArgumentException("foo"));
-
-    assertThat(th).isInstanceOf(IllegalArgumentException.class);
-    assertThat(th.getMessage()).isEqualTo("foo");
-  }
-
-  @Test
-  public void shouldPropagateInitialUncheckedException() {
-    try {
-      PicoUtils.propagate(newPicoLifecycleException());
-      fail();
-    } catch (RuntimeException e) {
-      assertThat(e).isInstanceOf(IllegalStateException.class);
-    }
-  }
-
-
-  private PicoLifecycleException newPicoLifecycleException() {
-    MutablePicoContainer container = ComponentContainer.createPicoContainer().as(Characteristics.CACHE);
-    container.addComponent(UncheckedFailureComponent.class);
-    try {
-      container.start();
-      throw new IllegalStateException("An exception should have been thrown by start()");
-
-    } catch (PicoLifecycleException e) {
-      return e;
-    }
-  }
-
-  public static class UncheckedFailureComponent implements Startable {
-    public void start() {
-      throw new IllegalStateException("A good reason to fail");
-    }
-
-    @Override
-    public void stop() {
-      // nothing to do
-    }
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/PriorityBeanFactoryTest.java b/sonar-core/src/test/java/org/sonar/core/platform/PriorityBeanFactoryTest.java
new file mode 100644 (file)
index 0000000..70f7fd8
--- /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.core.platform;
+
+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 {
+
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/SpringComponentContainerTest.java b/sonar-core/src/test/java/org/sonar/core/platform/SpringComponentContainerTest.java
new file mode 100644 (file)
index 0000000..64be7c3
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * 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.Arrays;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import org.junit.Test;
+import org.sonar.api.Property;
+import org.sonar.api.Startable;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.config.PropertyDefinitions;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+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).isOne();
+    assertThat(startStop.stop).isOne();
+  }
+
+  @Test
+  public void add_registers_instance_with_toString() {
+    SpringComponentContainer container = new SimpleContainer(new ToString("a"), new ToString("b"));
+    container.startComponents();
+    assertThat(container.context.getBeanDefinitionNames())
+      .contains(
+        this.getClass().getClassLoader() + "-org.sonar.core.platform.SpringComponentContainerTest.ToString-a",
+        this.getClass().getClassLoader() + "-org.sonar.core.platform.SpringComponentContainerTest.ToString-b");
+    assertThat(container.getComponentsByType(ToString.class)).hasSize(2);
+  }
+
+  @Test
+  public void add_registers_class_with_classloader_and_fqcn() {
+    SpringComponentContainer container = new SimpleContainer(A.class, B.class);
+    container.startComponents();
+    assertThat(container.context.getBeanDefinitionNames())
+      .contains(
+        this.getClass().getClassLoader() + "-org.sonar.core.platform.SpringComponentContainerTest.A",
+        this.getClass().getClassLoader() + "-org.sonar.core.platform.SpringComponentContainerTest.B");
+    assertThat(container.getComponentByType(A.class)).isNotNull();
+    assertThat(container.getComponentByType(B.class)).isNotNull();
+  }
+
+  @Test
+  public void add_configures_module_instances() {
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.add(new TestModule());
+    container.startComponents();
+    assertThat(container.getComponentByType(A.class)).isNotNull();
+  }
+
+  @Test
+  public void get_optional_component_by_type_should_return_correctly() {
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.add(A.class);
+    container.startComponents();
+    assertThat(container.getOptionalComponentByType(A.class)).containsInstanceOf(A.class);
+    assertThat(container.getOptionalComponentByType(B.class)).isEmpty();
+  }
+
+  @Test
+  public void createChild_method_should_spawn_a_child_container(){
+    SpringComponentContainer parent = new SpringComponentContainer();
+    SpringComponentContainer child = parent.createChild();
+    assertThat(child).isNotEqualTo(parent);
+    assertThat(child.parent).isEqualTo(parent);
+    assertThat(parent.children).contains(child);
+  }
+
+  @Test
+  public void get_component_by_type_should_throw_exception_when_type_does_not_exist() {
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.add(A.class);
+    container.startComponents();
+    assertThatThrownBy(() -> container.getComponentByType(B.class))
+      .isInstanceOf(IllegalStateException.class)
+      .hasMessage("Unable to load component class org.sonar.core.platform.SpringComponentContainerTest$B");
+  }
+
+  @Test
+  public void add_fails_if_adding_module_class() {
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.startComponents();
+    assertThatThrownBy(() -> container.add(TestModule.class))
+      .hasMessage("Modules should be added as instances")
+      .isInstanceOf(IllegalStateException.class);
+  }
+
+  @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 addExtension_supports_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 addExtension_supports_extension_instances_without_annotations() {
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.addExtension("", new ExtensionWithMultipleConstructorsAndNoAnnotations(new A()));
+    container.startComponents();
+    assertThat(container.getComponentByType(ExtensionWithMultipleConstructorsAndNoAnnotations.class)).isNotNull();
+  }
+
+  @Test
+  public void addExtension_resolves_iterables() {
+    List<Class<?>> classes = Arrays.asList(A.class, B.class);
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.addExtension("", classes);
+    container.startComponents();
+    assertThat(container.getComponentByType(A.class)).isNotNull();
+    assertThat(container.getComponentByType(B.class)).isNotNull();
+  }
+
+  @Test
+  public void addExtension_adds_property_with_PluginInfo() {
+    PluginInfo info = new PluginInfo("plugin1").setName("plugin1");
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.addExtension(info, A.class);
+
+    container.startComponents();
+    PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
+    PropertyDefinition propertyDefinition = propertyDefinitions.get("k");
+    assertThat(propertyDefinition.key()).isEqualTo("k");
+    assertThat(propertyDefinitions.getCategory("k")).isEqualTo("plugin1");
+  }
+
+  @Test
+  public void declareExtension_adds_property() {
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.addExtension((PluginInfo) null, A.class);
+
+    container.startComponents();
+    PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
+    PropertyDefinition propertyDefinition = propertyDefinitions.get("k");
+    assertThat(propertyDefinition.key()).isEqualTo("k");
+    assertThat(propertyDefinitions.getCategory("k")).isEmpty();
+  }
+
+  @Test
+  public void stop_should_stop_children() {
+    SpringComponentContainer parent = new SpringComponentContainer();
+    ApiStartable s1 = new ApiStartable();
+    parent.add(s1);
+    parent.startComponents();
+    SpringComponentContainer child = new SpringComponentContainer(parent);
+    assertThat(child.getParent()).isEqualTo(parent);
+    assertThat(parent.children).containsOnly(child);
+    ApiStartable s2 = new ApiStartable();
+    child.add(s2);
+    child.startComponents();
+
+    parent.stopComponents();
+    assertThat(s1.stop).isOne();
+    assertThat(s2.stop).isOne();
+  }
+
+  @Test
+  public void stop_should_remove_container_from_parent() {
+    SpringComponentContainer parent = new SpringComponentContainer();
+    SpringComponentContainer child = new SpringComponentContainer(parent);
+    assertThat(parent.children).containsOnly(child);
+    child.stopComponents();
+    assertThat(parent.children).isEmpty();
+  }
+
+  @Test
+  public void bean_create_fails_if_class_has_default_constructor_and_other_constructors() {
+    SpringComponentContainer container = new SpringComponentContainer();
+    container.add(ClassWithMultipleConstructorsIncNoArg.class);
+    container.startComponents();
+    assertThatThrownBy(() -> container.getComponentByType(ClassWithMultipleConstructorsIncNoArg.class))
+      .hasRootCauseMessage("Constructor annotations missing in: class org.sonar.core.platform.SpringComponentContainerTest$ClassWithMultipleConstructorsIncNoArg");
+  }
+
+  @Test
+  public void support_start_stop_callbacks() {
+    JsrLifecycleCallbacks jsr = new JsrLifecycleCallbacks();
+    ApiStartable api = new ApiStartable();
+    AutoClose closeable = new AutoClose();
+
+    SpringComponentContainer container = new SimpleContainer(jsr, api, closeable) {
+      @Override
+      public void doAfterStart() {
+        // force lazy instantiation
+        getComponentByType(JsrLifecycleCallbacks.class);
+        getComponentByType(ApiStartable.class);
+        getComponentByType(AutoClose.class);
+      }
+    };
+    container.execute();
+
+    assertThat(closeable.closed).isOne();
+    assertThat(jsr.postConstruct).isOne();
+    assertThat(jsr.preDestroy).isOne();
+    assertThat(api.start).isOne();
+    assertThat(api.stop).isOne();
+  }
+
+  private static class TestModule extends Module {
+    @Override
+    protected void configureModule() {
+      add(A.class);
+    }
+  }
+
+  private static class JsrLifecycleCallbacks {
+    private int postConstruct = 0;
+    private int preDestroy = 0;
+
+    @PostConstruct
+    public void postConstruct() {
+      postConstruct++;
+    }
+
+    @PreDestroy
+    public void preDestroy() {
+      preDestroy++;
+    }
+  }
+
+  private static class AutoClose implements AutoCloseable {
+    private int closed = 0;
+
+    @Override
+    public void close() {
+      closed++;
+    }
+  }
+
+  private static class ApiStartable implements Startable {
+    private int start = 0;
+    private int stop = 0;
+
+    public void start() {
+      start++;
+    }
+
+    public void stop() {
+      stop++;
+    }
+  }
+
+  private static class ToString {
+    private final String toString;
+
+    public ToString(String toString) {
+      this.toString = toString;
+    }
+
+    @Override
+    public String toString() {
+      return toString;
+    }
+  }
+
+  @Property(key = "k", name = "name")
+  private static class A {
+  }
+
+  private static class B {
+  }
+
+  private static class ClassWithMultipleConstructorsIncNoArg {
+    public ClassWithMultipleConstructorsIncNoArg() {
+    }
+
+    public ClassWithMultipleConstructorsIncNoArg(A a) {
+    }
+  }
+
+  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-core/src/test/java/org/sonar/core/platform/StartableBeanPostProcessorTest.java b/sonar-core/src/test/java/org/sonar/core/platform/StartableBeanPostProcessorTest.java
new file mode 100644 (file)
index 0000000..2103fca
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 org.junit.Test;
+import org.sonar.api.Startable;
+
+import static org.assertj.core.api.Assertions.assertThat;
+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_api_startable() {
+    Startable startable = mock(Startable.class);
+    underTest.postProcessBeforeInitialization(startable, "startable");
+    verify(startable).start();
+    verifyNoMoreInteractions(startable);
+  }
+
+  @Test
+  public void stops_api_startable() {
+    Startable startable = mock(Startable.class);
+    underTest.postProcessBeforeDestruction(startable, "startable");
+    verify(startable).stop();
+    verifyNoMoreInteractions(startable);
+  }
+
+  @Test
+  public void startable_and_autoCloseable_should_require_destruction(){
+    assertThat(underTest.requiresDestruction(mock(Startable.class))).isTrue();
+    assertThat(underTest.requiresDestruction(mock(org.sonar.api.Startable.class))).isTrue();
+    assertThat(underTest.requiresDestruction(mock(Object.class))).isFalse();
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/StartableCloseableSafeLifecyleStrategyTest.java b/sonar-core/src/test/java/org/sonar/core/platform/StartableCloseableSafeLifecyleStrategyTest.java
deleted file mode 100644 (file)
index 3f8b427..0000000
+++ /dev/null
@@ -1,218 +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.core.platform;
-
-import java.io.Closeable;
-import java.io.IOException;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.Startable;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-public class StartableCloseableSafeLifecyleStrategyTest {
-  @Rule
-  public LogTester logTester = new LogTester();
-
-  private StartableCloseableSafeLifecyleStrategy underTest = new StartableCloseableSafeLifecyleStrategy();
-
-  @Test
-  public void start_calls_start_on_Startable_subclass() {
-    Startable startable = mock(Startable.class);
-
-    underTest.start(startable);
-
-    verify(startable).start();
-    verifyNoMoreInteractions(startable);
-  }
-
-  @Test
-  public void start_calls_start_on_api_Startable_subclass() {
-    org.picocontainer.Startable startable = mock(org.picocontainer.Startable.class);
-
-    underTest.start(startable);
-
-    verify(startable).start();
-    verifyNoMoreInteractions(startable);
-  }
-
-  @Test
-  public void start_does_not_call_stop_on_class_with_method_start_not_implementing_startable() {
-    Object startable = spy(new Object() {
-      public void start() {
-        // nothing to do
-      }
-    });
-
-    underTest.start(startable);
-
-    verifyNoMoreInteractions(startable);
-  }
-
-  @Test
-  public void stop_calls_stop_on_Startable_subclass() {
-    Startable startable = mock(Startable.class);
-
-    underTest.stop(startable);
-
-    verify(startable).stop();
-    verifyNoMoreInteractions(startable);
-  }
-
-  @Test
-  public void stop_calls_stop_on_api_Startable_subclass() {
-    org.picocontainer.Startable startable = mock(org.picocontainer.Startable.class);
-
-    underTest.stop(startable);
-
-    verify(startable).stop();
-    verifyNoMoreInteractions(startable);
-  }
-
-  @Test
-  public void stop_does_not_call_stop_on_class_with_method_stop_not_implementing_startable() {
-    Object startable = spy(new Object() {
-      public void stop() {
-        // nothing to do
-      }
-    });
-
-    underTest.stop(startable);
-
-    verifyNoMoreInteractions(startable);
-  }
-
-  @Test
-  public void dispose_calls_close_on_Closeable_subclass() throws IOException {
-    Closeable closeable = mock(Closeable.class);
-
-    underTest.dispose(closeable);
-
-    verify(closeable).close();
-    verifyNoMoreInteractions(closeable);
-  }
-
-  @Test
-  public void dispose_calls_close_on_AutoCloseable_subclass() throws Exception {
-    AutoCloseable autoCloseable = mock(AutoCloseable.class);
-
-    underTest.dispose(autoCloseable);
-
-    verify(autoCloseable).close();
-    verifyNoMoreInteractions(autoCloseable);
-  }
-
-  @Test
-  public void dispose_does_not_call_close_on_class_with_method_close_not_implementing_Closeable_nor_AutoCloseable() {
-    Object closeable = spy(new Object() {
-      public void close() {
-        // nothing to do
-      }
-    });
-
-    underTest.dispose(closeable);
-
-    verifyNoMoreInteractions(closeable);
-  }
-
-  @Test
-  public void hasLifecycle_returns_true_on_Startable_and_subclass() {
-    Startable startable = mock(Startable.class);
-
-    assertThat(underTest.hasLifecycle(Startable.class)).isTrue();
-    assertThat(underTest.hasLifecycle(startable.getClass())).isTrue();
-  }
-
-  @Test
-  public void hasLifecycle_returns_true_on_api_Startable_and_subclass() {
-    org.picocontainer.Startable startable = mock(org.picocontainer.Startable.class);
-
-    assertThat(underTest.hasLifecycle(org.picocontainer.Startable.class)).isTrue();
-    assertThat(underTest.hasLifecycle(startable.getClass())).isTrue();
-  }
-
-  @Test
-  public void hasLifecycle_returns_true_on_api_Closeable_and_subclass() {
-    Closeable closeable = mock(Closeable.class);
-
-    assertThat(underTest.hasLifecycle(Closeable.class)).isTrue();
-    assertThat(underTest.hasLifecycle(closeable.getClass())).isTrue();
-  }
-
-  @Test
-  public void hasLifecycle_returns_true_on_api_AutoCloseable_and_subclass() {
-    AutoCloseable autoCloseable = mock(AutoCloseable.class);
-
-    assertThat(underTest.hasLifecycle(AutoCloseable.class)).isTrue();
-    assertThat(underTest.hasLifecycle(autoCloseable.getClass())).isTrue();
-  }
-
-  @Test
-  public void hasLifeCycle_returns_false_and_log_a_warning_for_type_defining_start_without_implementating_Startable() {
-    Object startable = new Object() {
-      public void start() {
-        // nothing to do
-      }
-    };
-
-    assertThat(underTest.hasLifecycle(startable.getClass())).isFalse();
-    verifyWarnLog(startable.getClass());
-  }
-
-  @Test
-  public void hasLifeCycle_returns_false_and_log_a_warning_for_type_defining_stop_without_implementating_Startable() {
-    Object startable = new Object() {
-      public void stop() {
-        // nothing to do
-      }
-    };
-
-    assertThat(underTest.hasLifecycle(startable.getClass())).isFalse();
-    verifyWarnLog(startable.getClass());
-  }
-
-  private void verifyWarnLog(Class<?> type) {
-    assertThat(logTester.logs()).hasSize(1);
-    assertThat(logTester.logs(LoggerLevel.WARN))
-      .contains("Component of type class " + type.getName() + " defines methods start() and/or stop(). Neither will be invoked to start/stop the component. " +
-        "Please implement either org.picocontainer.Startable or org.sonar.api.Startable");
-  }
-
-  @Test
-  public void hasLifeCycle_returns_false_and_log_a_warning_for_type_defining_close_without_implementating_Closeable_nor_AutoCloseable() {
-    Object startable = new Object() {
-      public void close() {
-        // nothing to do
-      }
-    };
-
-    assertThat(underTest.hasLifecycle(startable.getClass())).isFalse();
-    assertThat(logTester.logs()).hasSize(1);
-    assertThat(logTester.logs(LoggerLevel.WARN))
-      .contains("Component of type class " + startable.getClass().getName() + " defines method close(). It won't be invoked to dispose the component. " +
-        "Please implement either java.io.Closeable or java.lang.AutoCloseable");
-  }
-}
index d550fbadc1c2291d0e87d63c4051bb717f6f3033..122cc43c79da02f303eaf981eeb57fdcc843675c 100644 (file)
  */
 package org.sonar.api.resources;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
 import org.apache.commons.lang.ArrayUtils;
 import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.scanner.ScannerSide;
@@ -32,6 +26,13 @@ import org.sonar.api.server.ServerSide;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  * A class to store the list of languages
  *
index f3fa9ffdad96c3448ce26dadfe3a6c6fa705532f..3aa87f8962bb3505644d9759ff989a3374118058 100644 (file)
@@ -29,7 +29,6 @@ dependencies {
   compile 'javax.annotation:javax.annotation-api'
   compile 'org.eclipse.jgit:org.eclipse.jgit'
   compile 'org.tmatesoft.svnkit:svnkit'
-  compile 'org.picocontainer:picocontainer'
   compile 'org.slf4j:jcl-over-slf4j'
   compile 'org.slf4j:jul-to-slf4j'
   compile 'org.slf4j:log4j-over-slf4j'
@@ -60,7 +59,6 @@ dependencies {
   testCompile 'org.mockito:mockito-core'
   testCompile project(':plugins:sonar-xoo-plugin')
   testCompile project(':sonar-plugin-api').sourceSets.test.output
-
 }
 
 license {
index 753a6f3b711cd6d30a45ddf2030553bd9ce41ff8..8bc4ec75ce52bed3c26388ff284eff4146a65677 100644 (file)
@@ -30,7 +30,7 @@ import org.springframework.context.annotation.Bean;
 public class AnalysisTempFolderProvider {
   static final String TMP_NAME = ".sonartmp";
 
-  @Bean("TempFolder")
+  @Bean("AnalysisTempFolder")
   public TempFolder provide(DefaultInputProject project) {
     Path workingDir = project.getWorkDir();
     Path tempDir = workingDir.normalize().resolve(TMP_NAME);
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
deleted file mode 100644 (file)
index 0743b81..0000000
+++ /dev/null
@@ -1,62 +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.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 4cc825c19300a37ea9e0ec30dca4456800401e3a..7eb63a5b9a081e67603987dab01bbaacf8d53d15 100644 (file)
  */
 package org.sonar.scanner.bootstrap;
 
-import java.io.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.concurrent.TimeUnit;
 import org.apache.commons.lang.StringUtils;
 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 static org.sonar.core.util.FileUtils.deleteQuietly;
 import org.springframework.context.annotation.Bean;
 
-import static org.sonar.core.util.FileUtils.deleteQuietly;
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.concurrent.TimeUnit;
 
-public class GlobalTempFolderProvider implements Startable {
+public class GlobalTempFolderProvider {
   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 System2 system;
-  private DefaultTempFolder tempFolder;
 
   public GlobalTempFolderProvider() {
     this(new System2());
@@ -54,26 +52,24 @@ public class GlobalTempFolderProvider implements Startable {
     this.system = system;
   }
 
-  @Bean("TempFolder")
+  @Bean("GlobalTempFolder")
   public TempFolder provide(ScannerProperties scannerProps) {
-    if (tempFolder == null) {
 
-      String workingPathName = StringUtils.defaultIfBlank(scannerProps.property(CoreProperties.GLOBAL_WORKING_DIRECTORY), CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE);
-      Path workingPath = Paths.get(workingPathName);
+    String workingPathName = StringUtils.defaultIfBlank(scannerProps.property(CoreProperties.GLOBAL_WORKING_DIRECTORY), CoreProperties.GLOBAL_WORKING_DIRECTORY_DEFAULT_VALUE);
+    Path workingPath = Paths.get(workingPathName);
 
-      if (!workingPath.isAbsolute()) {
-        Path home = findSonarHome(scannerProps);
-        workingPath = home.resolve(workingPath).normalize();
-      }
-      try {
-        cleanTempFolders(workingPath);
-      } catch (IOException e) {
-        LOG.error(String.format("failed to clean global working directory: %s", workingPath), e);
-      }
-      Path tempDir = createTempFolder(workingPath);
-      tempFolder = new DefaultTempFolder(tempDir.toFile(), true);
+    if (!workingPath.isAbsolute()) {
+      Path home = findSonarHome(scannerProps);
+      workingPath = home.resolve(workingPath).normalize();
     }
-    return tempFolder;
+    try {
+      cleanTempFolders(workingPath);
+    } catch (IOException e) {
+      LOG.error(String.format("failed to clean global working directory: %s", workingPath), e);
+    }
+    Path tempDir = createTempFolder(workingPath);
+    return new DefaultTempFolder(tempDir.toFile(), true);
+
   }
 
   private static Path createTempFolder(Path workingPath) {
@@ -148,15 +144,4 @@ public class GlobalTempFolderProvider implements Startable {
     }
   }
 
-  @Override
-  public void start() {
-    // nothing to do
-  }
-
-  @Override
-  public void stop() {
-    if (tempFolder != null) {
-      tempFolder.stop();
-    }
-  }
 }
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
deleted file mode 100644 (file)
index 61fcb41..0000000
+++ /dev/null
@@ -1,35 +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 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);
-    }
-  }
-}
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
deleted file mode 100644 (file)
index 6d5a73b..0000000
+++ /dev/null
@@ -1,123 +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.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);
-  }
-}
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
deleted file mode 100644 (file)
index 1732519..0000000
+++ /dev/null
@@ -1,227 +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.Iterables;
-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 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());
-    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 classloader + fully qualified class name as the name of the bean
-   * - For instances, use the Classloader + 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(componentKeys.ofClass(clazz), 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(componentKeys.ofClass(clazz), 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
-  }
-}
index fb0f25eaf7638e503a02c8fb347e532cbbfb1105..4e85fc6c1cc4c8ee2be28498bac4900d25a0006f 100644 (file)
@@ -43,6 +43,7 @@ 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.platform.SpringComponentContainer;
 import org.sonar.core.util.DefaultHttpDownloader;
 import org.sonar.core.util.UuidFactoryImpl;
 import org.sonar.scanner.extension.ScannerCoreExtensionsInstaller;
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
deleted file mode 100644 (file)
index 3bb4cb5..0000000
+++ /dev/null
@@ -1,60 +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 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 b5629ce69ef8b29531e8c910a028548a9c671dff..ac65a92484ed988e796782dde9f10d686c29fd47 100644 (file)
@@ -32,7 +32,7 @@ public class InputProjectProvider {
 
   @Bean("DefaultInputProject")
   public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator,
-    ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) {
+    ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator, WorkDirectoriesInitializer workDirectoriesInit) {
     // 1 Apply project builders
     projectBuildersExecutor.execute(projectReactor);
 
@@ -41,6 +41,7 @@ public class InputProjectProvider {
 
     // 3 Create project
     DefaultInputProject project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt());
+    workDirectoriesInit.execute(project);
 
     LOG.info("Project key: {}", project.key());
     LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString());
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
deleted file mode 100644 (file)
index d1c3d97..0000000
+++ /dev/null
@@ -1,36 +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 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 79a09172a31fd7d5031d0bcf99f941bd02717c29..4707354a706524e5aea0baf6569d076dbab9c3ed 100644 (file)
@@ -23,7 +23,7 @@ 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.core.platform.SpringComponentContainer;
 import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
 import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
 import org.sonar.scanner.sensor.ModuleSensorContext;
index 8320fa8a3fc5490b1f6d8a955ae3adff09bd580a..888f5661e8c6b86ecc7322fc0397175b2dc0b664 100644 (file)
@@ -33,6 +33,7 @@ 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.language.LanguagesProvider;
 import org.sonar.core.metric.ScannerMetrics;
 import org.sonar.scanner.DefaultFileLinesContextFactory;
 import org.sonar.scanner.ProjectInfo;
@@ -41,7 +42,7 @@ 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.core.platform.SpringComponentContainer;
 import org.sonar.scanner.ci.CiConfigurationProvider;
 import org.sonar.scanner.ci.vendors.AppVeyor;
 import org.sonar.scanner.ci.vendors.AwsCodeBuild;
index b118a870ff727cf55aee7fbe9a09ad37be88944c..11552502e00f67bcc0aafc2cb88cf05e5cd2e72c 100644 (file)
@@ -24,26 +24,42 @@ import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Iterator;
-import org.sonar.core.util.FileUtils;
+import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.core.util.FileUtils;
 import org.sonar.scanner.fs.InputModuleHierarchy;
 
 /**
- * Clean and create working directories of each module.
+ * Clean and create working directories of each module, except the root.
  * Be careful that sub module work dir might be nested in parent working directory.
  */
 public class WorkDirectoriesInitializer {
   public void execute(InputModuleHierarchy moduleHierarchy) {
-    cleanAllWorkingDirs(moduleHierarchy, moduleHierarchy.root());
-    mkdirsAllWorkingDirs(moduleHierarchy, moduleHierarchy.root());
+    // dont apply to root. Root is done by InputProjectProvider
+    for (DefaultInputModule sub : moduleHierarchy.children(moduleHierarchy.root())) {
+      cleanAllWorkingDirs(moduleHierarchy, sub);
+    }
+    for (DefaultInputModule sub : moduleHierarchy.children(moduleHierarchy.root())) {
+      mkdirsAllWorkingDirs(moduleHierarchy, sub);
+    }
+  }
+
+  public void execute(DefaultInputProject project) {
+    cleanWorkingDir(project);
+    mkdirWorkingDir(project);
   }
 
   private static void cleanAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) {
     for (DefaultInputModule sub : moduleHierarchy.children(module)) {
       cleanAllWorkingDirs(moduleHierarchy, sub);
     }
-    if (Files.exists(module.getWorkDir())) {
-      deleteAllRecursivelyExceptLockFile(module.getWorkDir());
+    cleanWorkingDir(module);
+  }
+
+  private static void cleanWorkingDir(AbstractProjectOrModule projectOrModule) {
+    if (Files.exists(projectOrModule.getWorkDir())) {
+      deleteAllRecursivelyExceptLockFile(projectOrModule.getWorkDir());
     }
   }
 
@@ -51,10 +67,14 @@ public class WorkDirectoriesInitializer {
     for (DefaultInputModule sub : moduleHierarchy.children(module)) {
       mkdirsAllWorkingDirs(moduleHierarchy, sub);
     }
+    mkdirWorkingDir(module);
+  }
+
+  private static void mkdirWorkingDir(AbstractProjectOrModule projectOrModule) {
     try {
-      Files.createDirectories(module.getWorkDir());
+      Files.createDirectories(projectOrModule.getWorkDir());
     } catch (Exception e) {
-      throw new IllegalStateException("Fail to create working dir: " + module.getWorkDir(), e);
+      throw new IllegalStateException("Fail to create working dir: " + projectOrModule.getWorkDir(), e);
     }
   }
 
index d723bb2ebf36d7ad2697375e8e09eda65e2672ae..5764ba0c854d1d19cd04297b62f411b911a3b19b 100644 (file)
@@ -22,9 +22,8 @@ package org.sonar.scanner.sensor;
 import java.util.Collection;
 import java.util.stream.Collectors;
 import org.sonar.api.batch.sensor.Sensor;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 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 +34,7 @@ public class ModuleSensorExtensionDictionary extends AbstractExtensionDictionary
   private final MutableFileSystem fileSystem;
   private final BranchConfiguration branchConfiguration;
 
-  public ModuleSensorExtensionDictionary(SpringComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
+  public ModuleSensorExtensionDictionary(ExtensionContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
     MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
     super(componentContainer);
     this.sensorContext = sensorContext;
index 60b31745d19472f3d3a1018f6e8b35a854410501..b33c96fa848be448647b5ddb3ebb2b90eef7984e 100644 (file)
@@ -24,7 +24,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 import org.sonar.api.scanner.sensor.ProjectSensor;
 import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
-import org.sonar.scanner.bootstrap.SpringComponentContainer;
+import org.sonar.core.platform.SpringComponentContainer;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.filesystem.MutableFileSystem;
 
index b61685130a10d05f555ee71a6f304a429554db5e..41ec1d712e50bf4c1d2237a25ad454e946472da4 100644 (file)
@@ -33,7 +33,7 @@
     <level value="INFO"/>
   </logger>
 
-  <logger name="org.sonar.scanner.bootstrap.PriorityBeanFactory">
+  <logger name="org.sonar.core.platform.PriorityBeanFactory">
     <level value="INFO"/>
   </logger>
 
index d4c61ca7d9d95af8c7c13e79708fcbb33ac801af..9fcebc1958c9a8fbdf65c0f630542887804ca1a0 100644 (file)
 package org.sonar.scanner.bootstrap;
 
 import java.util.Arrays;
+
 import org.apache.commons.lang.ClassUtils;
 import org.junit.Test;
 import org.sonar.api.Plugin;
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.ScannerSide;
 import org.sonar.api.config.internal.MapSettings;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 import org.sonar.core.platform.PluginInfo;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -35,8 +36,8 @@ import static org.mockito.Mockito.when;
 
 public class ExtensionInstallerTest {
 
-  private MapSettings settings = new MapSettings();
-  private ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
+  private final MapSettings settings = new MapSettings();
+  private final ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
 
   private static Plugin newPluginInstance(final Object... extensions) {
     return desc -> desc.addExtensions(Arrays.asList(extensions));
@@ -47,12 +48,13 @@ public class ExtensionInstallerTest {
     when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo")));
     when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(Foo.class, Bar.class));
 
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
     ExtensionInstaller installer = new ExtensionInstaller(mock(SonarRuntime.class), pluginRepository, settings.asConfig());
     installer.install(container, new FooMatcher());
 
-    assertThat(container.getComponentByType(Foo.class)).isNotNull();
-    assertThat(container.getComponentByType(Bar.class)).isNull();
+    assertThat(container.getAddedObjects())
+      .contains(Foo.class)
+      .doesNotContain(Bar.class);
   }
 
   private static class FooMatcher implements ExtensionMatcher {
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
deleted file mode 100644 (file)
index 04327d5..0000000
+++ /dev/null
@@ -1,41 +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 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 b2625033efc7d3eddc8cf7a745330c7c48934b9b..2246bd1914d95975078f3c41b3ea3a5c231d116e 100644 (file)
  */
 package org.sonar.scanner.bootstrap;
 
-import com.google.common.collect.Lists;
+import java.util.ArrayList;
+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;
 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.scanner.scan.SpringModuleScanContainer;
+import org.sonar.core.platform.ExtensionContainer;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.filesystem.MutableFileSystem;
 import org.sonar.scanner.sensor.ModuleSensorContext;
@@ -41,10 +41,6 @@ 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;
@@ -61,17 +57,9 @@ public class ModuleSensorExtensionDictionaryTest {
     when(sensorOptimizer.shouldExecute(any(DefaultSensorDescriptor.class))).thenReturn(true);
   }
 
-  private ModuleSensorExtensionDictionary newSelector(Object... extensions) {
-    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();
-
+  private ModuleSensorExtensionDictionary newSelector(Class type, Object... instances) {
+    ExtensionContainer iocContainer = mock(ExtensionContainer.class);
+    when(iocContainer.getComponentsByType(type)).thenReturn(Arrays.asList(instances));
     return new ModuleSensorExtensionDictionary(iocContainer, mock(ModuleSensorContext.class), sensorOptimizer, fileSystem, branchConfiguration);
   }
 
@@ -80,7 +68,7 @@ public class ModuleSensorExtensionDictionaryTest {
     final Sensor sensor1 = new FakeSensor();
     final Sensor sensor2 = new FakeSensor();
 
-    ModuleSensorExtensionDictionary selector = newSelector(sensor1, sensor2);
+    ModuleSensorExtensionDictionary selector = newSelector(Sensor.class, sensor1, sensor2);
     Collection<Sensor> sensors = selector.select(Sensor.class, true, extension -> extension.equals(sensor1));
     assertThat(sensors).contains(sensor1);
     assertEquals(1, sensors.size());
@@ -90,9 +78,8 @@ public class ModuleSensorExtensionDictionaryTest {
   public void testGetFilteredExtensions() {
     Sensor sensor1 = new FakeSensor();
     Sensor sensor2 = new FakeSensor();
-    FieldDecorated.Decorator decorator = mock(FieldDecorated.Decorator.class);
 
-    ModuleSensorExtensionDictionary selector = newSelector(sensor1, sensor2, decorator);
+    ModuleSensorExtensionDictionary selector = newSelector(Sensor.class, sensor1, sensor2);
     Collection<Sensor> sensors = selector.select(Sensor.class, false, null);
 
     assertThat(sensors).containsOnly(sensor1, sensor2);
@@ -104,17 +91,16 @@ public class ModuleSensorExtensionDictionaryTest {
     Sensor b = new FakeSensor();
     Sensor c = new FakeSensor();
 
-    SpringComponentContainer grandParent = new SpringComponentContainer();
-    grandParent.add(a);
-    grandParent.context.refresh();
+    ExtensionContainer grandParent = mock(ExtensionContainer.class);
+    when(grandParent.getComponentsByType(Sensor.class)).thenReturn(List.of(a));
 
-    SpringComponentContainer parent = grandParent.createChild();
-    parent.add(b);
-    parent.context.refresh();
+    ExtensionContainer parent = mock(ExtensionContainer.class);
+    when(parent.getComponentsByType(Sensor.class)).thenReturn(List.of(b));
+    when(parent.getParent()).thenReturn(grandParent);
 
-    SpringComponentContainer child = parent.createChild();
-    child.add(c);
-    child.context.refresh();
+    ExtensionContainer child = mock(ExtensionContainer.class);
+    when(child.getComponentsByType(Sensor.class)).thenReturn(List.of(c));
+    when(child.getParent()).thenReturn(parent);
 
     ModuleSensorExtensionDictionary dictionnary = new ModuleSensorExtensionDictionary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class),
       fileSystem, branchConfiguration);
@@ -127,8 +113,8 @@ public class ModuleSensorExtensionDictionaryTest {
     Object b = new MethodDependentOf(a);
     Object c = new MethodDependentOf(b);
 
-    ModuleSensorExtensionDictionary selector = newSelector(b, c, a);
-    List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    ModuleSensorExtensionDictionary selector = newSelector(Marker.class, b, c, a);
+    List<Object> extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(3);
     assertThat(extensions.get(0)).isEqualTo(a);
@@ -141,16 +127,16 @@ public class ModuleSensorExtensionDictionaryTest {
     Object a = new GeneratesSomething("foo");
     Object b = new MethodDependentOf("foo");
 
-    ModuleSensorExtensionDictionary selector = newSelector(a, b);
-    List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    ModuleSensorExtensionDictionary selector = newSelector(Marker.class, a, b);
+    List<Object> extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions.size()).isEqualTo(2);
     assertThat(extensions.get(0)).isEqualTo(a);
     assertThat(extensions.get(1)).isEqualTo(b);
 
     // different initial order
-    selector = newSelector(b, a);
-    extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    selector = newSelector(Marker.class, b, a);
+    extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
@@ -162,16 +148,16 @@ public class ModuleSensorExtensionDictionaryTest {
     Object a = new GeneratesSomething("foo");
     Object b = new MethodDependentOf(Arrays.asList("foo"));
 
-    ModuleSensorExtensionDictionary selector = newSelector(a, b);
-    List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    ModuleSensorExtensionDictionary selector = newSelector(Marker.class, a, b);
+    List<Object> extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
     assertThat(extensions.get(1)).isEqualTo(b);
 
     // different initial order
-    selector = newSelector(b, a);
-    extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    selector = newSelector(Marker.class, b, a);
+    extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
@@ -183,16 +169,16 @@ public class ModuleSensorExtensionDictionaryTest {
     Object a = new GeneratesSomething("foo");
     Object b = new MethodDependentOf(new String[] {"foo"});
 
-    ModuleSensorExtensionDictionary selector = newSelector(a, b);
-    List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    ModuleSensorExtensionDictionary selector = newSelector(Marker.class, a, b);
+    List<Object> extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
     assertThat(extensions.get(1)).isEqualTo(b);
 
     // different initial order
-    selector = newSelector(b, a);
-    extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    selector = newSelector(Marker.class, b, a);
+    extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
@@ -204,16 +190,16 @@ public class ModuleSensorExtensionDictionaryTest {
     Object a = new ClassDependedUpon();
     Object b = new ClassDependsUpon();
 
-    ModuleSensorExtensionDictionary selector = newSelector(a, b);
-    List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    ModuleSensorExtensionDictionary selector = newSelector(Marker.class, a, b);
+    List<Object> extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
     assertThat(extensions.get(1)).isEqualTo(b);
 
     // different initial order
-    selector = newSelector(b, a);
-    extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    selector = newSelector(Marker.class, b, a);
+    extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
@@ -227,16 +213,16 @@ public class ModuleSensorExtensionDictionaryTest {
     Object b = new InterfaceDependsUpon() {
     };
 
-    ModuleSensorExtensionDictionary selector = newSelector(a, b);
-    List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    ModuleSensorExtensionDictionary selector = newSelector(Marker.class, a, b);
+    List<Object> extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
     assertThat(extensions.get(1)).isEqualTo(b);
 
     // different initial order
-    selector = newSelector(b, a);
-    extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    selector = newSelector(Marker.class, b, a);
+    extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
@@ -248,16 +234,16 @@ public class ModuleSensorExtensionDictionaryTest {
     Object a = new SubClass("foo");
     Object b = new MethodDependentOf("foo");
 
-    ModuleSensorExtensionDictionary selector = newSelector(b, a);
-    List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    ModuleSensorExtensionDictionary selector = newSelector(Marker.class, b, a);
+    List<Object> extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
     assertThat(extensions.get(1)).isEqualTo(b);
 
     // change initial order
-    selector = newSelector(a, b);
-    extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+    selector = newSelector(Marker.class, a, b);
+    extensions = new ArrayList<>(selector.select(Marker.class, true, null));
 
     assertThat(extensions).hasSize(2);
     assertThat(extensions.get(0)).isEqualTo(a);
@@ -266,7 +252,8 @@ public class ModuleSensorExtensionDictionaryTest {
 
   @Test(expected = IllegalStateException.class)
   public void annotatedMethodsCanNotBePrivate() {
-    ModuleSensorExtensionDictionary selector = newSelector();
+    ModuleSensorExtensionDictionary selector = new ModuleSensorExtensionDictionary(mock(ExtensionContainer.class), mock(ModuleSensorContext.class),
+      sensorOptimizer, fileSystem, branchConfiguration);
     Object wrong = new Object() {
       @DependsUpon
       private Object foo() {
@@ -282,7 +269,7 @@ public class ModuleSensorExtensionDictionaryTest {
     NormalSensor normal = new NormalSensor();
     PostSensor post = new PostSensor();
 
-    ModuleSensorExtensionDictionary selector = newSelector(normal, post, pre);
+    ModuleSensorExtensionDictionary selector = newSelector(Sensor.class, normal, post, pre);
     assertThat(selector.selectSensors(false)).extracting("wrappedSensor").containsExactly(pre, normal, post);
   }
 
@@ -292,8 +279,8 @@ public class ModuleSensorExtensionDictionaryTest {
     NormalSensor normal = new NormalSensor();
     PostSensorSubclass post = new PostSensorSubclass();
 
-    ModuleSensorExtensionDictionary selector = newSelector(normal, post, pre);
-    List extensions = Lists.newArrayList(selector.select(Sensor.class, true, null));
+    ModuleSensorExtensionDictionary selector = newSelector(Sensor.class, normal, post, pre);
+    List extensions = new ArrayList<>(selector.select(Sensor.class, true, null));
 
     assertThat(extensions).containsExactly(pre, normal, post);
   }
@@ -302,7 +289,7 @@ public class ModuleSensorExtensionDictionaryTest {
   public void selectSensors() {
     FakeSensor nonGlobalSensor = new FakeSensor();
     FakeGlobalSensor globalSensor = new FakeGlobalSensor();
-    ModuleSensorExtensionDictionary selector = newSelector(nonGlobalSensor, globalSensor);
+    ModuleSensorExtensionDictionary selector = newSelector(Sensor.class, nonGlobalSensor, globalSensor);
 
     // verify non-global sensor
     Collection<ModuleSensorWrapper> extensions = selector.selectSensors(false);
index e359a0f1be6fbe79b5f6babcee5a6be3ad675729..dbfd4bd9f5c6810f7f51b3460abcf01ce74390e2 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.scanner.bootstrap;
 
+import java.util.List;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.batch.Phase;
@@ -26,10 +27,7 @@ import org.sonar.api.batch.postjob.PostJob;
 import org.sonar.api.batch.postjob.PostJobContext;
 import org.sonar.api.batch.postjob.PostJobDescriptor;
 import org.sonar.api.batch.postjob.internal.DefaultPostJobDescriptor;
-import org.sonar.api.batch.sensor.Sensor;
-import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
 import org.sonar.scanner.postjob.PostJobOptimizer;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -38,49 +36,23 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 public class PostJobExtensionDictionaryTest {
-  private PostJobOptimizer postJobOptimizer = mock(PostJobOptimizer.class);
+  private final PostJobOptimizer postJobOptimizer = mock(PostJobOptimizer.class);
 
   @Before
   public void setUp() {
     when(postJobOptimizer.shouldExecute(any(DefaultPostJobDescriptor.class))).thenReturn(true);
   }
 
-  private PostJobExtensionDictionary newSelector(Object... extensions) {
-    ComponentContainer iocContainer = new ComponentContainer();
-    for (Object extension : extensions) {
-      iocContainer.addSingleton(extension);
-    }
-    return new PostJobExtensionDictionary(iocContainer, postJobOptimizer, mock(PostJobContext.class));
-  }
-
   @Test
   public void dependsUponPhaseForPostJob() {
     PrePostJob pre = new PrePostJob();
     NormalPostJob normal = new NormalPostJob();
 
-    PostJobExtensionDictionary selector = newSelector(normal, pre);
-    assertThat(selector.selectPostJobs()).extracting("wrappedPostJob").containsExactly(pre, normal);
-  }
-
-  interface Marker {
-
-  }
-
-  @Phase(name = Phase.Name.POST) static
-  class PostSensor implements Sensor {
-
-    @Override
-    public void describe(SensorDescriptor descriptor) {
-    }
-
-    @Override
-    public void execute(SensorContext context) {
-    }
-
-  }
-
-  class PostSensorSubclass extends PostSensor {
+    ExtensionContainer iocContainer = mock(ExtensionContainer.class);
+    when(iocContainer.getComponentsByType(PostJob.class)).thenReturn(List.of(pre, normal));
 
+    PostJobExtensionDictionary selector = new PostJobExtensionDictionary(iocContainer, postJobOptimizer, mock(PostJobContext.class));
+    assertThat(selector.selectPostJobs()).extracting("wrappedPostJob").containsExactly(pre, normal);
   }
 
   static class NormalPostJob implements PostJob {
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
deleted file mode 100644 (file)
index b20e87e..0000000
+++ /dev/null
@@ -1,103 +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 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 {
-
-  }
-
-}
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
deleted file mode 100644 (file)
index 7c1008b..0000000
+++ /dev/null
@@ -1,217 +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 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(
-        this.getClass().getClassLoader() + "-org.sonar.scanner.bootstrap.SpringComponentContainerTest.ToString-a",
-        this.getClass().getClassLoader() + "-org.sonar.scanner.bootstrap.SpringComponentContainerTest.ToString-b");
-    assertThat(container.getComponentsByType(ToString.class)).hasSize(2);
-  }
-
-  @Test
-  public void register_class_with_classloader_and_fqcn() {
-    SpringComponentContainer container = new SimpleContainer(A.class, B.class);
-    container.startComponents();
-    assertThat(container.context.getBeanDefinitionNames())
-      .contains(
-        this.getClass().getClassLoader() + "-org.sonar.scanner.bootstrap.SpringComponentContainerTest.A",
-        this.getClass().getClassLoader() + "-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/StartableBeanPostProcessorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessorTest.java
deleted file mode 100644 (file)
index ecdb616..0000000
+++ /dev/null
@@ -1,64 +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 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 febb3323f5d39dd3464bc05f1db1e2167a25069f..458d42dd69193b4ce260835b07f1ec132149f47b 100644 (file)
@@ -25,6 +25,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.stream.Stream;
+
 import org.junit.Test;
 import org.sonar.api.SonarRuntime;
 import org.sonar.api.scanner.ScannerSide;
@@ -32,7 +33,7 @@ import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.extension.CoreExtension;
 import org.sonar.core.extension.CoreExtensionRepository;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ListContainer;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -41,10 +42,9 @@ import static org.sonar.core.extension.CoreExtensionsInstaller.noAdditionalSideF
 import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter;
 
 public class ScannerCoreExtensionsInstallerTest {
-  private SonarRuntime sonarRuntime = mock(SonarRuntime.class);
-  private CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class);
-
-  private ScannerCoreExtensionsInstaller underTest = new ScannerCoreExtensionsInstaller(sonarRuntime, coreExtensionRepository);
+  private final SonarRuntime sonarRuntime = mock(SonarRuntime.class);
+  private final CoreExtensionRepository coreExtensionRepository = mock(CoreExtensionRepository.class);
+  private final ScannerCoreExtensionsInstaller underTest = new ScannerCoreExtensionsInstaller(sonarRuntime, coreExtensionRepository);
 
   @Test
   public void install_only_adds_ScannerSide_annotated_extension_to_container() {
@@ -61,14 +61,13 @@ public class ScannerCoreExtensionsInstallerTest {
             NoAnnotationClass.class, OtherAnnotationClass.class, MultipleAnnotationClass.class);
         }
       }));
-    ComponentContainer container = new ComponentContainer();
+    ListContainer container = new ListContainer();
 
     underTest.install(container, noExtensionFilter(), noAdditionalSideFilter());
 
-    assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 2);
-    assertThat(container.getComponentByType(ScannerClass.class)).isNotNull();
-    assertThat(container.getComponentByType(MultipleAnnotationClass.class)).isNotNull();
+    assertThat(container.getAddedObjects())
+      .hasSize(2)
+      .contains(ScannerClass.class, MultipleAnnotationClass.class);
   }
 
   @ComputeEngineSide
index 3f969ca4963f2cc5d2f12766bec6a7548cd13a72..e0c3137f27024c204d35585c9680142562e11744 100644 (file)
@@ -26,7 +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 org.springframework.beans.factory.BeanCreationException;
 
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
@@ -44,7 +44,7 @@ public class NoLanguagesPluginsMediumTest {
     assertThatThrownBy(() -> tester
       .newAnalysis(new File(projectDir, "sonar-project.properties"))
       .execute())
-      .isInstanceOf(UnsatisfiedDependencyException.class)
+      .isInstanceOf(BeanCreationException.class)
       .hasRootCauseMessage("No language plugins are installed.");
   }
 
index ec873cf72ae289662cac4faf694e6a3050778c40..180466e355c0601e7f1047cf78563743386b1375 100644 (file)
@@ -27,6 +27,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.scanner.fs.InputModuleHierarchy;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -34,46 +35,47 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 public class WorkDirectoriesInitializerTest {
-  private WorkDirectoriesInitializer initializer;
+  private final WorkDirectoriesInitializer initializer = new WorkDirectoriesInitializer();
+  private final InputModuleHierarchy hierarchy = mock(InputModuleHierarchy.class);
+  private final DefaultInputProject project = mock(DefaultInputProject.class);
+  private final DefaultInputModule root = mock(DefaultInputModule.class);
+
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
   private File rootWorkDir;
   private File lock;
-  private InputModuleHierarchy hierarchy;
-  private DefaultInputModule root;
 
   @Before
   public void setUp() throws IOException {
     rootWorkDir = temp.newFolder();
-    // create files to clean
-    new File(rootWorkDir, "foo.txt").createNewFile();
-    File newFolder = new File(rootWorkDir, "foo");
+    when(hierarchy.root()).thenReturn(root);
+    createFilesToClean(rootWorkDir);
+    when(root.getWorkDir()).thenReturn(rootWorkDir.toPath());
+    when(project.getWorkDir()).thenReturn(rootWorkDir.toPath());
+  }
+
+  private void createFilesToClean(File dir) throws IOException {
+    new File(dir, "foo.txt").createNewFile();
+    File newFolder = new File(dir, "foo");
     newFolder.mkdir();
     File fileInFolder = new File(newFolder, "test");
     fileInFolder.createNewFile();
 
-    lock = new File(rootWorkDir, DirectoryLock.LOCK_FILE_NAME);
+    lock = new File(dir, DirectoryLock.LOCK_FILE_NAME);
     lock.createNewFile();
-
-    hierarchy = mock(InputModuleHierarchy.class);
-    root = mock(DefaultInputModule.class);
-    when(hierarchy.root()).thenReturn(root);
-    when(root.getWorkDir()).thenReturn(rootWorkDir.toPath());
-
-    assertThat(rootWorkDir.list().length).isGreaterThan(1);
-    initializer = new WorkDirectoriesInitializer();
+    assertThat(dir.list()).hasSizeGreaterThan(1);
   }
 
   @Test
-  public void testNonExisting() {
+  public void execute_doesnt_fail_if_nothing_to_clean() {
     temp.delete();
     initializer.execute(hierarchy);
   }
 
   @Test
-  public void testClean() {
-    initializer.execute(hierarchy);
+  public void execute_should_clean_root() {
+    initializer.execute(project);
 
     assertThat(rootWorkDir).exists();
     assertThat(lock).exists();
@@ -81,20 +83,35 @@ public class WorkDirectoriesInitializerTest {
   }
 
   @Test
-  public void cleaningRootModuleShouldNotDeleteChildrenWorkDir() throws IOException {
+  public void execute_on_hierarchy_should_clean_submodules() throws IOException {
     DefaultInputModule moduleA = mock(DefaultInputModule.class);
+    DefaultInputModule moduleB = mock(DefaultInputModule.class);
+
     when(hierarchy.children(root)).thenReturn(Arrays.asList(moduleA));
+    when(hierarchy.children(moduleA)).thenReturn(Arrays.asList(moduleB));
+
     File moduleAWorkdir = new File(rootWorkDir, "moduleA");
+    File moduleBWorkdir = new File(moduleAWorkdir, "moduleB");
+
     when(moduleA.getWorkDir()).thenReturn(moduleAWorkdir.toPath());
+    when(moduleB.getWorkDir()).thenReturn(moduleBWorkdir.toPath());
+
     moduleAWorkdir.mkdir();
+    moduleBWorkdir.mkdir();
+
     new File(moduleAWorkdir, "fooA.txt").createNewFile();
+    new File(moduleBWorkdir, "fooB.txt").createNewFile();
 
+    initializer.execute(project);
     initializer.execute(hierarchy);
 
     assertThat(rootWorkDir).exists();
     assertThat(lock).exists();
     assertThat(rootWorkDir.list()).containsOnly(DirectoryLock.LOCK_FILE_NAME, "moduleA");
     assertThat(moduleAWorkdir).exists();
+    assertThat(moduleBWorkdir).exists();
+    assertThat(moduleAWorkdir.list()).containsOnly("moduleB");
+    assertThat(moduleBWorkdir).isEmptyDirectory();
   }
 
 }