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 getTemplate(); 291 } 292 293 /** 294 * @deprecated since 4.4, use {@link #setTemplate(Rule)}} 295 */ 296 @Deprecated 297 public Rule setParent(Rule parent) { 298 return setTemplate(parent); 299 } 300 301 /** 302 * @since 4.4 303 */ 304 public Rule getTemplate() { 305 return template; 306 } 307 308 /** 309 * @since 4.4 310 */ 311 public Rule setTemplate(Rule template) { 312 this.template = template; 313 return this; 314 } 315 316 /** 317 * @since 3.6 318 */ 319 public String getStatus() { 320 return status; 321 } 322 323 /** 324 * @since 3.6 325 */ 326 public Rule setStatus(String status) { 327 if (!STATUS_LIST.contains(status)) { 328 throw new SonarException("The status of a rule can only contain : " + Joiner.on(", ").join(STATUS_LIST)); 329 } 330 this.status = status; 331 return this; 332 } 333 334 /** 335 * @since 3.6 336 */ 337 public Date getCreatedAt() { 338 return createdAt; 339 } 340 341 /** 342 * @since 3.6 343 */ 344 public Rule setCreatedAt(Date d) { 345 this.createdAt = d; 346 return this; 347 } 348 349 /** 350 * @since 3.6 351 */ 352 public Date getUpdatedAt() { 353 return updatedAt; 354 } 355 356 /** 357 * @since 3.6 358 */ 359 public Rule setUpdatedAt(Date updatedAt) { 360 this.updatedAt = updatedAt; 361 return this; 362 } 363 364 /** 365 * @since 3.6 366 */ 367 public String getLanguage() { 368 return language; 369 } 370 371 /** 372 * For internal use only. 373 * 374 * @since 3.6 375 */ 376 public Rule setLanguage(String language) { 377 this.language = language; 378 return this; 379 } 380 381 /** 382 * For definition of rule only 383 */ 384 public String[] getTags() { 385 return tags == null ? new String[0] : StringUtils.split(tags, ','); 386 } 387 388 /** 389 * For definition of rule only 390 */ 391 public Rule setTags(String[] tags) { 392 this.tags = tags == null ? null : StringUtils.join(tags, ','); 393 return this; 394 } 395 396 /** 397 * For internal use 398 */ 399 public String[] getSystemTags() { 400 return systemTags == null ? new String[0] : StringUtils.split(systemTags, ','); 401 } 402 403 /** 404 * For internal use only. 405 * 406 * @deprecated since 4.4, use {@link #getCharacteristicKey()} 407 * @since 4.3 408 */ 409 @CheckForNull 410 @Deprecated 411 public Integer getCharacteristicId() { 412 return null; 413 } 414 415 /** 416 * For internal use only. 417 * 418 * @deprecated since 4.4, use {@link #setCharacteristicKey(String)} 419 * @since 4.3 420 */ 421 @Deprecated 422 public Rule setCharacteristicId(@Nullable Integer characteristicId) { 423 return this; 424 } 425 426 /** 427 * For internal use only. 428 * 429 * @deprecated since 4.4, use {@link #getDefaultCharacteristicKey()} 430 * @since 4.3 431 */ 432 @CheckForNull 433 @Deprecated 434 public Integer getDefaultCharacteristicId() { 435 return null; 436 } 437 438 /** 439 * For internal use only. 440 * 441 * @deprecated since 4.4, use {@link #setDefaultCharacteristicKey(String)} 442 * @since 4.3 443 */ 444 @Deprecated 445 public Rule setDefaultCharacteristicId(@Nullable Integer defaultCharacteristicId) { 446 return this; 447 } 448 449 @Override 450 public boolean equals(Object obj) { 451 if (!(obj instanceof Rule)) { 452 return false; 453 } 454 if (this == obj) { 455 return true; 456 } 457 Rule other = (Rule) obj; 458 return new EqualsBuilder() 459 .append(pluginName, other.getRepositoryKey()) 460 .append(key, other.getKey()) 461 .isEquals(); 462 } 463 464 @Override 465 public int hashCode() { 466 return new HashCodeBuilder(17, 37) 467 .append(pluginName) 468 .append(key) 469 .toHashCode(); 470 } 471 472 @Override 473 public String toString() { 474 // Note that ReflectionToStringBuilder will not work here - see SONAR-3077 475 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 476 .append("id", id) 477 .append("name", name) 478 .append("key", key) 479 .append("configKey", configKey) 480 .append("plugin", pluginName) 481 .append("severity", priority) 482 .append("isTemplate", isTemplate()) 483 .append("status", status) 484 .append("language", language) 485 .append("template", template) 486 .toString(); 487 } 488 489 @CheckForNull 490 private static String removeNewLineCharacters(@Nullable String text) { 491 String removedCRLF = StringUtils.remove(text, "\n"); 492 removedCRLF = StringUtils.remove(removedCRLF, "\r"); 493 removedCRLF = StringUtils.remove(removedCRLF, "\n\r"); 494 removedCRLF = StringUtils.remove(removedCRLF, "\r\n"); 495 return removedCRLF; 496 } 497 498 public static Rule create() { 499 return new Rule(); 500 } 501 502 /** 503 * Create with all required fields 504 */ 505 public static Rule create(String repositoryKey, String key, String name) { 506 return new Rule().setUniqueKey(repositoryKey, key).setName(name); 507 } 508 509 /** 510 * Create with all required fields 511 * 512 * @since 2.10 513 */ 514 public static Rule create(String repositoryKey, String key) { 515 return new Rule().setUniqueKey(repositoryKey, key); 516 } 517 518 /** 519 * @since 3.6 520 */ 521 public RuleKey ruleKey() { 522 return RuleKey.of(getRepositoryKey(), getKey()); 523 } 524 525 /** 526 * @since 4.4 527 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 528 */ 529 @CheckForNull 530 @Deprecated 531 public String getDefaultCharacteristicKey() { 532 return null; 533 } 534 535 /** 536 * @since 4.4 537 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 538 */ 539 @Deprecated 540 public Rule setDefaultCharacteristicKey(@Nullable String defaultCharacteristicKey) { 541 return this; 542 } 543 544 /** 545 * @since 4.4 546 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 547 */ 548 @CheckForNull 549 @Deprecated 550 public String getDefaultSubCharacteristicKey() { 551 return null; 552 } 553 554 /** 555 * @since 4.4 556 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 557 */ 558 @Deprecated 559 public Rule setDefaultSubCharacteristicKey(@Nullable String defaultSubCharacteristicKey) { 560 return this; 561 } 562 563 /** 564 * @since 4.4 565 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 566 */ 567 @CheckForNull 568 @Deprecated 569 public String getCharacteristicKey() { 570 return null; 571 } 572 573 /** 574 * @since 4.4 575 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 576 */ 577 @Deprecated 578 public Rule setCharacteristicKey(@Nullable String characteristicKey) { 579 return this; 580 } 581 582 /** 583 * @since 4.4 584 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 585 */ 586 @CheckForNull 587 @Deprecated 588 public String getSubCharacteristicKey() { 589 return null; 590 } 591 592 /** 593 * @since 4.4 594 * @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. 595 */ 596 @Deprecated 597 public Rule setSubCharacteristicKey(@Nullable String subCharacteristicKey) { 598 return this; 599 } 600}