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 * @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 }