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