package org.sonar.server.platform;
import com.google.common.collect.Lists;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
import org.apache.commons.configuration.BaseConfiguration;
import org.sonar.api.config.EmailSettings;
import org.sonar.api.issue.action.Actions;
import org.sonar.core.metric.DefaultMetricFinder;
import org.sonar.core.notification.DefaultNotificationManager;
import org.sonar.core.permission.PermissionFacade;
-import org.sonar.core.persistence.*;
+import org.sonar.core.persistence.DaoUtils;
+import org.sonar.core.persistence.DatabaseVersion;
+import org.sonar.core.persistence.DefaultDatabase;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.persistence.PreviewDatabaseFactory;
+import org.sonar.core.persistence.SemaphoreUpdater;
+import org.sonar.core.persistence.SemaphoresImpl;
import org.sonar.core.preview.PreviewCache;
import org.sonar.core.profiling.Profiling;
import org.sonar.core.purge.PurgeProfiler;
import org.sonar.server.activity.ws.ActivitiesWebService;
import org.sonar.server.activity.ws.ActivityMapping;
import org.sonar.server.authentication.ws.AuthenticationWs;
-import org.sonar.server.batch.*;
+import org.sonar.server.batch.BatchIndex;
+import org.sonar.server.batch.BatchWs;
+import org.sonar.server.batch.GlobalReferentialsAction;
+import org.sonar.server.batch.ProjectReferentialsAction;
+import org.sonar.server.batch.ProjectReferentialsLoader;
import org.sonar.server.charts.ChartFactory;
import org.sonar.server.component.DefaultComponentFinder;
import org.sonar.server.component.DefaultRubyComponentService;
import org.sonar.server.component.persistence.ComponentDao;
import org.sonar.server.component.persistence.SnapshotDao;
-import org.sonar.server.component.ws.*;
+import org.sonar.server.component.ws.ComponentAppAction;
+import org.sonar.server.component.ws.ComponentsWs;
+import org.sonar.server.component.ws.EventsWs;
+import org.sonar.server.component.ws.ProjectsWs;
+import org.sonar.server.component.ws.ResourcesWs;
import org.sonar.server.config.ws.PropertiesWs;
import org.sonar.server.db.DatabaseChecker;
import org.sonar.server.db.DbClient;
import org.sonar.server.db.EmbeddedDatabaseFactory;
import org.sonar.server.db.migrations.DatabaseMigrations;
import org.sonar.server.db.migrations.DatabaseMigrator;
-import org.sonar.server.debt.*;
+import org.sonar.server.debt.DebtCharacteristicsXMLImporter;
+import org.sonar.server.debt.DebtModelBackup;
+import org.sonar.server.debt.DebtModelLookup;
+import org.sonar.server.debt.DebtModelOperations;
+import org.sonar.server.debt.DebtModelPluginRepository;
+import org.sonar.server.debt.DebtModelService;
+import org.sonar.server.debt.DebtModelXMLExporter;
+import org.sonar.server.debt.DebtRulesXMLImporter;
import org.sonar.server.duplication.ws.DuplicationsJsonWriter;
import org.sonar.server.duplication.ws.DuplicationsParser;
import org.sonar.server.duplication.ws.DuplicationsWs;
-import org.sonar.server.issue.*;
+import org.sonar.server.issue.ActionService;
+import org.sonar.server.issue.AssignAction;
+import org.sonar.server.issue.CommentAction;
+import org.sonar.server.issue.DefaultIssueFinder;
+import org.sonar.server.issue.InternalRubyIssueService;
+import org.sonar.server.issue.IssueBulkChangeService;
+import org.sonar.server.issue.IssueChangelogFormatter;
+import org.sonar.server.issue.IssueChangelogService;
+import org.sonar.server.issue.IssueCommentService;
+import org.sonar.server.issue.IssueService;
+import org.sonar.server.issue.IssueStatsFinder;
+import org.sonar.server.issue.PlanAction;
+import org.sonar.server.issue.PublicRubyIssueService;
+import org.sonar.server.issue.ServerIssueStorage;
+import org.sonar.server.issue.SetSeverityAction;
+import org.sonar.server.issue.TransitionAction;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.issue.actionplan.ActionPlanWs;
import org.sonar.server.issue.db.IssueDao;
import org.sonar.server.platform.ws.RestartHandler;
import org.sonar.server.platform.ws.ServerWs;
import org.sonar.server.platform.ws.SystemWs;
-import org.sonar.server.plugins.*;
+import org.sonar.server.plugins.InstalledPluginReferentialFactory;
+import org.sonar.server.plugins.PluginDownloader;
+import org.sonar.server.plugins.ServerExtensionInstaller;
+import org.sonar.server.plugins.ServerPluginJarInstaller;
+import org.sonar.server.plugins.ServerPluginJarsInstaller;
+import org.sonar.server.plugins.ServerPluginRepository;
+import org.sonar.server.plugins.UpdateCenterClient;
+import org.sonar.server.plugins.UpdateCenterMatrixFactory;
import org.sonar.server.qualitygate.QgateProjectFinder;
import org.sonar.server.qualitygate.QualityGates;
import org.sonar.server.qualitygate.RegisterQualityGates;
-import org.sonar.server.qualitygate.ws.*;
-import org.sonar.server.qualityprofile.*;
+import org.sonar.server.qualitygate.ws.QGatesAppAction;
+import org.sonar.server.qualitygate.ws.QGatesCopyAction;
+import org.sonar.server.qualitygate.ws.QGatesCreateAction;
+import org.sonar.server.qualitygate.ws.QGatesCreateConditionAction;
+import org.sonar.server.qualitygate.ws.QGatesDeleteConditionAction;
+import org.sonar.server.qualitygate.ws.QGatesDeselectAction;
+import org.sonar.server.qualitygate.ws.QGatesDestroyAction;
+import org.sonar.server.qualitygate.ws.QGatesListAction;
+import org.sonar.server.qualitygate.ws.QGatesRenameAction;
+import org.sonar.server.qualitygate.ws.QGatesSearchAction;
+import org.sonar.server.qualitygate.ws.QGatesSelectAction;
+import org.sonar.server.qualitygate.ws.QGatesSetAsDefaultAction;
+import org.sonar.server.qualitygate.ws.QGatesShowAction;
+import org.sonar.server.qualitygate.ws.QGatesUnsetDefaultAction;
+import org.sonar.server.qualitygate.ws.QGatesUpdateConditionAction;
+import org.sonar.server.qualitygate.ws.QGatesWs;
+import org.sonar.server.qualityprofile.BuiltInProfiles;
+import org.sonar.server.qualityprofile.QProfileBackuper;
+import org.sonar.server.qualityprofile.QProfileCopier;
+import org.sonar.server.qualityprofile.QProfileExporters;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileLoader;
+import org.sonar.server.qualityprofile.QProfileLookup;
+import org.sonar.server.qualityprofile.QProfileProjectLookup;
+import org.sonar.server.qualityprofile.QProfileProjectOperations;
+import org.sonar.server.qualityprofile.QProfileReset;
+import org.sonar.server.qualityprofile.QProfileService;
+import org.sonar.server.qualityprofile.QProfiles;
+import org.sonar.server.qualityprofile.RegisterQualityProfiles;
+import org.sonar.server.qualityprofile.RuleActivator;
+import org.sonar.server.qualityprofile.RuleActivatorContextFactory;
import org.sonar.server.qualityprofile.db.ActiveRuleDao;
import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
-import org.sonar.server.qualityprofile.ws.*;
-import org.sonar.server.rule.*;
+import org.sonar.server.qualityprofile.ws.BulkRuleActivationActions;
+import org.sonar.server.qualityprofile.ws.ProfilesWs;
+import org.sonar.server.qualityprofile.ws.QProfileRestoreBuiltInAction;
+import org.sonar.server.qualityprofile.ws.QProfilesWs;
+import org.sonar.server.qualityprofile.ws.RuleActivationActions;
+import org.sonar.server.rule.DefaultRuleFinder;
+import org.sonar.server.rule.DeprecatedRulesDefinitionLoader;
+import org.sonar.server.rule.RegisterRules;
+import org.sonar.server.rule.RubyRuleService;
+import org.sonar.server.rule.RuleCreator;
+import org.sonar.server.rule.RuleDefinitionsLoader;
+import org.sonar.server.rule.RuleDeleter;
+import org.sonar.server.rule.RuleOperations;
+import org.sonar.server.rule.RuleRepositories;
+import org.sonar.server.rule.RuleService;
+import org.sonar.server.rule.RuleUpdater;
import org.sonar.server.rule.db.RuleDao;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.rule.index.RuleNormalizer;
-import org.sonar.server.rule.ws.*;
-import org.sonar.server.search.*;
+import org.sonar.server.rule.ws.ActiveRuleCompleter;
+import org.sonar.server.rule.ws.AppAction;
+import org.sonar.server.rule.ws.DeleteAction;
+import org.sonar.server.rule.ws.RuleMapping;
+import org.sonar.server.rule.ws.RulesWebService;
+import org.sonar.server.rule.ws.SearchAction;
+import org.sonar.server.rule.ws.TagsAction;
+import org.sonar.server.rule.ws.UpdateAction;
+import org.sonar.server.search.IndexClient;
+import org.sonar.server.search.IndexQueue;
+import org.sonar.server.search.IndexSynchronizer;
+import org.sonar.server.search.SearchClient;
+import org.sonar.server.search.SearchHealth;
import org.sonar.server.source.CodeColorizers;
import org.sonar.server.source.DeprecatedSourceDecorator;
import org.sonar.server.source.HtmlSourceDecorator;
import org.sonar.server.source.ws.ScmWriter;
import org.sonar.server.source.ws.ShowAction;
import org.sonar.server.source.ws.SourcesWs;
-import org.sonar.server.startup.*;
+import org.sonar.server.startup.CleanPreviewAnalysisCache;
+import org.sonar.server.startup.ClearRulesOverloadedDebt;
+import org.sonar.server.startup.CopyRequirementsFromCharacteristicsToRules;
+import org.sonar.server.startup.GeneratePluginIndex;
+import org.sonar.server.startup.GwtPublisher;
+import org.sonar.server.startup.JdbcDriverDeployer;
+import org.sonar.server.startup.LogServerId;
+import org.sonar.server.startup.RegisterDashboards;
+import org.sonar.server.startup.RegisterDebtModel;
+import org.sonar.server.startup.RegisterMetrics;
+import org.sonar.server.startup.RegisterNewMeasureFilters;
+import org.sonar.server.startup.RegisterPermissionTemplates;
+import org.sonar.server.startup.RegisterServletFilters;
+import org.sonar.server.startup.RenameDeprecatedPropertyKeys;
+import org.sonar.server.startup.ServerMetadataPersister;
import org.sonar.server.test.CoverageService;
-import org.sonar.server.test.ws.*;
+import org.sonar.server.test.ws.CoverageShowAction;
+import org.sonar.server.test.ws.CoverageWs;
+import org.sonar.server.test.ws.TestsCoveredFilesAction;
+import org.sonar.server.test.ws.TestsShowAction;
+import org.sonar.server.test.ws.TestsTestCasesAction;
+import org.sonar.server.test.ws.TestsWs;
import org.sonar.server.text.MacroInterpreter;
import org.sonar.server.text.RubyTextService;
import org.sonar.server.ui.JRubyI18n;
import org.sonar.server.ui.PageDecorations;
import org.sonar.server.ui.Views;
import org.sonar.server.updatecenter.ws.UpdateCenterWs;
-import org.sonar.server.user.*;
+import org.sonar.server.user.DefaultUserService;
+import org.sonar.server.user.DoPrivileged;
+import org.sonar.server.user.GroupMembershipFinder;
+import org.sonar.server.user.GroupMembershipService;
+import org.sonar.server.user.NewUserNotifier;
+import org.sonar.server.user.SecurityRealmFactory;
import org.sonar.server.user.ws.FavoritesWs;
import org.sonar.server.user.ws.UserPropertiesWs;
import org.sonar.server.user.ws.UsersWs;
-import org.sonar.server.util.*;
+import org.sonar.server.util.BooleanTypeValidation;
+import org.sonar.server.util.FloatTypeValidation;
+import org.sonar.server.util.IntegerTypeValidation;
+import org.sonar.server.util.StringListTypeValidation;
+import org.sonar.server.util.StringTypeValidation;
+import org.sonar.server.util.TextTypeValidation;
+import org.sonar.server.util.TypeValidations;
import org.sonar.server.ws.ListingWs;
import org.sonar.server.ws.WebServiceEngine;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
class ServerComponents {
private final Object[] rootComponents;
startupContainer.addSingleton(RegisterServletFilters.class);
startupContainer.addSingleton(CleanPreviewAnalysisCache.class);
startupContainer.addSingleton(CopyRequirementsFromCharacteristicsToRules.class);
+ startupContainer.addSingleton(ClearRulesOverloadedDebt.class);
DoPrivileged.execute(new DoPrivileged.Task() {
@Override
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.startup;
+
+import org.picocontainer.Startable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.template.LoadedTemplateDto;
+import org.sonar.server.db.DbClient;
+
+import static org.sonar.core.template.LoadedTemplateDto.ONE_SHOT_TASK_TYPE;
+
+/**
+ * Clear the overloaded technical debt of rules when SQALE plugin is not installed.
+ * See <a href="https://jira.sonarsource.com/browse/SONAR-6547">SONAR-6547</a>.
+ *
+ * Should be removed after LTS 5.X
+ *
+ * @since 5.2
+ */
+public class ClearRulesOverloadedDebt implements Startable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ClearRulesOverloadedDebt.class);
+
+ private static final String TEMPLATE_KEY = "ClearRulesOverloadedDebt";
+
+ private static final String SQALE_LICENSE_PROPERTY = "sonar.sqale.licenseHash.secured";
+
+ private final DbClient dbClient;
+
+ public ClearRulesOverloadedDebt(DbClient dbClient) {
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ public void start() {
+ DbSession session = dbClient.openSession(false);
+ try {
+ if (hasAlreadyBeenExecuted(session)) {
+ return;
+ }
+ if (!isSqalePluginInstalled(session)) {
+ clearDebt(session);
+ }
+ markAsExecuted(session);
+ session.commit();
+ } finally {
+ session.close();
+ }
+ }
+
+ private void clearDebt(DbSession session) {
+ int countClearedRules = 0;
+ for (RuleDto rule : dbClient.ruleDao().findAll(session)) {
+ if (isDebtOverridden(rule)) {
+ rule.setSubCharacteristicId(null);
+ rule.setRemediationFunction(null);
+ rule.setRemediationCoefficient(null);
+ rule.setRemediationOffset(null);
+ dbClient.ruleDao().update(session, rule);
+ countClearedRules++;
+ }
+ }
+ if (countClearedRules > 0) {
+ LOG.warn("The SQALE model has been cleaned to remove useless data left over by previous migrations. The technical debt of {} rules was reset to their default values.",
+ countClearedRules);
+ LOG.warn("=> As a consequence, the overall technical debt of your projects might slightly evolve during the next analysis.");
+ }
+ }
+
+ private static boolean isDebtOverridden(RuleDto ruleDto) {
+ return ruleDto.getSubCharacteristicId() != null || ruleDto.getRemediationFunction() != null || ruleDto.getRemediationCoefficient() != null
+ || ruleDto.getRemediationOffset() != null;
+ }
+
+ private boolean isSqalePluginInstalled(DbSession session) {
+ return dbClient.propertiesDao().selectGlobalProperty(session, SQALE_LICENSE_PROPERTY) != null;
+ }
+
+ private boolean hasAlreadyBeenExecuted(DbSession session) {
+ return dbClient.loadedTemplateDao().countByTypeAndKey(ONE_SHOT_TASK_TYPE, TEMPLATE_KEY, session) > 0;
+ }
+
+ private void markAsExecuted(DbSession session) {
+ dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(TEMPLATE_KEY, ONE_SHOT_TASK_TYPE), session);
+ }
+
+ @Override
+ public void stop() {
+ // Nothing to do
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.startup;
+
+import java.util.Date;
+import javax.annotation.Nullable;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.properties.PropertyDto;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.rule.Rule;
+import org.sonar.server.rule.RuleTesting;
+import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.rule.index.RuleIndex;
+import org.sonar.server.tester.ServerTester;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.sonar.core.template.LoadedTemplateDto.ONE_SHOT_TASK_TYPE;
+import static org.sonar.server.rule.RuleTesting.XOO_X1;
+import static org.sonar.server.rule.RuleTesting.XOO_X2;
+import static org.sonar.server.rule.RuleTesting.XOO_X3;
+
+public class ClearRulesOverloadedDebtTest {
+
+ static final int SUB_CHARACTERISTIC_ID = 1;
+
+ private static final RuleKey RULE_KEY_1 = XOO_X1;
+ private static final RuleKey RULE_KEY_2 = XOO_X2;
+ private static final RuleKey RULE_KEY_3 = XOO_X3;
+
+ @ClassRule
+ public static ServerTester tester = new ServerTester();
+
+ RuleDao ruleDao = tester.get(RuleDao.class);
+ RuleIndex ruleIndex = tester.get(RuleIndex.class);
+ DbClient dbClient = tester.get(DbClient.class);
+ DbSession dbSession = tester.get(DbClient.class).openSession(false);
+
+ ClearRulesOverloadedDebt underTest = new ClearRulesOverloadedDebt(dbClient);
+
+ @Before
+ public void before() {
+ tester.clearDbAndIndexes();
+ }
+
+ @After
+ public void after() {
+ dbSession.close();
+ }
+
+ @Test
+ public void remove_overridden_debt() throws Exception {
+ // Characteristic and remediation function is overridden
+ insertRuleDto(RULE_KEY_1, SUB_CHARACTERISTIC_ID, "LINEAR", null, "1d");
+ // Only characteristic is overridden
+ insertRuleDto(RULE_KEY_2, SUB_CHARACTERISTIC_ID, null, null, null);
+ // Only remediation function is overridden
+ insertRuleDto(RULE_KEY_3, null, "CONSTANT_ISSUE", "5min", null);
+
+ underTest.start();
+
+ verifyRuleHasNotOverriddenDebt(RULE_KEY_1);
+ verifyRuleHasNotOverriddenDebt(RULE_KEY_2);
+ verifyRuleHasNotOverriddenDebt(RULE_KEY_3);
+ verifyTaskRegistered();
+ }
+
+ @Test
+ public void not_update_rule_debt_not_overridden() throws Exception {
+ RuleDto rule = insertRuleDto(RULE_KEY_1, null, null, null, null);
+ Date updateAt = rule.getUpdatedAt();
+
+ underTest.start();
+
+ RuleDto reloaded = ruleDao.getByKey(dbSession, RULE_KEY_1);
+ assertThat(reloaded.getUpdatedAt()).isEqualTo(updateAt);
+ verifyRuleHasNotOverriddenDebt(RULE_KEY_1);
+
+ verifyTaskRegistered();
+ }
+
+ @Test
+ public void not_update_rule_debt_when_sqale_is_installed() throws Exception {
+ insertSqaleProperty();
+ RuleDto rule = insertRuleDto(RULE_KEY_1, SUB_CHARACTERISTIC_ID, "LINEAR", null, "1d");
+ Date updateAt = rule.getUpdatedAt();
+
+ underTest.start();
+
+ RuleDto reloaded = ruleDao.getByKey(dbSession, RULE_KEY_1);
+ assertThat(reloaded.getUpdatedAt()).isEqualTo(updateAt);
+
+ Rule ruleEs = ruleIndex.getByKey(RULE_KEY_1);
+ assertThat(ruleEs.debtOverloaded()).isTrue();
+
+ verifyTaskRegistered();
+ }
+
+ private void verifyRuleHasNotOverriddenDebt(RuleKey ruleKey) {
+ // Refresh session
+ dbSession.commit(true);
+
+ RuleDto ruleDto = ruleDao.getByKey(dbSession, ruleKey);
+ assertThat(ruleDto.getSubCharacteristicId()).isNull();
+ assertThat(ruleDto.getRemediationFunction()).isNull();
+ assertThat(ruleDto.getRemediationCoefficient()).isNull();
+ assertThat(ruleDto.getRemediationOffset()).isNull();
+
+ Rule rule = ruleIndex.getByKey(ruleKey);
+ assertThat(rule.debtOverloaded()).isFalse();
+ }
+
+ private RuleDto insertRuleDto(RuleKey ruleKey, @Nullable Integer subCharId, @Nullable String function, @Nullable String coeff, @Nullable String offset) {
+ RuleDto ruleDto = RuleTesting.newDto(ruleKey)
+ .setSubCharacteristicId(subCharId)
+ .setRemediationFunction(function)
+ .setRemediationOffset(offset)
+ .setRemediationCoefficient(coeff);
+ ruleDao.insert(dbSession,
+ ruleDto
+ );
+ dbSession.commit();
+ return ruleDto;
+ }
+
+ private void insertSqaleProperty() {
+ dbClient.propertiesDao().setProperty(new PropertyDto().setKey("sonar.sqale.licenseHash.secured").setValue("ABCD"), dbSession);
+ dbSession.commit();
+ }
+
+ private void verifyTaskRegistered() {
+ assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(ONE_SHOT_TASK_TYPE, "ClearRulesOverloadedDebt")).isEqualTo(1);
+ }
+
+}