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.

DefaultNewRule.java 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 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.api.server.rule.internal;
  21. import java.io.IOException;
  22. import java.net.URL;
  23. import java.util.Collection;
  24. import java.util.HashMap;
  25. import java.util.Locale;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.util.TreeSet;
  29. import javax.annotation.CheckForNull;
  30. import javax.annotation.Nullable;
  31. import org.apache.commons.io.IOUtils;
  32. import org.sonar.api.rule.RuleKey;
  33. import org.sonar.api.rule.RuleScope;
  34. import org.sonar.api.rule.RuleStatus;
  35. import org.sonar.api.rule.Severity;
  36. import org.sonar.api.rules.RuleType;
  37. import org.sonar.api.server.debt.DebtRemediationFunction;
  38. import org.sonar.api.server.rule.RuleTagFormat;
  39. import org.sonar.api.server.rule.RulesDefinition;
  40. import static java.lang.String.format;
  41. import static java.nio.charset.StandardCharsets.UTF_8;
  42. import static org.apache.commons.lang.StringUtils.isEmpty;
  43. import static org.apache.commons.lang.StringUtils.trimToNull;
  44. import static org.sonar.api.utils.Preconditions.checkArgument;
  45. import static org.sonar.api.utils.Preconditions.checkState;
  46. class DefaultNewRule extends RulesDefinition.NewRule {
  47. private final String pluginKey;
  48. private final String repoKey;
  49. private final String key;
  50. private RuleType type;
  51. private String name;
  52. private String htmlDescription;
  53. private String markdownDescription;
  54. private String internalKey;
  55. private String severity = Severity.MAJOR;
  56. private boolean template;
  57. private RuleStatus status = RuleStatus.defaultStatus();
  58. private DebtRemediationFunction debtRemediationFunction;
  59. private String gapDescription;
  60. private final Set<String> tags = new TreeSet<>();
  61. private final Set<String> securityStandards = new TreeSet<>();
  62. private final Map<String, RulesDefinition.NewParam> paramsByKey = new HashMap<>();
  63. private final RulesDefinition.DebtRemediationFunctions functions;
  64. private boolean activatedByDefault;
  65. private RuleScope scope;
  66. private final Set<RuleKey> deprecatedRuleKeys = new TreeSet<>();
  67. DefaultNewRule(@Nullable String pluginKey, String repoKey, String key) {
  68. this.pluginKey = pluginKey;
  69. this.repoKey = repoKey;
  70. this.key = key;
  71. this.functions = new DefaultDebtRemediationFunctions(repoKey, key);
  72. }
  73. @Override
  74. public String key() {
  75. return this.key;
  76. }
  77. @CheckForNull
  78. @Override
  79. public RuleScope scope() {
  80. return this.scope;
  81. }
  82. @Override
  83. public DefaultNewRule setScope(RuleScope scope) {
  84. this.scope = scope;
  85. return this;
  86. }
  87. @Override
  88. public DefaultNewRule setName(String s) {
  89. this.name = trimToNull(s);
  90. return this;
  91. }
  92. @Override
  93. public DefaultNewRule setTemplate(boolean template) {
  94. this.template = template;
  95. return this;
  96. }
  97. @Override
  98. public DefaultNewRule setActivatedByDefault(boolean activatedByDefault) {
  99. this.activatedByDefault = activatedByDefault;
  100. return this;
  101. }
  102. @Override
  103. public DefaultNewRule setSeverity(String s) {
  104. checkArgument(Severity.ALL.contains(s), "Severity of rule %s is not correct: %s", this, s);
  105. this.severity = s;
  106. return this;
  107. }
  108. @Override
  109. public DefaultNewRule setType(RuleType t) {
  110. this.type = t;
  111. return this;
  112. }
  113. @Override
  114. public DefaultNewRule setHtmlDescription(@Nullable String s) {
  115. checkState(markdownDescription == null, "Rule '%s' already has a Markdown description", this);
  116. this.htmlDescription = trimToNull(s);
  117. return this;
  118. }
  119. @Override
  120. public DefaultNewRule setHtmlDescription(@Nullable URL classpathUrl) {
  121. if (classpathUrl != null) {
  122. try {
  123. setHtmlDescription(IOUtils.toString(classpathUrl, UTF_8));
  124. } catch (IOException e) {
  125. throw new IllegalStateException("Fail to read: " + classpathUrl, e);
  126. }
  127. } else {
  128. this.htmlDescription = null;
  129. }
  130. return this;
  131. }
  132. @Override
  133. public DefaultNewRule setMarkdownDescription(@Nullable String s) {
  134. checkState(htmlDescription == null, "Rule '%s' already has an HTML description", this);
  135. this.markdownDescription = trimToNull(s);
  136. return this;
  137. }
  138. @Override
  139. public DefaultNewRule setMarkdownDescription(@Nullable URL classpathUrl) {
  140. if (classpathUrl != null) {
  141. try {
  142. setMarkdownDescription(IOUtils.toString(classpathUrl, UTF_8));
  143. } catch (IOException e) {
  144. throw new IllegalStateException("Fail to read: " + classpathUrl, e);
  145. }
  146. } else {
  147. this.markdownDescription = null;
  148. }
  149. return this;
  150. }
  151. @Override
  152. public DefaultNewRule setStatus(RuleStatus status) {
  153. checkArgument(RuleStatus.REMOVED != status, "Status 'REMOVED' is not accepted on rule '%s'", this);
  154. this.status = status;
  155. return this;
  156. }
  157. @Override
  158. public RulesDefinition.DebtRemediationFunctions debtRemediationFunctions() {
  159. return functions;
  160. }
  161. @Override
  162. public DefaultNewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn) {
  163. this.debtRemediationFunction = fn;
  164. return this;
  165. }
  166. @Override
  167. public DefaultNewRule setGapDescription(@Nullable String s) {
  168. this.gapDescription = s;
  169. return this;
  170. }
  171. @Override
  172. public RulesDefinition.NewParam createParam(String paramKey) {
  173. checkArgument(!paramsByKey.containsKey(paramKey), "The parameter '%s' is declared several times on the rule %s", paramKey, this);
  174. DefaultNewParam param = new DefaultNewParam(paramKey);
  175. paramsByKey.put(paramKey, param);
  176. return param;
  177. }
  178. @CheckForNull
  179. @Override
  180. public RulesDefinition.NewParam param(String paramKey) {
  181. return paramsByKey.get(paramKey);
  182. }
  183. @Override
  184. public Collection<RulesDefinition.NewParam> params() {
  185. return paramsByKey.values();
  186. }
  187. @Override
  188. public DefaultNewRule addTags(String... list) {
  189. for (String tag : list) {
  190. RuleTagFormat.validate(tag);
  191. tags.add(tag);
  192. }
  193. return this;
  194. }
  195. @Override
  196. public DefaultNewRule setTags(String... list) {
  197. tags.clear();
  198. addTags(list);
  199. return this;
  200. }
  201. @Override
  202. public DefaultNewRule addOwaspTop10(RulesDefinition.OwaspTop10... standards) {
  203. for (RulesDefinition.OwaspTop10 owaspTop10 : standards) {
  204. String standard = "owaspTop10:" + owaspTop10.name().toLowerCase(Locale.ENGLISH);
  205. securityStandards.add(standard);
  206. }
  207. return this;
  208. }
  209. @Override
  210. public DefaultNewRule addCwe(int... nums) {
  211. for (int num : nums) {
  212. String standard = "cwe:" + num;
  213. securityStandards.add(standard);
  214. }
  215. return this;
  216. }
  217. @Override
  218. public DefaultNewRule setInternalKey(@Nullable String s) {
  219. this.internalKey = s;
  220. return this;
  221. }
  222. void validate() {
  223. if (isEmpty(name)) {
  224. throw new IllegalStateException(format("Name of rule %s is empty", this));
  225. }
  226. if (isEmpty(htmlDescription) && isEmpty(markdownDescription)) {
  227. throw new IllegalStateException(format("One of HTML description or Markdown description must be defined for rule %s", this));
  228. }
  229. }
  230. @Override
  231. public DefaultNewRule addDeprecatedRuleKey(String repository, String key) {
  232. deprecatedRuleKeys.add(RuleKey.of(repository, key));
  233. return this;
  234. }
  235. String pluginKey() {
  236. return pluginKey;
  237. }
  238. String repoKey() {
  239. return repoKey;
  240. }
  241. RuleType type() {
  242. return type;
  243. }
  244. String name() {
  245. return name;
  246. }
  247. String htmlDescription() {
  248. return htmlDescription;
  249. }
  250. String markdownDescription() {
  251. return markdownDescription;
  252. }
  253. @CheckForNull
  254. String internalKey() {
  255. return internalKey;
  256. }
  257. String severity() {
  258. return severity;
  259. }
  260. boolean template() {
  261. return template;
  262. }
  263. RuleStatus status() {
  264. return status;
  265. }
  266. DebtRemediationFunction debtRemediationFunction() {
  267. return debtRemediationFunction;
  268. }
  269. String gapDescription() {
  270. return gapDescription;
  271. }
  272. Set<String> tags() {
  273. return tags;
  274. }
  275. Set<String> securityStandards() {
  276. return securityStandards;
  277. }
  278. Map<String, RulesDefinition.NewParam> paramsByKey() {
  279. return paramsByKey;
  280. }
  281. boolean activatedByDefault() {
  282. return activatedByDefault;
  283. }
  284. Set<RuleKey> deprecatedRuleKeys() {
  285. return deprecatedRuleKeys;
  286. }
  287. @Override
  288. public String toString() {
  289. return format("[repository=%s, key=%s]", repoKey, key);
  290. }
  291. }