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