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