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 package org.sonar.api.profiles; 021 022 import com.google.common.base.Predicate; 023 import com.google.common.collect.Iterables; 024 import com.google.common.collect.Lists; 025 import org.apache.commons.collections.CollectionUtils; 026 import org.apache.commons.collections.Transformer; 027 import org.apache.commons.lang.StringUtils; 028 import org.apache.commons.lang.builder.EqualsBuilder; 029 import org.apache.commons.lang.builder.HashCodeBuilder; 030 import org.sonar.api.rules.ActiveRule; 031 import org.sonar.api.rules.Rule; 032 import org.sonar.api.rules.RulePriority; 033 import org.sonar.api.utils.MessageException; 034 035 import javax.annotation.CheckForNull; 036 import javax.persistence.*; 037 038 import java.util.ArrayList; 039 import java.util.List; 040 041 /** 042 * This class is badly named. It should be "QualityProfile". Indeed it does not relate only to rules but to metric thresholds too. 043 */ 044 @Entity 045 @Table(name = "rules_profiles") 046 public class RulesProfile implements Cloneable { 047 048 /** 049 * Name of the default profile "Sonar Way" 050 * @deprecated in 4.2. Use your own constant. 051 */ 052 @Deprecated 053 public static final String SONAR_WAY_NAME = "Sonar way"; 054 055 /** 056 * Name of the default java profile "Sonar way with Findbugs" 057 * @deprecated in 4.2. Use your own constant. 058 */ 059 @Deprecated 060 public static final String SONAR_WAY_FINDBUGS_NAME = "Sonar way with Findbugs"; 061 062 /** 063 * Name of the default java profile "Sun checks" 064 * @deprecated in 4.2. Use your own constant. 065 */ 066 @Deprecated 067 public static final String SUN_CONVENTIONS_NAME = "Sun checks"; 068 069 @Id 070 @Column(name = "id") 071 @GeneratedValue 072 private Integer id; 073 074 @Column(name = "name", updatable = true, nullable = false) 075 private String name; 076 077 @Column(name = "version", updatable = true, nullable = false) 078 private int version = 1; 079 080 @Transient 081 private Boolean defaultProfile = Boolean.FALSE; 082 083 @Column(name = "used_profile", updatable = true, nullable = false) 084 private Boolean used = Boolean.FALSE; 085 086 @Column(name = "language", updatable = true, nullable = false, length = 20) 087 private String language; 088 089 @Column(name = "parent_name", updatable = true, nullable = true) 090 private String parentName; 091 092 @OneToMany(mappedBy = "rulesProfile", fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE}) 093 private List<ActiveRule> activeRules = Lists.newArrayList(); 094 095 /** 096 * @deprecated use the factory method create() 097 */ 098 @Deprecated 099 public RulesProfile() { 100 } 101 102 /** 103 * @deprecated since 2.3. Use the factory method create() 104 */ 105 @Deprecated 106 public RulesProfile(String name, String language) { 107 this.name = name; 108 this.language = language; 109 this.activeRules = Lists.newArrayList(); 110 } 111 112 /** 113 * @deprecated since 2.3. Use the factory method create() 114 */ 115 @Deprecated 116 public RulesProfile(String name, String language, boolean defaultProfile, /* kept for backward-compatibility */boolean provided) { 117 this(name, language); 118 this.defaultProfile = defaultProfile; 119 } 120 121 public Integer getId() { 122 return id; 123 } 124 125 /** 126 * @return the profile name, unique by language. 127 */ 128 public String getName() { 129 return name; 130 } 131 132 /** 133 * Set the profile name. 134 */ 135 public RulesProfile setName(String s) { 136 this.name = s; 137 return this; 138 } 139 140 public int getVersion() { 141 return version; 142 } 143 144 public RulesProfile setVersion(int version) { 145 this.version = version; 146 return this; 147 } 148 149 public Boolean getUsed() { 150 return used; 151 } 152 153 public RulesProfile setUsed(Boolean used) { 154 this.used = used; 155 return this; 156 } 157 158 /** 159 * @return the list of active rules 160 */ 161 public List<ActiveRule> getActiveRules() { 162 return getActiveRules(false); 163 } 164 165 /** 166 * @return the list of active rules 167 */ 168 public List<ActiveRule> getActiveRules(boolean acceptDisabledRules) { 169 if (acceptDisabledRules) { 170 return activeRules; 171 } 172 List<ActiveRule> result = Lists.newArrayList(); 173 for (ActiveRule activeRule : activeRules) { 174 if (activeRule.isEnabled()) { 175 result.add(activeRule); 176 } 177 } 178 return result; 179 } 180 181 public RulesProfile removeActiveRule(ActiveRule activeRule) { 182 activeRules.remove(activeRule); 183 return this; 184 } 185 186 public RulesProfile addActiveRule(ActiveRule activeRule) { 187 activeRules.add(activeRule); 188 return this; 189 } 190 191 /** 192 * Set the list of active rules 193 */ 194 public void setActiveRules(List<ActiveRule> activeRules) { 195 this.activeRules = activeRules; 196 } 197 198 /** 199 * @return whether this is the default profile for the language 200 */ 201 public Boolean getDefaultProfile() { 202 return defaultProfile; 203 } 204 205 /** 206 * Set whether this is the default profile for the language. The default profile is used when none is explicitly defined when auditing a 207 * project. 208 */ 209 public void setDefaultProfile(Boolean b) { 210 this.defaultProfile = b; 211 } 212 213 /** 214 * @deprecated since 3.3 not replaced 215 */ 216 @Deprecated 217 public Boolean getProvided() { 218 return false; 219 } 220 221 /** 222 * @deprecated since 3.3 not replaced 223 */ 224 @Deprecated 225 public void setProvided(Boolean b) { 226 } 227 228 /** 229 * @deprecated since 3.3. Always return true. 230 */ 231 @Deprecated 232 public Boolean getEnabled() { 233 return Boolean.TRUE; 234 } 235 236 /** 237 * @deprecated since 3.3. Always return true. 238 */ 239 @Deprecated 240 public boolean isEnabled() { 241 return true; 242 } 243 244 /** 245 * @deprecated since 3.3. 246 */ 247 @Deprecated 248 public RulesProfile setEnabled(Boolean b) { 249 throw new UnsupportedOperationException("The field RulesProfile#enabled is not supported since 3.3."); 250 } 251 252 /** 253 * @return the profile language 254 */ 255 public String getLanguage() { 256 return language; 257 } 258 259 /** 260 * Set the profile language 261 */ 262 public RulesProfile setLanguage(String s) { 263 this.language = s; 264 return this; 265 } 266 267 /** 268 * For internal use only. 269 * 270 * @since 2.5 271 */ 272 @CheckForNull 273 public String getParentName() { 274 return parentName; 275 } 276 277 /** 278 * For internal use only. 279 * 280 * @since 2.5 281 */ 282 public void setParentName(String parentName) { 283 this.parentName = parentName; 284 } 285 286 /** 287 * Note: disabled rules are excluded. 288 * 289 * @return the list of active rules for a given severity 290 */ 291 public List<ActiveRule> getActiveRules(RulePriority severity) { 292 List<ActiveRule> result = Lists.newArrayList(); 293 for (ActiveRule activeRule : activeRules) { 294 if (activeRule.getSeverity().equals(severity) && activeRule.isEnabled()) { 295 result.add(activeRule); 296 } 297 } 298 return result; 299 } 300 301 /** 302 * @deprecated since 2.3 use {@link #getActiveRulesByRepository(String)} instead. 303 */ 304 @Deprecated 305 public List<ActiveRule> getActiveRulesByPlugin(String repositoryKey) { 306 return getActiveRulesByRepository(repositoryKey); 307 } 308 309 /** 310 * Get the active rules of a specific repository. 311 * Only enabled rules are selected. Disabled rules are excluded. 312 */ 313 public List<ActiveRule> getActiveRulesByRepository(String repositoryKey) { 314 List<ActiveRule> result = Lists.newArrayList(); 315 for (ActiveRule activeRule : activeRules) { 316 if (repositoryKey.equals(activeRule.getRepositoryKey()) && activeRule.isEnabled()) { 317 result.add(activeRule); 318 } 319 } 320 return result; 321 } 322 323 /** 324 * Note: disabled rules are excluded. 325 * 326 * @return an active rule from a plugin key and a rule key if the rule is activated, null otherwise 327 */ 328 @CheckForNull 329 public ActiveRule getActiveRule(String repositoryKey, String ruleKey) { 330 for (ActiveRule activeRule : activeRules) { 331 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getRuleKey(), ruleKey) && activeRule.isEnabled()) { 332 return activeRule; 333 } 334 } 335 return null; 336 } 337 338 /** 339 * Note: disabled rules are excluded. 340 */ 341 @CheckForNull 342 public ActiveRule getActiveRuleByConfigKey(String repositoryKey, String configKey) { 343 for (ActiveRule activeRule : activeRules) { 344 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getConfigKey(), configKey) && activeRule.isEnabled()) { 345 return activeRule; 346 } 347 } 348 return null; 349 } 350 351 /** 352 * Note: disabled rules are excluded. 353 */ 354 @CheckForNull 355 public ActiveRule getActiveRule(Rule rule) { 356 return getActiveRule(rule.getRepositoryKey(), rule.getKey()); 357 } 358 359 /** 360 * @param optionalSeverity if null, then the default rule severity is used 361 */ 362 public ActiveRule activateRule(final Rule rule, RulePriority optionalSeverity) { 363 if (Iterables.any(activeRules, new Predicate<ActiveRule>() { 364 @Override 365 public boolean apply(ActiveRule input) { 366 return input.getRule().equals(rule); 367 } 368 })) { 369 throw MessageException.of(String.format( 370 "The definition of the profile '%s' (language '%s') contains multiple occurrences of the '%s:%s' rule. The plugin which declares this profile should fix this.", 371 getName(), getLanguage(), rule.getRepositoryKey(), rule.getKey())); 372 } 373 ActiveRule activeRule = new ActiveRule(); 374 activeRule.setRule(rule); 375 activeRule.setRulesProfile(this); 376 activeRule.setSeverity(optionalSeverity == null ? rule.getSeverity() : optionalSeverity); 377 activeRules.add(activeRule); 378 return activeRule; 379 } 380 381 @Override 382 public boolean equals(Object obj) { 383 if (!(obj instanceof RulesProfile)) { 384 return false; 385 } 386 if (this == obj) { 387 return true; 388 } 389 RulesProfile other = (RulesProfile) obj; 390 return new EqualsBuilder().append(language, other.getLanguage()).append(name, other.getName()).isEquals(); 391 } 392 393 @Override 394 public int hashCode() { 395 return new HashCodeBuilder(17, 37).append(language).append(name).toHashCode(); 396 } 397 398 @Override 399 public Object clone() { 400 RulesProfile clone = RulesProfile.create(getName(), getLanguage()); 401 clone.setDefaultProfile(getDefaultProfile()); 402 clone.setParentName(getParentName()); 403 if (activeRules != null && !activeRules.isEmpty()) { 404 clone.setActiveRules(new ArrayList<ActiveRule>(CollectionUtils.collect(activeRules, new Transformer() { 405 public Object transform(Object input) { 406 return ((ActiveRule) input).clone(); 407 } 408 }))); 409 } 410 return clone; 411 } 412 413 @Override 414 public String toString() { 415 return new StringBuilder().append("[name=").append(name).append(",language=").append(language).append("]").toString(); 416 } 417 418 public static RulesProfile create(String name, String language) { 419 return new RulesProfile().setName(name).setLanguage(language); 420 } 421 422 public static RulesProfile create() { 423 return new RulesProfile(); 424 } 425 }