001/* 002 * SonarQube 003 * Copyright (C) 2009-2017 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.rules; 021 022import com.google.common.base.Joiner; 023import java.util.ArrayList; 024import java.util.Date; 025import java.util.LinkedHashSet; 026import java.util.List; 027import java.util.Set; 028import javax.annotation.CheckForNull; 029import javax.annotation.Nullable; 030import org.apache.commons.lang.StringUtils; 031import org.apache.commons.lang.builder.EqualsBuilder; 032import org.apache.commons.lang.builder.HashCodeBuilder; 033import org.apache.commons.lang.builder.ToStringBuilder; 034import org.apache.commons.lang.builder.ToStringStyle; 035import org.sonar.api.rule.RuleKey; 036import org.sonar.api.utils.SonarException; 037import org.sonar.check.Cardinality; 038 039import static java.util.Arrays.asList; 040import static java.util.Collections.unmodifiableSet; 041 042public class Rule { 043 044 /** 045 * @since 3.6 046 */ 047 public static final String STATUS_BETA = "BETA"; 048 /** 049 * @since 3.6 050 */ 051 public static final String STATUS_DEPRECATED = "DEPRECATED"; 052 /** 053 * @since 3.6 054 */ 055 public static final String STATUS_READY = "READY"; 056 057 /** 058 * For internal use only. 059 * 060 * @since 3.6 061 */ 062 public static final String STATUS_REMOVED = "REMOVED"; 063 064 /** 065 * List of available status 066 * 067 * @since 3.6 068 */ 069 private static final Set<String> STATUS_LIST = unmodifiableSet(new LinkedHashSet<>(asList(STATUS_READY, STATUS_BETA, STATUS_DEPRECATED, STATUS_REMOVED))); 070 071 private Integer id; 072 073 /** 074 * The default priority given to a rule if not explicitly set 075 */ 076 public static final RulePriority DEFAULT_PRIORITY = RulePriority.MAJOR; 077 078 private String name; 079 private String key; 080 private String configKey; 081 private RulePriority priority = DEFAULT_PRIORITY; 082 private String description; 083 private String pluginName; 084 private boolean isTemplate = false; 085 private String status = STATUS_READY; 086 private String language; 087 private Rule template = null; 088 private List<RuleParam> params = new ArrayList<>(); 089 private Date createdAt; 090 private Date updatedAt; 091 private String tags; 092 private String systemTags; 093 094 /** 095 * @deprecated since 2.3. Use the factory method {@link #create()} 096 */ 097 @Deprecated 098 public Rule() { 099 } 100 101 /** 102 * Creates rule with minimum set of info 103 * 104 * @param pluginName the plugin name indicates which plugin the rule belongs to 105 * @param key the key should be unique within a plugin, but it is even more careful for the time being that it is unique across the 106 * application 107 * @deprecated since 2.3. Use the factory method {@link #create()} 108 */ 109 @Deprecated 110 public Rule(String pluginName, String key) { 111 this.pluginName = pluginName; 112 this.key = key; 113 this.configKey = key; 114 } 115 116 public Integer getId() { 117 return id; 118 } 119 120 /** 121 * @deprecated since 2.3. visibility should be decreased to protected or package 122 */ 123 @Deprecated 124 public void setId(Integer id) { 125 this.id = id; 126 } 127 128 public String getName() { 129 return name; 130 } 131 132 /** 133 * Sets the rule name 134 */ 135 public Rule setName(String name) { 136 this.name = removeNewLineCharacters(name); 137 return this; 138 } 139 140 public String getKey() { 141 return key; 142 } 143 144 /** 145 * Sets the rule key 146 */ 147 public Rule setKey(String key) { 148 this.key = key; 149 return this; 150 } 151 152 public String getConfigKey() { 153 return configKey; 154 } 155 156 /** 157 * Sets the configuration key 158 */ 159 public Rule setConfigKey(String configKey) { 160 this.configKey = configKey; 161 return this; 162 } 163 164 public String getDescription() { 165 return description; 166 } 167 168 /** 169 * Sets the rule description 170 */ 171 public Rule setDescription(String description) { 172 this.description = StringUtils.strip(description); 173 return this; 174 } 175 176 public Boolean isEnabled() { 177 return !STATUS_REMOVED.equals(status); 178 } 179 180 public List<RuleParam> getParams() { 181 return params; 182 } 183 184 public RuleParam getParam(String key) { 185 for (RuleParam param : params) { 186 if (StringUtils.equals(key, param.getKey())) { 187 return param; 188 } 189 } 190 return null; 191 } 192 193 /** 194 * Sets the rule parameters 195 */ 196 public Rule setParams(List<RuleParam> params) { 197 this.params.clear(); 198 for (RuleParam param : params) { 199 param.setRule(this); 200 this.params.add(param); 201 } 202 return this; 203 } 204 205 public RuleParam createParameter() { 206 RuleParam parameter = new RuleParam() 207 .setRule(this); 208 params.add(parameter); 209 return parameter; 210 } 211 212 public RuleParam createParameter(String key) { 213 RuleParam parameter = new RuleParam() 214 .setKey(key) 215 .setRule(this); 216 params.add(parameter); 217 return parameter; 218 } 219 220 /** 221 * @since 2.5 222 */ 223 public RulePriority getSeverity() { 224 return priority; 225 } 226 227 /** 228 * @param severity severity to set, if null, uses the default priority. 229 * @since 2.5 230 */ 231 public Rule setSeverity(RulePriority severity) { 232 if (severity == null) { 233 this.priority = DEFAULT_PRIORITY; 234 } else { 235 this.priority = severity; 236 } 237 return this; 238 } 239 240 public String getRepositoryKey() { 241 return pluginName; 242 } 243 244 public Rule setRepositoryKey(String s) { 245 this.pluginName = s; 246 return this; 247 } 248 249 public Rule setUniqueKey(String repositoryKey, String key) { 250 return setRepositoryKey(repositoryKey).setKey(key).setConfigKey(key); 251 } 252 253 /** 254 * @since 4.4 255 */ 256 public boolean isTemplate() { 257 return isTemplate; 258 } 259 260 /** 261 * @since 4.4 262 */ 263 public Rule setIsTemplate(boolean isTemplate) { 264 this.isTemplate = isTemplate; 265 return this; 266 } 267 268 /** 269 * @deprecated since 4.4, use {@link #isTemplate()} 270 */ 271 @Deprecated 272 public Cardinality getCardinality() { 273 return isTemplate ? Cardinality.MULTIPLE : Cardinality.SINGLE; 274 } 275 276 /** 277 * @deprecated since 4.4, use {@link #setIsTemplate(boolean)} 278 */ 279 @Deprecated 280 public Rule setCardinality(Cardinality c) { 281 this.isTemplate = Cardinality.MULTIPLE.equals(c); 282 return this; 283 } 284 285 /** 286 * @deprecated since 4.4, use {@link #getTemplate()} 287 */ 288 @Deprecated 289 public Rule getParent() { 290 return template; 291 } 292 293 /** 294 * @deprecated since 4.4, use {@link #setTemplate(Rule)}} 295 */ 296 @Deprecated 297 public Rule setParent(Rule parent) { 298 this.template = parent; 299 return this; 300 } 301 302 /** 303 * @since 4.4 304 */ 305 public Rule getTemplate() { 306 return template; 307 } 308 309 /** 310 * @since 4.4 311 */ 312 public Rule setTemplate(Rule template) { 313 this.template = template; 314 return this; 315 } 316 317 /** 318 * @since 3.6 319 */ 320 public String getStatus() { 321 return status; 322 } 323 324 /** 325 * @since 3.6 326 */ 327 public Rule setStatus(String status) { 328 if (!STATUS_LIST.contains(status)) { 329 throw new SonarException("The status of a rule can only contain : " + Joiner.on(", ").join(STATUS_LIST)); 330 } 331 this.status = status; 332 return this; 333 } 334 335 /** 336 * @since 3.6 337 */ 338 public Date getCreatedAt() { 339 return createdAt; 340 } 341 342 /** 343 * @since 3.6 344 */ 345 public Rule setCreatedAt(Date d) { 346 this.createdAt = d; 347 return this; 348 } 349 350 /** 351 * @since 3.6 352 */ 353 public Date getUpdatedAt() { 354 return updatedAt; 355 } 356 357 /** 358 * @since 3.6 359 */ 360 public Rule setUpdatedAt(Date updatedAt) { 361 this.updatedAt = updatedAt; 362 return this; 363 } 364 365 /** 366 * @since 3.6 367 */ 368 public String getLanguage() { 369 return language; 370 } 371 372 /** 373 * For internal use only. 374 * 375 * @since 3.6 376 */ 377 public Rule setLanguage(String language) { 378 this.language = language; 379 return this; 380 } 381 382 /** 383 * For definition of rule only 384 */ 385 public String[] getTags() { 386 return tags == null ? new String[0] : StringUtils.split(tags, ','); 387 } 388 389 /** 390 * For definition of rule only 391 */ 392 public Rule setTags(String[] tags) { 393 this.tags = tags == null ? null : StringUtils.join(tags, ','); 394 return this; 395 } 396 397 /** 398 * For internal use 399 */ 400 public String[] getSystemTags() { 401 return systemTags == null ? new String[0] : StringUtils.split(systemTags, ','); 402 } 403 404 /** 405 * For internal use only. 406 * 407 * @deprecated since 4.4, use {@link #getCharacteristicKey()} 408 * @since 4.3 409 */ 410 @CheckForNull 411 @Deprecated 412 public Integer getCharacteristicId() { 413 return null; 414 } 415 416 /** 417 * For internal use only. 418 * 419 * @deprecated since 4.4, use {@link #setCharacteristicKey(String)} 420 * @since 4.3 421 */ 422 @Deprecated 423 public Rule setCharacteristicId(@Nullable Integer characteristicId) { 424 return this; 425 } 426 427 /** 428 * For internal use only. 429 * 430 * @deprecated since 4.4, use {@link #getDefaultCharacteristicKey()} 431 * @since 4.3 432 */ 433 @CheckForNull 434 @Deprecated 435 public Integer getDefaultCharacteristicId() { 436 return null; 437 } 438 439 /** 440 * For internal use only. 441 * 442 * @deprecated since 4.4, use {@link #setDefaultCharacteristicKey(String)} 443 * @since 4.3 444 */ 445 @Deprecated 446 public Rule setDefaultCharacteristicId(@Nullable Integer defaultCharacteristicId) { 447 return this; 448 } 449 450 @Override 451 public boolean equals(Object obj) { 452 if (!(obj instanceof Rule)) { 453 return false; 454 } 455 if (this == obj) { 456 return true; 457 } 458 Rule other = (Rule) obj; 459 return new EqualsBuilder() 460 .append(pluginName, other.getRepositoryKey()) 461 .append(key, other.getKey()) 462 .isEquals(); 463 } 464 465 @Override 466 public int hashCode() { 467 return new HashCodeBuilder(17, 37) 468 .append(pluginName) 469 .append(key) 470 .toHashCode(); 471 } 472 473 @Override 474 public String toString() { 475 // Note that ReflectionToStringBuilder will not work here - see SONAR-3077 476 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 477 .append("id", id) 478 .append("name", name) 479 .append("key", key) 480 .append("configKey", configKey) 481 .append("plugin", pluginName) 482 .append("severity", priority) 483 .append("isTemplate", isTemplate()) 484 .append("status", status) 485 .append("language", language) 486 .append("template", template) 487 .toString(); 488 } 489 490 @CheckForNull 491 private static String removeNewLineCharacters(@Nullable String text) { 492 String removedCRLF = StringUtils.remove(text, "\n"); 493 removedCRLF = StringUtils.remove(removedCRLF, "\r"); 494 removedCRLF = StringUtils.remove(removedCRLF, "\n\r"); 495 removedCRLF = StringUtils.remove(removedCRLF, "\r\n"); 496 return removedCRLF; 497 } 498 499 public static Rule create() { 500 return new Rule(); 501 } 502 503 /** 504 * Create with all required fields 505 */ 506 public static Rule create(String repositoryKey, String key, String name) { 507 return new Rule().setUniqueKey(repositoryKey, key).setName(name); 508 } 509 510 /** 511 * Create with all required fields 512 * 513 * @since 2.10 514 */ 515 public static Rule create(String repositoryKey, String key) { 516 return new Rule().setUniqueKey(repositoryKey, key); 517 } 518 519 /** 520 * @since 3.6 521 */ 522 public RuleKey ruleKey() { 523 return RuleKey.of(getRepositoryKey(), getKey()); 524 } 525 526 /** 527 * @since 4.4 528 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 529 */ 530 @CheckForNull 531 @Deprecated 532 public String getDefaultCharacteristicKey() { 533 return null; 534 } 535 536 /** 537 * @since 4.4 538 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 539 */ 540 @Deprecated 541 public Rule setDefaultCharacteristicKey(@Nullable String defaultCharacteristicKey) { 542 return this; 543 } 544 545 /** 546 * @since 4.4 547 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 548 */ 549 @CheckForNull 550 @Deprecated 551 public String getDefaultSubCharacteristicKey() { 552 return null; 553 } 554 555 /** 556 * @since 4.4 557 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 558 */ 559 @Deprecated 560 public Rule setDefaultSubCharacteristicKey(@Nullable String defaultSubCharacteristicKey) { 561 return this; 562 } 563 564 /** 565 * @since 4.4 566 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 567 */ 568 @CheckForNull 569 @Deprecated 570 public String getCharacteristicKey() { 571 return null; 572 } 573 574 /** 575 * @since 4.4 576 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 577 */ 578 @Deprecated 579 public Rule setCharacteristicKey(@Nullable String characteristicKey) { 580 return this; 581 } 582 583 /** 584 * @since 4.4 585 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 586 */ 587 @CheckForNull 588 @Deprecated 589 public String getSubCharacteristicKey() { 590 return null; 591 } 592 593 /** 594 * @since 4.4 595 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 596 */ 597 @Deprecated 598 public Rule setSubCharacteristicKey(@Nullable String subCharacteristicKey) { 599 return this; 600 } 601}