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 */ 020package org.sonar.api.profiles; 021 022import com.google.common.base.Predicate; 023import com.google.common.collect.Iterables; 024import com.google.common.collect.Lists; 025import org.apache.commons.collections.CollectionUtils; 026import org.apache.commons.collections.Transformer; 027import org.apache.commons.lang.StringUtils; 028import org.apache.commons.lang.builder.EqualsBuilder; 029import org.apache.commons.lang.builder.HashCodeBuilder; 030import org.sonar.api.rules.ActiveRule; 031import org.sonar.api.rules.Rule; 032import org.sonar.api.rules.RulePriority; 033import org.sonar.api.utils.MessageException; 034 035import javax.annotation.CheckForNull; 036import javax.annotation.Nullable; 037 038import java.util.ArrayList; 039import 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 */ 044public 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 null. 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 * @return the profile language 209 */ 210 public String getLanguage() { 211 return language; 212 } 213 214 /** 215 * Set the profile language 216 */ 217 public RulesProfile setLanguage(String s) { 218 this.language = s; 219 return this; 220 } 221 222 /** 223 * For internal use only. 224 * 225 * @since 2.5 226 */ 227 @CheckForNull 228 public String getParentName() { 229 return parentName; 230 } 231 232 /** 233 * For internal use only. 234 * 235 * @since 2.5 236 */ 237 public void setParentName(String parentName) { 238 this.parentName = parentName; 239 } 240 241 /** 242 * Note: disabled rules are excluded. 243 * 244 * @return the list of active rules for a given severity 245 */ 246 public List<ActiveRule> getActiveRules(RulePriority severity) { 247 List<ActiveRule> result = Lists.newArrayList(); 248 for (ActiveRule activeRule : activeRules) { 249 if (activeRule.getSeverity().equals(severity) && activeRule.isEnabled()) { 250 result.add(activeRule); 251 } 252 } 253 return result; 254 } 255 256 /** 257 * Get the active rules of a specific repository. 258 * Only enabled rules are selected. Disabled rules are excluded. 259 */ 260 public List<ActiveRule> getActiveRulesByRepository(String repositoryKey) { 261 List<ActiveRule> result = Lists.newArrayList(); 262 for (ActiveRule activeRule : activeRules) { 263 if (repositoryKey.equals(activeRule.getRepositoryKey()) && activeRule.isEnabled()) { 264 result.add(activeRule); 265 } 266 } 267 return result; 268 } 269 270 /** 271 * Note: disabled rules are excluded. 272 * 273 * @return an active rule from a plugin key and a rule key if the rule is activated, null otherwise 274 */ 275 @CheckForNull 276 public ActiveRule getActiveRule(String repositoryKey, String ruleKey) { 277 for (ActiveRule activeRule : activeRules) { 278 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getRuleKey(), ruleKey) && activeRule.isEnabled()) { 279 return activeRule; 280 } 281 } 282 return null; 283 } 284 285 /** 286 * Note: disabled rules are excluded. 287 */ 288 @CheckForNull 289 public ActiveRule getActiveRuleByConfigKey(String repositoryKey, String configKey) { 290 for (ActiveRule activeRule : activeRules) { 291 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getConfigKey(), configKey) && activeRule.isEnabled()) { 292 return activeRule; 293 } 294 } 295 return null; 296 } 297 298 /** 299 * Note: disabled rules are excluded. 300 */ 301 @CheckForNull 302 public ActiveRule getActiveRule(Rule rule) { 303 return getActiveRule(rule.getRepositoryKey(), rule.getKey()); 304 } 305 306 /** 307 * @param optionalSeverity if null, then the default rule severity is used 308 */ 309 public ActiveRule activateRule(final Rule rule, @Nullable RulePriority optionalSeverity) { 310 if (Iterables.any(activeRules, new Predicate<ActiveRule>() { 311 @Override 312 public boolean apply(ActiveRule input) { 313 return input.getRule().equals(rule); 314 } 315 })) { 316 throw MessageException.of(String.format( 317 "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.", 318 getName(), getLanguage(), rule.getRepositoryKey(), rule.getKey())); 319 } 320 ActiveRule activeRule = new ActiveRule(); 321 activeRule.setRule(rule); 322 activeRule.setRulesProfile(this); 323 activeRule.setSeverity(optionalSeverity == null ? rule.getSeverity() : optionalSeverity); 324 activeRules.add(activeRule); 325 return activeRule; 326 } 327 328 @Override 329 public boolean equals(Object obj) { 330 if (!(obj instanceof RulesProfile)) { 331 return false; 332 } 333 if (this == obj) { 334 return true; 335 } 336 RulesProfile other = (RulesProfile) obj; 337 return new EqualsBuilder().append(language, other.getLanguage()).append(name, other.getName()).isEquals(); 338 } 339 340 @Override 341 public int hashCode() { 342 return new HashCodeBuilder(17, 37).append(language).append(name).toHashCode(); 343 } 344 345 @Override 346 public Object clone() { 347 RulesProfile clone = RulesProfile.create(getName(), getLanguage()); 348 clone.setDefaultProfile(getDefaultProfile()); 349 clone.setParentName(getParentName()); 350 if (activeRules != null && !activeRules.isEmpty()) { 351 clone.setActiveRules(new ArrayList<ActiveRule>(CollectionUtils.collect(activeRules, new Transformer() { 352 @Override 353 public Object transform(Object input) { 354 return ((ActiveRule) input).clone(); 355 } 356 }))); 357 } 358 return clone; 359 } 360 361 @Override 362 public String toString() { 363 return new StringBuilder().append("[name=").append(name).append(",language=").append(language).append("]").toString(); 364 } 365 366 public static RulesProfile create(String name, String language) { 367 return new RulesProfile().setName(name).setLanguage(language); 368 } 369 370 public static RulesProfile create() { 371 return new RulesProfile(); 372 } 373}