You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DeprecatedRulesDefinitionLoader.java 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.rule;
  21. import com.google.common.base.Predicate;
  22. import com.google.common.collect.Iterables;
  23. import java.io.Reader;
  24. import java.util.Collection;
  25. import java.util.List;
  26. import javax.annotation.CheckForNull;
  27. import javax.annotation.Nonnull;
  28. import javax.annotation.Nullable;
  29. import org.apache.commons.io.IOUtils;
  30. import org.apache.commons.lang.StringUtils;
  31. import org.sonar.api.rule.RuleKey;
  32. import org.sonar.api.rule.RuleStatus;
  33. import org.sonar.api.rules.RuleParam;
  34. import org.sonar.api.rules.RuleRepository;
  35. import org.sonar.api.server.ServerSide;
  36. import org.sonar.api.server.debt.DebtRemediationFunction;
  37. import org.sonar.api.server.rule.RuleParamType;
  38. import org.sonar.api.server.rule.RulesDefinition;
  39. import org.sonar.api.utils.ValidationMessages;
  40. import org.sonar.api.utils.log.Logger;
  41. import org.sonar.api.utils.log.Loggers;
  42. import org.sonar.core.i18n.RuleI18nManager;
  43. import org.sonar.server.debt.DebtModelPluginRepository;
  44. import org.sonar.server.debt.DebtModelXMLExporter;
  45. import org.sonar.server.debt.DebtModelXMLExporter.RuleDebt;
  46. import org.sonar.server.debt.DebtRulesXMLImporter;
  47. import org.sonar.server.plugins.ServerPluginRepository;
  48. import static com.google.common.collect.Lists.newArrayList;
  49. /**
  50. * Inject deprecated RuleRepository into {@link org.sonar.api.server.rule.RulesDefinition} for backward-compatibility.
  51. */
  52. @ServerSide
  53. public class DeprecatedRulesDefinitionLoader {
  54. private static final Logger LOG = Loggers.get(DeprecatedRulesDefinitionLoader.class);
  55. private final RuleI18nManager i18n;
  56. private final RuleRepository[] repositories;
  57. private final DebtModelPluginRepository languageModelFinder;
  58. private final DebtRulesXMLImporter importer;
  59. private final ServerPluginRepository serverPluginRepository;
  60. public DeprecatedRulesDefinitionLoader(RuleI18nManager i18n, DebtModelPluginRepository languageModelFinder, DebtRulesXMLImporter importer,
  61. ServerPluginRepository serverPluginRepository, RuleRepository[] repositories) {
  62. this.i18n = i18n;
  63. this.serverPluginRepository = serverPluginRepository;
  64. this.repositories = repositories;
  65. this.languageModelFinder = languageModelFinder;
  66. this.importer = importer;
  67. }
  68. /**
  69. * Used when no deprecated repositories
  70. */
  71. public DeprecatedRulesDefinitionLoader(RuleI18nManager i18n, DebtModelPluginRepository languageModelFinder, DebtRulesXMLImporter importer,
  72. ServerPluginRepository serverPluginRepository) {
  73. this(i18n, languageModelFinder, importer, serverPluginRepository, new RuleRepository[0]);
  74. }
  75. void complete(RulesDefinition.Context context) {
  76. // Load rule debt definitions from xml files provided by plugin
  77. List<RuleDebt> ruleDebts = loadRuleDebtList();
  78. for (RuleRepository repository : repositories) {
  79. context.setCurrentPluginKey(serverPluginRepository.getPluginKey(repository));
  80. // RuleRepository API does not handle difference between new and extended repositories,
  81. RulesDefinition.NewRepository newRepository;
  82. if (context.repository(repository.getKey()) == null) {
  83. newRepository = context.createRepository(repository.getKey(), repository.getLanguage());
  84. newRepository.setName(repository.getName());
  85. } else {
  86. newRepository = context.extendRepository(repository.getKey(), repository.getLanguage());
  87. }
  88. for (org.sonar.api.rules.Rule rule : repository.createRules()) {
  89. RulesDefinition.NewRule newRule = newRepository.createRule(rule.getKey());
  90. newRule.setName(ruleName(repository.getKey(), rule));
  91. newRule.setHtmlDescription(ruleDescription(repository.getKey(), rule));
  92. newRule.setInternalKey(rule.getConfigKey());
  93. newRule.setTemplate(rule.isTemplate());
  94. newRule.setSeverity(rule.getSeverity().toString());
  95. newRule.setStatus(rule.getStatus() == null ? RuleStatus.defaultStatus() : RuleStatus.valueOf(rule.getStatus()));
  96. newRule.setTags(rule.getTags());
  97. for (RuleParam param : rule.getParams()) {
  98. RulesDefinition.NewParam newParam = newRule.createParam(param.getKey());
  99. newParam.setDefaultValue(param.getDefaultValue());
  100. newParam.setDescription(paramDescription(repository.getKey(), rule.getKey(), param));
  101. newParam.setType(RuleParamType.parse(param.getType()));
  102. }
  103. updateRuleDebtDefinitions(newRule, repository.getKey(), rule.getKey(), ruleDebts);
  104. }
  105. newRepository.done();
  106. }
  107. }
  108. private static void updateRuleDebtDefinitions(RulesDefinition.NewRule newRule, String repoKey, String ruleKey, List<RuleDebt> ruleDebts) {
  109. RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey);
  110. if (ruleDebt != null) {
  111. newRule.setDebtRemediationFunction(remediationFunction(DebtRemediationFunction.Type.valueOf(ruleDebt.function()),
  112. ruleDebt.coefficient(),
  113. ruleDebt.offset(),
  114. newRule.debtRemediationFunctions(),
  115. repoKey, ruleKey));
  116. }
  117. }
  118. private static DebtRemediationFunction remediationFunction(DebtRemediationFunction.Type function, @Nullable String coefficient, @Nullable String offset,
  119. RulesDefinition.DebtRemediationFunctions functions, String repoKey, String ruleKey) {
  120. if (DebtRemediationFunction.Type.LINEAR.equals(function) && coefficient != null) {
  121. return functions.linear(coefficient);
  122. } else if (DebtRemediationFunction.Type.CONSTANT_ISSUE.equals(function) && offset != null) {
  123. return functions.constantPerIssue(offset);
  124. } else if (DebtRemediationFunction.Type.LINEAR_OFFSET.equals(function) && coefficient != null && offset != null) {
  125. return functions.linearWithOffset(coefficient, offset);
  126. } else {
  127. throw new IllegalArgumentException(String.format("Debt definition on rule '%s:%s' is invalid", repoKey, ruleKey));
  128. }
  129. }
  130. @CheckForNull
  131. private String ruleName(String repositoryKey, org.sonar.api.rules.Rule rule) {
  132. String name = i18n.getName(repositoryKey, rule.getKey());
  133. if (StringUtils.isNotBlank(name)) {
  134. return name;
  135. }
  136. return StringUtils.defaultIfBlank(rule.getName(), null);
  137. }
  138. @CheckForNull
  139. private String ruleDescription(String repositoryKey, org.sonar.api.rules.Rule rule) {
  140. String description = i18n.getDescription(repositoryKey, rule.getKey());
  141. if (StringUtils.isNotBlank(description)) {
  142. return description;
  143. }
  144. return StringUtils.defaultIfBlank(rule.getDescription(), null);
  145. }
  146. @CheckForNull
  147. private String paramDescription(String repositoryKey, String ruleKey, RuleParam param) {
  148. String desc = StringUtils.defaultIfEmpty(
  149. i18n.getParamDescription(repositoryKey, ruleKey, param.getKey()),
  150. param.getDescription());
  151. return StringUtils.defaultIfBlank(desc, null);
  152. }
  153. public List<DebtModelXMLExporter.RuleDebt> loadRuleDebtList() {
  154. List<RuleDebt> ruleDebtList = newArrayList();
  155. for (String pluginKey : getContributingPluginListWithoutSqale()) {
  156. ruleDebtList.addAll(loadRuleDebtsFromXml(pluginKey));
  157. }
  158. return ruleDebtList;
  159. }
  160. public List<RuleDebt> loadRuleDebtsFromXml(String pluginKey) {
  161. Reader xmlFileReader = null;
  162. try {
  163. xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
  164. ValidationMessages validationMessages = ValidationMessages.create();
  165. List<RuleDebt> rules = importer.importXML(xmlFileReader, validationMessages);
  166. validationMessages.log(LOG);
  167. return rules;
  168. } finally {
  169. IOUtils.closeQuietly(xmlFileReader);
  170. }
  171. }
  172. private Collection<String> getContributingPluginListWithoutSqale() {
  173. Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
  174. pluginList.remove(DebtModelPluginRepository.DEFAULT_MODEL);
  175. return pluginList;
  176. }
  177. @CheckForNull
  178. private static RuleDebt findRequirement(List<RuleDebt> requirements, final String repoKey, final String ruleKey) {
  179. return Iterables.find(requirements, new RuleDebtMatchRepoKeyAndRuleKey(repoKey, ruleKey), null);
  180. }
  181. private static class RuleDebtMatchRepoKeyAndRuleKey implements Predicate<RuleDebt> {
  182. private final String repoKey;
  183. private final String ruleKey;
  184. public RuleDebtMatchRepoKeyAndRuleKey(String repoKey, String ruleKey) {
  185. this.repoKey = repoKey;
  186. this.ruleKey = ruleKey;
  187. }
  188. @Override
  189. public boolean apply(@Nonnull RuleDebt input) {
  190. return input.ruleKey().equals(RuleKey.of(repoKey, ruleKey));
  191. }
  192. }
  193. }