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