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