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