org.sonar.server.debt.DebtModelBackup.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.debt.DebtModelBackup.java

Source

/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact 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.debt;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import java.util.Date;
import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.debt.DebtModelXMLExporter.RuleDebt;
import org.sonar.server.rule.RuleDefinitionsLoader;
import org.sonar.server.rule.RuleOperations;
import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.user.UserSession;

import static com.google.common.collect.Lists.newArrayList;

@ServerSide
public class DebtModelBackup {

    private static final Logger LOG = Loggers.get(DebtModelBackup.class);

    private final DbClient dbClient;
    private final RuleOperations ruleOperations;
    private final DebtRulesXMLImporter rulesXMLImporter;
    private final DebtModelXMLExporter debtModelXMLExporter;
    private final RuleDefinitionsLoader defLoader;
    private final System2 system2;
    private final UserSession userSession;
    private final RuleIndexer ruleIndexer;

    public DebtModelBackup(DbClient dbClient, RuleOperations ruleOperations, DebtRulesXMLImporter rulesXMLImporter,
            DebtModelXMLExporter debtModelXMLExporter, RuleDefinitionsLoader defLoader, System2 system2,
            UserSession userSession, RuleIndexer ruleIndexer) {
        this.dbClient = dbClient;
        this.ruleOperations = ruleOperations;
        this.rulesXMLImporter = rulesXMLImporter;
        this.debtModelXMLExporter = debtModelXMLExporter;
        this.defLoader = defLoader;
        this.system2 = system2;
        this.userSession = userSession;
        this.ruleIndexer = ruleIndexer;
    }

    public String backup() {
        return backupFromLanguage(null);
    }

    public String backup(String languageKey) {
        return backupFromLanguage(languageKey);
    }

    private String backupFromLanguage(@Nullable String languageKey) {
        checkPermission();

        DbSession session = dbClient.openSession(false);
        try {
            List<RuleDebt> rules = newArrayList();
            for (RuleDto rule : dbClient.ruleDao().selectEnabled(session)) {
                if (languageKey != null && !languageKey.equals(rule.getLanguage())) {
                    continue;
                }
                RuleDebt ruleDebt = toRuleDebt(rule);
                if (ruleDebt != null) {
                    rules.add(ruleDebt);
                }
            }
            return debtModelXMLExporter.export(rules);
        } finally {
            MyBatis.closeQuietly(session);
        }
    }

    /**
     * Reset from provided model
     */
    public void reset() {
        checkPermission();

        long updateDate = system2.now();
        DbSession session = dbClient.openSession(false);
        try {
            // Restore rules
            List<RuleDto> ruleDtos = dbClient.ruleDao().selectEnabled(session);
            if (!ruleDtos.isEmpty()) {

                // Load default rule definitions
                RulesDefinition.Context context = defLoader.load();
                List<RulesDefinition.Rule> rules = newArrayList();
                for (RulesDefinition.Repository repoDef : context.repositories()) {
                    rules.addAll(repoDef.rules());
                }

                resetRules(ruleDtos, rules, updateDate, session);
            }

            session.commit();
            ruleIndexer.index();
        } finally {
            MyBatis.closeQuietly(session);
        }
    }

    private void resetRules(List<RuleDto> ruleDtos, List<RulesDefinition.Rule> rules, long updateDate,
            DbSession session) {
        for (RuleDto rule : ruleDtos) {
            // Restore default debt definitions

            RulesDefinition.Rule ruleDef;
            Integer ruleTemplateId = rule.getTemplateId();
            if (ruleTemplateId != null) {
                RuleDto templateRule = rule(ruleTemplateId, ruleDtos);
                ruleDef = ruleDef(templateRule.getRepositoryKey(), templateRule.getRuleKey(), rules);
            } else {
                ruleDef = ruleDef(rule.getRepositoryKey(), rule.getRuleKey(), rules);
            }

            if (ruleDef != null) {
                DebtRemediationFunction remediationFunction = ruleDef.debtRemediationFunction();
                boolean hasDebtDefinition = remediationFunction != null;

                rule.setDefaultRemediationFunction(hasDebtDefinition ? remediationFunction.type().name() : null);
                rule.setDefaultRemediationGapMultiplier(
                        hasDebtDefinition ? remediationFunction.gapMultiplier() : null);
                rule.setDefaultRemediationBaseEffort(hasDebtDefinition ? remediationFunction.baseEffort() : null);
            }

            // Reset overridden debt definitions
            rule.setRemediationFunction(null);
            rule.setRemediationGapMultiplier(null);
            rule.setRemediationBaseEffort(null);
            rule.setUpdatedAt(updateDate);
            dbClient.ruleDao().update(session, rule);
        }
    }

    /**
     * Restore model from a given XML model (characteristics and rule debt are restored from XML)
     */
    public ValidationMessages restoreFromXml(String xml) {
        return restoreXmlModel(xml, null);
    }

    /**
     * Restore model from a given XML model and a given language (only debt of rules on given language are restored from XML)
     */
    public ValidationMessages restoreFromXml(String xml, final String languageKey) {
        return restoreXmlModel(xml, languageKey);
    }

