001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2009 SonarSource SA
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 org.apache.commons.collections.CollectionUtils;
023 import org.apache.commons.collections.Transformer;
024 import org.apache.commons.lang.StringUtils;
025 import org.apache.commons.lang.builder.EqualsBuilder;
026 import org.apache.commons.lang.builder.HashCodeBuilder;
027 import org.sonar.api.database.model.ResourceModel;
028 import org.sonar.api.rules.ActiveRule;
029 import org.sonar.api.rules.Rule;
030 import org.sonar.api.rules.RulePriority;
031
032 import java.util.ArrayList;
033 import java.util.List;
034
035 import javax.persistence.*;
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 = "default_profile", updatable = true, nullable = false)
068 private Boolean defaultProfile = Boolean.FALSE;
069
070 @Column(name = "provided", updatable = true, nullable = false)
071 private Boolean provided = Boolean.FALSE;
072
073 @Column(name = "language", updatable = true, nullable = false)
074 private String language;
075
076 @Column(name = "parent_name", updatable = true, nullable = true)
077 private String parentName;
078
079 @OneToMany(mappedBy = "rulesProfile", fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE })
080 private List<ActiveRule> activeRules = new ArrayList<ActiveRule>();
081
082 @OneToMany(mappedBy = "rulesProfile", fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE })
083 private List<Alert> alerts = new ArrayList<Alert>();
084
085 @OneToMany(mappedBy = "rulesProfile", fetch = FetchType.LAZY)
086 private List<ResourceModel> projects = new ArrayList<ResourceModel>();
087
088 /**
089 * @deprecated use the factory method create()
090 */
091 @Deprecated
092 public RulesProfile() {
093 }
094
095 /**
096 * @deprecated since 2.3. Use the factory method create()
097 */
098 @Deprecated
099 public RulesProfile(String name, String language) {
100 this.name = name;
101 this.language = language;
102 this.activeRules = new ArrayList<ActiveRule>();
103 this.alerts = new ArrayList<Alert>();
104 this.projects = new ArrayList<ResourceModel>();
105 }
106
107 /**
108 * @deprecated since 2.3. Use the factory method create()
109 */
110 @Deprecated
111 public RulesProfile(String name, String language, boolean defaultProfile, boolean provided) {
112 this(name, language);
113 this.defaultProfile = defaultProfile;
114 this.provided = provided;
115 }
116
117 public Integer getId() {
118 return id;
119 }
120
121 /**
122 * @return the profile name, unique by language.
123 */
124 public String getName() {
125 return name;
126 }
127
128 /**
129 * Set the profile name.
130 */
131 public RulesProfile setName(String s) {
132 this.name = s;
133 return this;
134 }
135
136 /**
137 * @return the list of active rules
138 */
139 public List<ActiveRule> getActiveRules() {
140 return activeRules;
141 }
142
143 /**
144 * Set the list of active rules
145 */
146 public void setActiveRules(List<ActiveRule> activeRules) {
147 this.activeRules = activeRules;
148 }
149
150 /**
151 * @return whether this is the default profile for the language
152 */
153 public Boolean getDefaultProfile() {
154 return defaultProfile;
155 }
156
157 /**
158 * Set whether this is the default profile for the language. The default profile is used when none is explicitly defined when auditing a
159 * project.
160 */
161 public void setDefaultProfile(Boolean b) {
162 this.defaultProfile = b;
163 }
164
165 /**
166 * @return whether the profile is defined in a plugin. Provided profiles are automatically restored during server startup and can not be
167 * updated by end users.
168 */
169 public Boolean getProvided() {
170 return provided;
171 }
172
173 /**
174 * Set whether the profile is provided by a plugin
175 */
176 public void setProvided(Boolean b) {
177 this.provided = b;
178 }
179
180 /**
181 * @return the profile language
182 */
183 public String getLanguage() {
184 return language;
185 }
186
187 /**
188 * Set the profile language
189 */
190 public RulesProfile setLanguage(String s) {
191 this.language = s;
192 return this;
193 }
194
195 /**
196 * For internal use only.
197 *
198 * @since 2.5
199 */
200 public String getParentName() {
201 return parentName;
202 }
203
204 /**
205 * For internal use only.
206 *
207 * @since 2.5
208 */
209 public void setParentName(String parentName) {
210 this.parentName = parentName;
211 }
212
213 /**
214 * @return the list of alerts defined in the profile
215 */
216 public List<Alert> getAlerts() {
217 return alerts;
218 }
219
220 /**
221 * Sets the list of alerts for the profile
222 */
223 public void setAlerts(List<Alert> alerts) {
224 this.alerts = alerts;
225 }
226
227 /**
228 * @return the list of projects attached to the profile
229 */
230 public List<ResourceModel> getProjects() {
231 return projects;
232 }
233
234 /**
235 * Sets the list of projects attached to the profile
236 */
237 public void setProjects(List<ResourceModel> projects) {
238 this.projects = projects;
239 }
240
241 /**
242 * @return the list of active rules for a given priority
243 */
244 public List<ActiveRule> getActiveRules(RulePriority priority) {
245 List<ActiveRule> result = new ArrayList<ActiveRule>();
246 for (ActiveRule activeRule : getActiveRules()) {
247 if (activeRule.getSeverity().equals(priority)) {
248 result.add(activeRule);
249 }
250 }
251 return result;
252 }
253
254 /**
255 * @deprecated since 2.3 use {@link #getActiveRulesByRepository(String)} instead.
256 */
257 @Deprecated
258 public List<ActiveRule> getActiveRulesByPlugin(String repositoryKey) {
259 return getActiveRulesByRepository(repositoryKey);
260 }
261
262 public List<ActiveRule> getActiveRulesByRepository(String repositoryKey) {
263 List<ActiveRule> result = new ArrayList<ActiveRule>();
264 for (ActiveRule activeRule : getActiveRules()) {
265 if (repositoryKey.equals(activeRule.getRepositoryKey())) {
266 result.add(activeRule);
267 }
268 }
269 return result;
270 }
271
272 /**
273 * @return an active rule from a plugin key and a rule key if the rule is activated, null otherwise
274 */
275 public ActiveRule getActiveRule(String repositoryKey, String ruleKey) {
276 for (ActiveRule activeRule : getActiveRules()) {
277 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getRuleKey(), ruleKey)) {
278 return activeRule;
279 }
280 }
281 return null;
282 }
283
284 public ActiveRule getActiveRuleByConfigKey(String repositoryKey, String configKey) {
285 for (ActiveRule activeRule : getActiveRules()) {
286 if (StringUtils.equals(activeRule.getRepositoryKey(), repositoryKey) && StringUtils.equals(activeRule.getConfigKey(), configKey)) {
287 return activeRule;
288 }
289 }
290 return null;
291 }
292
293 public ActiveRule getActiveRule(Rule rule) {
294 return getActiveRule(rule.getRepositoryKey(), rule.getKey());
295 }
296
297 /**
298 * @param optionalSeverity if null, then the default rule severity is used
299 */
300 public ActiveRule activateRule(Rule rule, RulePriority optionalSeverity) {
301 ActiveRule activeRule = new ActiveRule();
302 activeRule.setRule(rule);
303 activeRule.setRulesProfile(this);
304 activeRule.setSeverity(optionalSeverity == null ? rule.getSeverity() : optionalSeverity);
305 activeRules.add(activeRule);
306 return activeRule;
307 }
308
309 @Override
310 public boolean equals(Object obj) {
311 if (!(obj instanceof RulesProfile)) {
312 return false;
313 }
314 if (this == obj) {
315 return true;
316 }
317 RulesProfile other = (RulesProfile) obj;
318 return new EqualsBuilder().append(language, other.getLanguage()).append(name, other.getName()).isEquals();
319 }
320
321 @Override
322 public int hashCode() {
323 return new HashCodeBuilder(17, 37).append(language).append(name).toHashCode();
324 }
325
326 @Override
327 public Object clone() {
328 RulesProfile clone = RulesProfile.create(getName(), getLanguage());
329 clone.setDefaultProfile(getDefaultProfile());
330 clone.setProvided(getProvided());
331 clone.setParentName(getParentName());
332 if (CollectionUtils.isNotEmpty(getActiveRules())) {
333 clone.setActiveRules(new ArrayList<ActiveRule>(CollectionUtils.collect(getActiveRules(), new Transformer() {
334 public Object transform(Object input) {
335 return ((ActiveRule) input).clone();
336 }
337 })));
338 }
339 if (CollectionUtils.isNotEmpty(getAlerts())) {
340 clone.setAlerts(new ArrayList<Alert>(CollectionUtils.collect(getAlerts(), new Transformer() {
341 public Object transform(Object input) {
342 return ((Alert) input).clone();
343 }
344 })));
345 }
346 if (CollectionUtils.isNotEmpty(getProjects())) {
347 clone.setProjects(new ArrayList<ResourceModel>(CollectionUtils.collect(getProjects(), new Transformer() {
348 public Object transform(Object input) {
349 return ((ResourceModel) input).clone();
350 }
351 })));
352 }
353 return clone;
354 }
355
356 @Override
357 public String toString() {
358 return new StringBuilder().append("[name=").append(name).append(",language=").append(language).append("]").toString();
359 }
360
361 public static RulesProfile create(String name, String language) {
362 return new RulesProfile().setName(name).setLanguage(language);
363 }
364
365 public static RulesProfile create() {
366 return new RulesProfile();
367 }
368 }