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.database.model.ResourceModel; 029import org.sonar.api.rules.ActiveRule; 030import org.sonar.api.rules.Rule; 031import org.sonar.api.rules.RulePriority; 032 033import javax.persistence.*; 034import java.util.ArrayList; 035import 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") 042public 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 * 310 * @return the list of active rules for a given severity 311 */ 312 public List<ActiveRule> getActiveRules(RulePriority severity) { 313 List<ActiveRule> result = Lists.newArrayList(); 314 for (ActiveRule activeRule : activeRules) { 315 if (activeRule.getSeverity().equals(severity) && activeRule.isEnabled()) { 316 result.add(activeRule); 317 } 318 } 319 return result; 320 } 321 322 /** 323 * @deprecated since 2.3 use {@link #getActiveRulesByRepository(String)} instead. 324 */ 325 @Deprecated 326 public List<ActiveRule> getActiveRulesByPlugin(String repositoryKey) { 327 return getActiveRulesByRepository(repositoryKey); 328 } 329 330 /** 331 * Get the active rules of a specific repository. 332 * Only enabled rules are selected. Disabled rules are excluded. 333 */ 334 public List<ActiveRule> getActiveRulesByRepository(String repositoryKey) { 335 List<ActiveRule> result = Lists.newArrayList(); 336 for (ActiveRule activeRule : activeRules) { 337 if (repositoryKey.equals(activeRule.getRepositoryKey()) && activeRule.isEnabled()) { 338 result.add(activeRule); 339 } 340 } 341 return result; 342 } 343 344 /** 345 * Note: disabled rules are excluded. 346 * 347 * @return an active rule from a plugin key and a rule key if the rule is activated, null otherwise 348 */ 349 public ActiveRule getActiveRule(String repositoryKey, String ruleKey) { 350 for (ActiveRule activeRule : activeRules) { 351 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getRuleKey(), ruleKey) && activeRule.isEnabled()) { 352 return activeRule; 353 } 354 } 355 return null; 356 } 357 358 /** 359 * Note: disabled rules are excluded. 360 */ 361 public ActiveRule getActiveRuleByConfigKey(String repositoryKey, String configKey) { 362 for (ActiveRule activeRule : activeRules) { 363 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getConfigKey(), configKey) && activeRule.isEnabled()) { 364 return activeRule; 365 } 366 } 367 return null; 368 } 369 370 /** 371 * Note: disabled rules are excluded. 372 */ 373 374 public ActiveRule getActiveRule(Rule rule) { 375 return getActiveRule(rule.getRepositoryKey(), rule.getKey()); 376 } 377 378 /** 379 * @param optionalSeverity if null, then the default rule severity is used 380 */ 381 public ActiveRule activateRule(Rule rule, RulePriority optionalSeverity) { 382 ActiveRule activeRule = new ActiveRule(); 383 activeRule.setRule(rule); 384 activeRule.setRulesProfile(this); 385 activeRule.setSeverity(optionalSeverity == null ? rule.getSeverity() : optionalSeverity); 386 activeRules.add(activeRule); 387 return activeRule; 388 } 389 390 @Override 391 public boolean equals(Object obj) { 392 if (!(obj instanceof RulesProfile)) { 393 return false; 394 } 395 if (this == obj) { 396 return true; 397 } 398 RulesProfile other = (RulesProfile) obj; 399 return new EqualsBuilder().append(language, other.getLanguage()).append(name, other.getName()).isEquals(); 400 } 401 402 @Override 403 public int hashCode() { 404 return new HashCodeBuilder(17, 37).append(language).append(name).toHashCode(); 405 } 406 407 @Override 408 public Object clone() { 409 RulesProfile clone = RulesProfile.create(getName(), getLanguage()); 410 clone.setDefaultProfile(getDefaultProfile()); 411 clone.setProvided(getProvided()); 412 clone.setParentName(getParentName()); 413 if (CollectionUtils.isNotEmpty(activeRules)) { 414 clone.setActiveRules(new ArrayList<ActiveRule>(CollectionUtils.collect(activeRules, new Transformer() { 415 public Object transform(Object input) { 416 return ((ActiveRule) input).clone(); 417 } 418 }))); 419 } 420 if (CollectionUtils.isNotEmpty(getAlerts())) { 421 clone.setAlerts(new ArrayList<Alert>(CollectionUtils.collect(getAlerts(), new Transformer() { 422 public Object transform(Object input) { 423 return ((Alert) input).clone(); 424 } 425 }))); 426 } 427 if (CollectionUtils.isNotEmpty(getProjects())) { 428 clone.setProjects(new ArrayList<ResourceModel>(CollectionUtils.collect(getProjects(), new Transformer() { 429 public Object transform(Object input) { 430 return ((ResourceModel) input).clone(); 431 } 432 }))); 433 } 434 return clone; 435 } 436 437 @Override 438 public String toString() { 439 return new StringBuilder().append("[name=").append(name).append(",language=").append(language).append("]").toString(); 440 } 441 442 public static RulesProfile create(String name, String language) { 443 return new RulesProfile().setName(name).setLanguage(language); 444 } 445 446 public static RulesProfile create() { 447 return new RulesProfile(); 448 } 449}