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