/* * SonarQube * Copyright (C) 2009-2017 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.container; import com.google.common.annotations.VisibleForTesting; import java.util.List; import javax.annotation.CheckForNull; import org.sonar.api.SonarQubeSide; import org.sonar.api.SonarQubeVersion; import org.sonar.api.config.EmailSettings; import org.sonar.api.internal.ApiVersion; import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.profiles.AnnotationProfileParser; 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.rules.XMLRuleParser; import org.sonar.api.server.rule.RulesDefinitionXmlLoader; import org.sonar.api.utils.Durations; import org.sonar.api.utils.System2; import org.sonar.api.utils.UriReader; import org.sonar.api.utils.Version; import org.sonar.ce.CeConfigurationModule; import org.sonar.ce.CeDistributedInformationImpl; import org.sonar.ce.CeHttpModule; import org.sonar.ce.CeQueueModule; import org.sonar.ce.CeTaskCommonsModule; import org.sonar.ce.StandaloneCeDistributedInformation; import org.sonar.ce.cleaning.CeCleaningModule; import org.sonar.ce.cluster.HazelcastClientWrapperImpl; import org.sonar.ce.db.ReadOnlyPropertiesDao; import org.sonar.ce.log.CeProcessLogging; import org.sonar.ce.platform.ComputeEngineExtensionInstaller; import org.sonar.ce.queue.CeQueueCleaner; import org.sonar.ce.queue.PurgeCeActivities; import org.sonar.ce.settings.ProjectSettingsFactory; import org.sonar.ce.taskprocessor.CeTaskProcessorModule; import org.sonar.ce.user.CeUserSession; import org.sonar.core.component.DefaultResourceTypes; import org.sonar.core.config.CorePropertyDefinitions; import org.sonar.core.i18n.DefaultI18n; import org.sonar.core.i18n.RuleI18nManager; import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.Module; import org.sonar.core.platform.PluginClassloaderFactory; import org.sonar.core.platform.PluginLoader; import org.sonar.core.timemachine.Periods; import org.sonar.core.util.UuidFactoryImpl; import org.sonar.db.DaoModule; import org.sonar.db.DatabaseChecker; import org.sonar.db.DbClient; import org.sonar.db.DefaultDatabase; import org.sonar.db.purge.PurgeProfiler; import org.sonar.process.Props; import org.sonar.process.logging.LogbackHelper; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.index.ComponentIndexer; import org.sonar.server.computation.task.projectanalysis.ProjectAnalysisTaskModule; import org.sonar.server.debt.DebtModelPluginRepository; import org.sonar.server.debt.DebtRulesXMLImporter; import org.sonar.server.event.NewAlerts; import org.sonar.server.issue.IssueFieldsSetter; import org.sonar.server.issue.index.IssueIndex; import org.sonar.server.issue.index.IssueIndexer; import org.sonar.server.issue.index.IssueIteratorFactory; import org.sonar.server.issue.notification.ChangesOnMyIssueNotificationDispatcher; import org.sonar.server.issue.notification.DoNotFixNotificationDispatcher; import org.sonar.server.issue.notification.IssueChangesEmailTemplate; import org.sonar.server.issue.notification.MyNewIssuesEmailTemplate; import org.sonar.server.issue.notification.MyNewIssuesNotificationDispatcher; import org.sonar.server.issue.notification.NewIssuesEmailTemplate; import org.sonar.server.issue.notification.NewIssuesNotificationDispatcher; import org.sonar.server.issue.notification.NewIssuesNotificationFactory; import org.sonar.server.issue.workflow.FunctionExecutor; import org.sonar.server.issue.workflow.IssueWorkflow; import org.sonar.server.measure.index.ProjectMeasuresIndexer; import org.sonar.server.metric.CoreCustomMetrics; import org.sonar.server.metric.DefaultMetricFinder; import org.sonar.server.notification.DefaultNotificationManager; import org.sonar.server.notification.NotificationService; import org.sonar.server.notification.email.AlertsEmailTemplate; import org.sonar.server.notification.email.EmailNotificationChannel; import org.sonar.server.organization.BillingValidationsProxyImpl; import org.sonar.server.organization.DefaultOrganizationProviderImpl; import org.sonar.server.permission.GroupPermissionChanger; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.permission.PermissionUpdater; import org.sonar.server.permission.UserPermissionChanger; import org.sonar.server.permission.index.PermissionIndexer; import org.sonar.server.permission.ws.template.DefaultTemplatesResolverImpl; import org.sonar.server.platform.DatabaseServerCompatibility; import org.sonar.server.platform.DefaultServerUpgradeStatus; import org.sonar.server.platform.ServerFileSystemImpl; import org.sonar.server.platform.ServerIdManager; import org.sonar.server.platform.ServerImpl; import org.sonar.server.platform.ServerLifecycleNotifier; import org.sonar.server.platform.ServerLogging; import org.sonar.server.platform.StartupMetadataProvider; import org.sonar.server.platform.TempFolderProvider; import org.sonar.server.platform.UrlSettings; import org.sonar.server.platform.cluster.ClusterImpl; import org.sonar.server.platform.db.migration.MigrationConfigurationModule; import org.sonar.server.platform.db.migration.version.DatabaseVersion; import org.sonar.server.plugins.InstalledPluginReferentialFactory; import org.sonar.server.plugins.ServerExtensionInstaller; import org.sonar.server.plugins.privileged.PrivilegedPluginsBootstraper; import org.sonar.server.plugins.privileged.PrivilegedPluginsStopper; import org.sonar.server.property.InternalPropertiesImpl; import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; import org.sonar.server.rule.CommonRuleDefinitionsImpl; import org.sonar.server.rule.DefaultRuleFinder; import org.sonar.server.rule.DeprecatedRulesDefinitionLoader; import org.sonar.server.rule.RuleDefinitionsLoader; import org.sonar.server.rule.index.RuleIndex; import org.sonar.server.search.EsSearchModule; import org.sonar.server.setting.DatabaseSettingLoader; import org.sonar.server.setting.DatabaseSettingsEnabler; import org.sonar.server.setting.ThreadLocalSettings; import org.sonar.server.startup.LogServerId; import org.sonar.server.test.index.TestIndexer; import org.sonar.server.user.DefaultUserFinder; import org.sonar.server.user.DeprecatedUserFinder; import org.sonar.server.user.index.UserIndex; import org.sonar.server.user.index.UserIndexer; import org.sonar.server.util.OkHttpClientProvider; import org.sonar.server.view.index.ViewIndex; import org.sonar.server.view.index.ViewIndexer; import org.sonarqube.ws.Rules; public class ComputeEngineContainerImpl implements ComputeEngineContainer { @CheckForNull private ComponentContainer level1; @CheckForNull private ComponentContainer level4; @Override public ComputeEngineContainer start(Props props) { this.level1 = new ComponentContainer(); this.level1 .add(props.rawProperties()) .add(level1Components()) .add(toArray(CorePropertyDefinitions.all())); configureFromModules(this.level1); this.level1.startComponents(); ComponentContainer level2 = this.level1.createChild(); level2.add(level2Components()); configureFromModules(level2); level2.startComponents(); ComponentContainer level3 = level2.createChild(); level3.add(level3Components()); configureFromModules(level3); level3.startComponents(); this.level4 = level3.createChild(); this.level4.add(level4Components()); // TODO refactoring levelXComponents() if (props.valueAsBoolean("sonar.cluster.enabled")) { this.level4.add( HazelcastClientWrapperImpl.class, CeDistributedInformationImpl.class ); } else { this.level4.add( StandaloneCeDistributedInformation.class ); } configureFromModules(this.level4); ServerExtensionInstaller extensionInstaller = this.level4.getComponentByType(ServerExtensionInstaller.class); extensionInstaller.installExtensions(this.level4); this.level4.startComponents(); startupTasks(); return this; } private void startupTasks() { ComponentContainer startupLevel = this.level4.createChild(); startupLevel.add(startupComponents()); startupLevel.startComponents(); // done in PlatformLevelStartup ServerLifecycleNotifier serverLifecycleNotifier = startupLevel.getComponentByType(ServerLifecycleNotifier.class); if (serverLifecycleNotifier != null) { serverLifecycleNotifier.notifyStart(); } startupLevel.stopComponents(); } @Override public ComputeEngineContainer stop() { this.level1.stopComponents(); return this; } @VisibleForTesting protected ComponentContainer getComponentContainer() { return level4; } private static Object[] level1Components() { Version apiVersion = ApiVersion.load(System2.INSTANCE); return new Object[] { ThreadLocalSettings.class, new SonarQubeVersion(apiVersion), SonarRuntimeImpl.forSonarQube(ApiVersion.load(System2.INSTANCE), SonarQubeSide.COMPUTE_ENGINE), CeProcessLogging.class, UuidFactoryImpl.INSTANCE, ClusterImpl.class, LogbackHelper.class, DefaultDatabase.class, DatabaseChecker.class, // must instantiate deprecated class in 5.2 and only this one (and not its replacement) // to avoid having two SqlSessionFactory instances org.sonar.core.persistence.MyBatis.class, PurgeProfiler.class, ServerFileSystemImpl.class, new TempFolderProvider(), System2.INSTANCE, // user session CeUserSession.class, // DB DaoModule.class, ReadOnlyPropertiesDao.class, DbClient.class, // Elasticsearch EsSearchModule.class, // rules/qprofiles RuleIndex.class, // issues IssueIndex.class, new OkHttpClientProvider() }; } private static Object[] level2Components() { return new Object[] { MigrationConfigurationModule.class, DatabaseVersion.class, DatabaseServerCompatibility.class, DatabaseSettingLoader.class, DatabaseSettingsEnabler.class, UrlSettings.class, // add ReadOnlyPropertiesDao at level2 again so that it shadows PropertiesDao ReadOnlyPropertiesDao.class, DefaultServerUpgradeStatus.class, // plugins PluginClassloaderFactory.class, CePluginJarExploder.class, PluginLoader.class, CePluginRepository.class, InstalledPluginReferentialFactory.class, ComputeEngineExtensionInstaller.class, // depends on plugins DefaultI18n.class, // used by RuleI18nManager RuleI18nManager.class, // used by DebtRulesXMLImporter Durations.class, // used in Web Services and DebtCalculator }; } private static Object[] level3Components() { return new Object[] { new StartupMetadataProvider(), ServerIdManager.class, UriReader.class, ServerImpl.class, DefaultOrganizationProviderImpl.class }; } private static Object[] level4Components() { return new Object[] { ResourceTypes.class, DefaultResourceTypes.get(), Periods.class, BillingValidationsProxyImpl.class, // quality profile ActiveRuleIndexer.class, XMLProfileParser.class, XMLProfileSerializer.class, AnnotationProfileParser.class, Rules.QProfiles.class, // rule AnnotationRuleParser.class, XMLRuleParser.class, DefaultRuleFinder.class, DeprecatedRulesDefinitionLoader.class, CommonRuleDefinitionsImpl.class, RuleDefinitionsLoader.class, RulesDefinitionXmlLoader.class, // languages Languages.class, // used by CommonRuleDefinitionsImpl // measure CoreCustomMetrics.class, DefaultMetricFinder.class, // users DeprecatedUserFinder.class, DefaultUserFinder.class, UserIndexer.class, UserIndex.class, // permissions DefaultTemplatesResolverImpl.class, PermissionTemplateService.class, PermissionUpdater.class, UserPermissionChanger.class, GroupPermissionChanger.class, // components ComponentFinder.class, // used in ComponentService NewAlerts.class, NewAlerts.newMetadata(), ComponentCleanerService.class, ProjectMeasuresIndexer.class, ComponentIndexer.class, // views ViewIndexer.class, ViewIndex.class, // issues IssueIndexer.class, IssueIteratorFactory.class, PermissionIndexer.class, IssueFieldsSetter.class, // used in Web Services and CE's DebtCalculator FunctionExecutor.class, // used by IssueWorkflow IssueWorkflow.class, // used in Web Services and CE's DebtCalculator NewIssuesEmailTemplate.class, MyNewIssuesEmailTemplate.class, IssueChangesEmailTemplate.class, ChangesOnMyIssueNotificationDispatcher.class, ChangesOnMyIssueNotificationDispatcher.newMetadata(), NewIssuesNotificationDispatcher.class, NewIssuesNotificationDispatcher.newMetadata(), MyNewIssuesNotificationDispatcher.class, MyNewIssuesNotificationDispatcher.newMetadata(), DoNotFixNotificationDispatcher.class, DoNotFixNotificationDispatcher.newMetadata(), NewIssuesNotificationFactory.class, // used by SendIssueNotificationsStep // technical debt DebtModelPluginRepository.class, DebtRulesXMLImporter.class, // Notifications AlertsEmailTemplate.class, EmailSettings.class, NotificationService.class, DefaultNotificationManager.class, EmailNotificationChannel.class, // Tests TestIndexer.class, // System ServerLogging.class, // privileged plugins PrivilegedPluginsBootstraper.class, PrivilegedPluginsStopper.class, // Compute engine (must be after Views and Developer Cockpit) CeConfigurationModule.class, CeQueueModule.class, CeHttpModule.class, CeTaskCommonsModule.class, ProjectAnalysisTaskModule.class, CeTaskProcessorModule.class, InternalPropertiesImpl.class, ProjectSettingsFactory.class, // cleaning CeCleaningModule.class }; } private static Object[] startupComponents() { return new Object[] { LogServerId.class, ServerLifecycleNotifier.class, PurgeCeActivities.class, CeQueueCleaner.class }; } 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); } } }