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