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