001/* 002 * SonarQube 003 * Copyright (C) 2009-2017 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program 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 * This program 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 java.util.ArrayList; 023import java.util.List; 024import java.util.stream.Collectors; 025import javax.annotation.CheckForNull; 026import javax.annotation.Nullable; 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 035/** 036 * This class is badly named. It should be "QualityProfile". Indeed it does not relate only to rules but to metric thresholds too. 037 */ 038public class RulesProfile implements Cloneable { 039 040 /** 041 * Name of the default profile "Sonar Way" 042 * @deprecated in 4.2. Use your own constant. 043 */ 044 @Deprecated 045 public static final String SONAR_WAY_NAME = "Sonar way"; 046 047 /** 048 * Name of the default java profile "Sonar way with Findbugs" 049 * @deprecated in 4.2. Use your own constant. 050 */ 051 @Deprecated 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 * @deprecated in 4.2. Use your own constant. 057 */ 058 @Deprecated 059 public static final String SUN_CONVENTIONS_NAME = "Sun checks"; 060 061 private String name; 062 private Boolean defaultProfile = Boolean.FALSE; 063 private String language; 064 private List<ActiveRule> activeRules = new ArrayList<>(); 065 066 /** 067 * @deprecated use the factory method create() 068 */ 069 @Deprecated 070 public RulesProfile() { 071 } 072 073 /** 074 * @deprecated since 2.3. Use the factory method create() 075 */ 076 @Deprecated 077 public RulesProfile(String name, String language) { 078 this.name = name; 079 this.language = language; 080 this.activeRules = new ArrayList<>(); 081 } 082 083 /** 084 * @deprecated since 2.3. Use the factory method create() 085 */ 086 @Deprecated 087 public RulesProfile(String name, String language, boolean defaultProfile, /* kept for backward-compatibility */boolean provided) { 088 this(name, language); 089 this.defaultProfile = defaultProfile; 090 } 091 092 public Integer getId() { 093 return null; 094 } 095 096 /** 097 * @return the profile name, unique by language. 098 */ 099 public String getName() { 100 return name; 101 } 102 103 /** 104 * Set the profile name. 105 */ 106 public RulesProfile setName(String s) { 107 this.name = s; 108 return this; 109 } 110 111 /** 112 * @deprecated profile versioning is dropped in 4.4. Always returns -1. 113 */ 114 @Deprecated 115 public int getVersion() { 116 return -1; 117 } 118 119 /** 120 * @deprecated profile versioning is dropped in 4.4. Always returns -1. 121 */ 122 @Deprecated 123 public RulesProfile setVersion(int version) { 124 // ignore 125 return this; 126 } 127 128 /** 129 * @deprecated profile versioning is dropped in 4.4. Always returns null. 130 */ 131 @CheckForNull 132 @Deprecated 133 public Boolean getUsed() { 134 return null; 135 } 136 137 /** 138 * @deprecated profile versioning is dropped in 4.4. Always returns -1. 139 */ 140 @Deprecated 141 public RulesProfile setUsed(Boolean used) { 142 return this; 143 } 144 145 /** 146 * @return the list of active rules 147 */ 148 public List<ActiveRule> getActiveRules() { 149 return getActiveRules(false); 150 } 151 152 /** 153 * @return the list of active rules 154 */ 155 public List<ActiveRule> getActiveRules(boolean acceptDisabledRules) { 156 if (acceptDisabledRules) { 157 return activeRules; 158 } 159 List<ActiveRule> result = new ArrayList<>(); 160 for (ActiveRule activeRule : activeRules) { 161 if (activeRule.isEnabled()) { 162 result.add(activeRule); 163 } 164 } 165 return result; 166 } 167 168 public RulesProfile removeActiveRule(ActiveRule activeRule) { 169 activeRules.remove(activeRule); 170 return this; 171 } 172 173 public RulesProfile addActiveRule(ActiveRule activeRule) { 174 activeRules.add(activeRule); 175 return this; 176 } 177 178 /** 179 * Set the list of active rules 180 */ 181 public void setActiveRules(List<ActiveRule> activeRules) { 182 this.activeRules = activeRules; 183 } 184 185 /** 186 * @return whether this is the default profile for the language 187 */ 188 public Boolean getDefaultProfile() { 189 return defaultProfile; 190 } 191 192 /** 193 * Set whether this is the default profile for the language. The default profile is used when none is explicitly defined when auditing a 194 * project. 195 */ 196 public void setDefaultProfile(Boolean b) { 197 this.defaultProfile = b; 198 } 199 200 /** 201 * @return the profile language 202 */ 203 public String getLanguage() { 204 return language; 205 } 206 207 /** 208 * Set the profile language 209 */ 210 public RulesProfile setLanguage(String s) { 211 this.language = s; 212 return this; 213 } 214 215 /** 216 * Does nothing. 217 * 218 * @return {@code null} 219 * @deprecated in 6.5 220 */ 221 @Deprecated 222 @CheckForNull 223 public String getParentName() { 224 return null; 225 } 226 227 /** 228 * Does nothing. 229 * 230 * @deprecated in 6.5 231 */ 232 @Deprecated 233 public void setParentName(String parentName) { 234 // does nothing 235 } 236 237 /** 238 * Note: disabled rules are excluded. 239 * 240 * @return the list of active rules for a given severity 241 */ 242 public List<ActiveRule> getActiveRules(RulePriority severity) { 243 List<ActiveRule> result = new ArrayList<>(); 244 for (ActiveRule activeRule : activeRules) { 245 if (activeRule.getSeverity().equals(severity) && activeRule.isEnabled()) { 246 result.add(activeRule); 247 } 248 } 249 return result; 250 } 251 252 /** 253 * Get the active rules of a specific repository. 254 * Only enabled rules are selected. Disabled rules are excluded. 255 */ 256 public List<ActiveRule> getActiveRulesByRepository(String repositoryKey) { 257 List<ActiveRule> result = new ArrayList<>(); 258 for (ActiveRule activeRule : activeRules) { 259 if (repositoryKey.equals(activeRule.getRepositoryKey()) && activeRule.isEnabled()) { 260 result.add(activeRule); 261 } 262 } 263 return result; 264 } 265 266 /** 267 * Note: disabled rules are excluded. 268 * 269 * @return an active rule from a plugin key and a rule key if the rule is activated, null otherwise 270 */ 271 @CheckForNull 272 public ActiveRule getActiveRule(String repositoryKey, String ruleKey) { 273 for (ActiveRule activeRule : activeRules) { 274 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getRuleKey(), ruleKey) && activeRule.isEnabled()) { 275 return activeRule; 276 } 277 } 278 return null; 279 } 280 281 /** 282 * Note: disabled rules are excluded. 283 */ 284 @CheckForNull 285 public ActiveRule getActiveRuleByConfigKey(String repositoryKey, String configKey) { 286 for (ActiveRule activeRule : activeRules) { 287 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getConfigKey(), configKey) && activeRule.isEnabled()) { 288 return activeRule; 289 } 290 } 291 return null; 292 } 293 294 /** 295 * Note: disabled rules are excluded. 296 */ 297 @CheckForNull 298 public ActiveRule getActiveRule(Rule rule) { 299 return getActiveRule(rule.getRepositoryKey(), rule.getKey()); 300 } 301 302 /** 303 * @param optionalSeverity if null, then the default rule severity is used 304 */ 305 public ActiveRule activateRule(final Rule rule, @Nullable RulePriority optionalSeverity) { 306 if (activeRules.stream().anyMatch(ar -> ar.getRule().equals(rule))) { 307 throw MessageException.of(String.format( 308 "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.", 309 getName(), getLanguage(), rule.getRepositoryKey(), rule.getKey())); 310 } 311 ActiveRule activeRule = new ActiveRule(this, rule, optionalSeverity); 312 activeRules.add(activeRule); 313 return activeRule; 314 } 315 316 @Override 317 public boolean equals(Object obj) { 318 if (!(obj instanceof RulesProfile)) { 319 return false; 320 } 321 if (this == obj) { 322 return true; 323 } 324 RulesProfile other = (RulesProfile) obj; 325 return new EqualsBuilder().append(language, other.getLanguage()).append(name, other.getName()).isEquals(); 326 } 327 328 @Override 329 public int hashCode() { 330 return new HashCodeBuilder(17, 37).append(language).append(name).toHashCode(); 331 } 332 333 @Override 334 public Object clone() { 335 RulesProfile clone = RulesProfile.create(getName(), getLanguage()); 336 clone.setDefaultProfile(getDefaultProfile()); 337 if (activeRules != null && !activeRules.isEmpty()) { 338 clone.setActiveRules(activeRules.stream() 339 .map(ar -> (ActiveRule) ar.clone()) 340 .collect(Collectors.toList())); 341 } 342 return clone; 343 } 344 345 @Override 346 public String toString() { 347 return new StringBuilder().append("[name=").append(name).append(",language=").append(language).append("]").toString(); 348 } 349 350 public static RulesProfile create(String name, String language) { 351 return new RulesProfile().setName(name).setLanguage(language); 352 } 353 354 public static RulesProfile create() { 355 return new RulesProfile(); 356 } 357 358}