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 }