    private ValidationMessages restoreXmlModel(String xml, @Nullable final String languageKey) {
        checkPermission();

        ValidationMessages validationMessages = ValidationMessages.create();
        Date updateDate = new Date(system2.now());
        DbSession session = dbClient.openSession(false);
        try {
            restoreRules(rules(languageKey, session), rulesXMLImporter.importXML(xml, validationMessages),
                    validationMessages, updateDate, session);

            session.commit();
            ruleIndexer.index();
        } catch (IllegalArgumentException e) {
            LOG.debug("Error when restoring the model", e);
            validationMessages.addErrorText(e.getMessage());
        } finally {
            MyBatis.closeQuietly(session);
        }
        return validationMessages;
    }

    private void restoreRules(List<RuleDto> rules, List<RuleDebt> ruleDebts, ValidationMessages validationMessages,
            Date updateDate, DbSession session) {
        for (RuleDto rule : rules) {
            RuleDebt ruleDebt = ruleDebt(rule.getRepositoryKey(), rule.getRuleKey(), ruleDebts);
            ruleOperations.updateRule(rule, ruleDebt != null ? ruleDebt.function() : null,
                    ruleDebt != null ? ruleDebt.coefficient() : null, ruleDebt != null ? ruleDebt.offset() : null,
                    session);
            rule.setUpdatedAt(updateDate.getTime());
            ruleDebts.remove(ruleDebt);
        }

        for (RuleDebt ruleDebt : ruleDebts) {
            validationMessages.addWarningText(String.format("The rule '%s' does not exist.", ruleDebt.ruleKey()));
        }
    }

    private List<RuleDto> rules(@Nullable String languageKey, DbSession session) {
        List<RuleDto> rules = dbClient.ruleDao().selectEnabled(session);
        if (languageKey == null) {
            return rules;
        }
        return newArrayList(Iterables.filter(rules, new RuleDtoMatchLanguage(languageKey)));
    }

    @CheckForNull
    private static RuleDebt ruleDebt(String ruleRepo, String ruleKey, List<RuleDebt> ruleDebts) {
        if (ruleDebts.isEmpty()) {
            return null;
        }
        return Iterables.find(ruleDebts, new RuleDebtMatchRuleRepoAndRuleKey(ruleRepo, ruleKey), null);
    }

    private static RuleDto rule(int id, List<RuleDto> rules) {
        return Iterables.find(rules, new RuleDtoMatchId(id));
    }

    @CheckForNull
    private static RulesDefinition.Rule ruleDef(String ruleRepo, String ruleKey, List<RulesDefinition.Rule> rules) {
        return Iterables.find(rules, new RuleDefMatchRuleRepoAndRuleKey(ruleRepo, ruleKey), null);
    }

    @CheckForNull
    private static RuleDebt toRuleDebt(RuleDto rule) {
        RuleDebt ruleDebt = new RuleDebt().setRuleKey(RuleKey.of(rule.getRepositoryKey(), rule.getRuleKey()));
        String overriddenFunction = rule.getRemediationFunction();
        String defaultFunction = rule.getDefaultRemediationFunction();
        if (overriddenFunction != null) {
            ruleDebt.setFunction(overriddenFunction);
            ruleDebt.setCoefficient(rule.getRemediationGapMultiplier());
            ruleDebt.setOffset(rule.getRemediationBaseEffort());
            return ruleDebt;
        } else if (defaultFunction != null) {
            ruleDebt.setFunction(defaultFunction);
            ruleDebt.setCoefficient(rule.getDefaultRemediationGapMultiplier());
            ruleDebt.setOffset(rule.getDefaultRemediationBaseEffort());
            return ruleDebt;
        }
        return null;
    }

    private void checkPermission() {
        userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN);
    }

    private static class RuleDtoMatchLanguage implements Predicate<RuleDto> {
        private final String languageKey;

        public RuleDtoMatchLanguage(String languageKey) {
            this.languageKey = languageKey;
        }

        @Override
        public boolean apply(@Nonnull RuleDto input) {
            return languageKey.equals(input.getLanguage());
        }
    }

    private static class RuleDebtMatchRuleRepoAndRuleKey implements Predicate<RuleDebt> {

        private final String ruleRepo;
        private final String ruleKey;

        public RuleDebtMatchRuleRepoAndRuleKey(String ruleRepo, String ruleKey) {
            this.ruleRepo = ruleRepo;
            this.ruleKey = ruleKey;
        }

        @Override
        public boolean apply(@Nullable RuleDebt input) {
            return input != null && ruleRepo.equals(input.ruleKey().repository())
                    && ruleKey.equals(input.ruleKey().rule());
        }
    }

    private static class RuleDtoMatchId implements Predicate<RuleDto> {
        private final int id;

        public RuleDtoMatchId(int id) {
            this.id = id;
        }

        @Override
        public boolean apply(@Nonnull RuleDto input) {
            return id == input.getId();
        }
    }

    private static class RuleDefMatchRuleRepoAndRuleKey implements Predicate<RulesDefinition.Rule> {

        private final String ruleRepo;
        private final String ruleKey;

        public RuleDefMatchRuleRepoAndRuleKey(String ruleRepo, String ruleKey) {
            this.ruleRepo = ruleRepo;
            this.ruleKey = ruleKey;
        }

        @Override
        public boolean apply(@Nonnull RulesDefinition.Rule input) {
            return ruleRepo.equals(input.repository().key()) && ruleKey.equals(input.key());
        }
    }
}