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    }