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