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.apache.commons.lang.builder.ReflectionToStringBuilder; 029 import org.apache.commons.lang.builder.ToStringStyle; 030 import org.sonar.api.database.model.ResourceModel; 031 import org.sonar.api.rules.ActiveRule; 032 import org.sonar.api.rules.Rule; 033 import org.sonar.api.rules.RulePriority; 034 035 import javax.persistence.*; 036 import java.util.ArrayList; 037 import java.util.List; 038 039 /** 040 * This class is badly named. It should be "QualityProfile". Indeed it does not relate only to rules but to metric thresholds too. 041 */ 042 @Entity 043 @Table(name = "rules_profiles") 044 public class RulesProfile implements Cloneable { 045 046 /** 047 * Name of the default profile "Sonar Way" 048 */ 049 public static final String SONAR_WAY_NAME = "Sonar way"; 050 051 /** 052 * Name of the default java profile "Sonar way with Findbugs" 053 */ 054 public static final String SONAR_WAY_FINDBUGS_NAME = "Sonar way with Findbugs"; 055 056 /** 057 * Name of the default java profile "Sun checks" 058 */ 059 public static final String SUN_CONVENTIONS_NAME = "Sun checks"; 060 061 @Id 062 @Column(name = "id") 063 @GeneratedValue 064 private Integer id; 065 066 @Column(name = "name", updatable = true, nullable = false) 067 private String name; 068 069 @Column(name = "version", updatable = true, nullable = false) 070 private int version = 1; 071 072 @Column(name = "default_profile", updatable = true, nullable = false) 073 private Boolean defaultProfile = Boolean.FALSE; 074 075 @Column(name = "provided", updatable = true, nullable = false) 076 private Boolean provided = Boolean.FALSE; 077 078 @Column(name = "enabled", updatable = true, nullable = false) 079 private Boolean enabled = Boolean.TRUE; 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) 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 @OneToMany(mappedBy = "rulesProfile", fetch = FetchType.LAZY) 097 private List<ResourceModel> projects = Lists.newArrayList(); 098 099 /** 100 * @deprecated use the factory method create() 101 */ 102 @Deprecated 103 public RulesProfile() { 104 } 105 106 /** 107 * @deprecated since 2.3. Use the factory method create() 108 */ 109 @Deprecated 110 public RulesProfile(String name, String language) { 111 this.name = name; 112 this.language = language; 113 this.activeRules = Lists.newArrayList(); 114 this.alerts = Lists.newArrayList(); 115 this.projects = Lists.newArrayList(); 116 } 117 118 /** 119 * @deprecated since 2.3. Use the factory method create() 120 */ 121 @Deprecated 122 public RulesProfile(String name, String language, boolean defaultProfile, boolean provided) { 123 this(name, language); 124 this.defaultProfile = defaultProfile; 125 this.provided = provided; 126 } 127 128 public Integer getId() { 129 return id; 130 } 131 132 /** 133 * @return the profile name, unique by language. 134 */ 135 public String getName() { 136 return name; 137 } 138 139 /** 140 * Set the profile name. 141 */ 142 public RulesProfile setName(String s) { 143 this.name = s; 144 return this; 145 } 146 147 public int getVersion() { 148 return version; 149 } 150 151 public RulesProfile setVersion(int version) { 152 this.version = version; 153 return this; 154 } 155 156 public Boolean getUsed() { 157 return used; 158 } 159 160 public RulesProfile setUsed(Boolean used) { 161 this.used = used; 162 return this; 163 } 164 165 /** 166 * @return the list of active rules 167 */ 168 public List<ActiveRule> getActiveRules() { 169 return getActiveRules(false); 170 } 171 172 /** 173 * @return the list of active rules 174 */ 175 public List<ActiveRule> getActiveRules(boolean acceptDisabledRules) { 176 if (acceptDisabledRules) { 177 return activeRules; 178 } 179 List<ActiveRule> result = Lists.newArrayList(); 180 for (ActiveRule activeRule : activeRules) { 181 if (activeRule.isEnabled()) { 182 result.add(activeRule); 183 } 184 } 185 return result; 186 } 187 188 public RulesProfile removeActiveRule(ActiveRule activeRule) { 189 activeRules.remove(activeRule); 190 return this; 191 } 192 193 public RulesProfile addActiveRule(ActiveRule activeRule) { 194 activeRules.add(activeRule); 195 return this; 196 } 197 198 /** 199 * Set the list of active rules 200 */ 201 public void setActiveRules(List<ActiveRule> activeRules) { 202 this.activeRules = activeRules; 203 } 204 205 /** 206 * @return whether this is the default profile for the language 207 */ 208 public Boolean getDefaultProfile() { 209 return defaultProfile; 210 } 211 212 /** 213 * Set whether this is the default profile for the language. The default profile is used when none is explicitly defined when auditing a 214 * project. 215 */ 216 public void setDefaultProfile(Boolean b) { 217 this.defaultProfile = b; 218 } 219 220 /** 221 * @return whether the profile is defined in a plugin. Provided profiles are automatically restored during server startup and can not be 222 * updated by end users. 223 */ 224 public Boolean getProvided() { 225 return provided; 226 } 227 228 /** 229 * Set whether the profile is provided by a plugin 230 */ 231 public void setProvided(Boolean b) { 232 this.provided = b; 233 } 234 235 public Boolean getEnabled() { 236 return enabled; 237 } 238 239 public boolean isEnabled() { 240 return enabled == Boolean.TRUE; 241 } 242 243 public RulesProfile setEnabled(Boolean b) { 244 this.enabled = b; 245 return this; 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 * @return the list of projects attached to the profile 297 */ 298 public List<ResourceModel> getProjects() { 299 return projects; 300 } 301 302 /** 303 * Sets the list of projects attached to the profile 304 */ 305 public void setProjects(List<ResourceModel> projects) { 306 this.projects = projects; 307 } 308 309 /** 310 * Note: disabled rules are excluded. 311 * @return the list of active rules for a given severity 312 */ 313 public List<ActiveRule> getActiveRules(RulePriority severity) { 314 List<ActiveRule> result = Lists.newArrayList(); 315 for (ActiveRule activeRule : activeRules) { 316 if (activeRule.getSeverity().equals(severity) && activeRule.isEnabled()) { 317 result.add(activeRule); 318 } 319 } 320 return result; 321 } 322 323 /** 324 * @deprecated since 2.3 use {@link #getActiveRulesByRepository(String)} instead. 325 */ 326 @Deprecated 327 public List<ActiveRule> getActiveRulesByPlugin(String repositoryKey) { 328 return getActiveRulesByRepository(repositoryKey); 329 } 330 331 /** 332 * Get the active rules of a specific repository. 333 * Only enabled rules are selected. Disabled rules are excluded. 334 */ 335 public List<ActiveRule> getActiveRulesByRepository(String repositoryKey) { 336 List<ActiveRule> result = Lists.newArrayList(); 337 for (ActiveRule activeRule : activeRules) { 338 if (repositoryKey.equals(activeRule.getRepositoryKey()) && activeRule.isEnabled()) { 339 result.add(activeRule); 340 } 341 } 342 return result; 343 } 344 345 /** 346 * Note: disabled rules are excluded. 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 }