001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 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.rules;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.apache.commons.lang.builder.*;
024    import org.sonar.api.database.DatabaseProperties;
025    import org.sonar.check.Cardinality;
026    
027    import java.util.ArrayList;
028    import java.util.List;
029    
030    import javax.persistence.*;
031    
032    @Entity
033    @Table(name = "rules")
034    public final class Rule {
035    
036      private final static RulesCategory NONE = new RulesCategory("none");
037      
038      @Id
039      @Column(name = "id")
040      @GeneratedValue
041      private Integer id;
042    
043      /**
044       * The default priority given to a rule if not explicitly set
045       */
046      public static final RulePriority DEFAULT_PRIORITY = RulePriority.MAJOR;
047    
048      @Column(name = "name", updatable = true, nullable = true, length = 200)
049      private String name;
050    
051      @Column(name = "plugin_rule_key", updatable = false, nullable = true, length = 200)
052      private String key;
053    
054      @Column(name = "enabled", updatable = true, nullable = true)
055      private Boolean enabled = Boolean.TRUE;
056    
057      @Column(name = "plugin_config_key", updatable = true, nullable = true, length = 500)
058      private String configKey;
059    
060      // Godin: This field should be named priority, otherwise StandardRulesXmlParserTest fails
061      @Column(name = "priority", updatable = true, nullable = true)
062      @Enumerated(EnumType.ORDINAL)
063      private RulePriority priority = DEFAULT_PRIORITY;
064    
065      @Column(name = "description", updatable = true, nullable = true, length = DatabaseProperties.MAX_TEXT_SIZE)
066      private String description;
067    
068      @Column(name = "plugin_name", updatable = true, nullable = false)
069      private String pluginName;
070    
071      @Enumerated(EnumType.STRING)
072      @Column(name = "cardinality", updatable = true, nullable = false)
073      private Cardinality cardinality = Cardinality.SINGLE;
074    
075      @ManyToOne(fetch = FetchType.EAGER)
076      @JoinColumn(name = "parent_id", updatable = true, nullable = true)
077      private Rule parent = null;
078    
079      @org.hibernate.annotations.Cascade({ org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
080      @OneToMany(mappedBy = "rule")
081      private List<RuleParam> params = new ArrayList<RuleParam>();
082    
083      /**
084       * @deprecated since 2.3. Use the factory method {@link #create()}
085       */
086      @Deprecated
087      public Rule() {
088        // TODO reduce visibility to package
089      }
090    
091      /**
092       * Creates rule with minimum set of info
093       * 
094       * @param pluginName the plugin name indicates which plugin the rule belongs to
095       * @param key the key should be unique within a plugin, but it is even more careful for the time being that it is unique across the
096       *          application
097       * @deprecated since 2.3. Use the factory method {@link #create()}
098       */
099      @Deprecated
100      public Rule(String pluginName, String key) {
101        this.pluginName = pluginName;
102        this.key = key;
103        this.configKey = key;
104      }
105    
106      /**
107       * Creates a fully qualified rule
108       * 
109       * @param pluginKey the plugin the rule belongs to
110       * @param key the key should be unique within a plugin, but it is even more careful for the time being that it is unique across the
111       *          application
112       * @param name the name displayed in the UI
113       * @param rulesCategory the ISO category the rule belongs to
114       * @param severity this is the severity associated to the rule
115       * @deprecated since 2.3. Use the factory method {@link #create()}
116       */
117      @Deprecated
118      public Rule(String pluginKey, String key, String name, RulesCategory rulesCategory, RulePriority severity) {
119        setName(name);
120        this.key = key;
121        this.configKey = key;
122        this.priority = severity;
123        this.pluginName = pluginKey;
124      }
125    
126      /**
127       * @deprecated since 2.3. Use the factory method {@link #create()}
128       */
129      @Deprecated
130      public Rule(String name, String key, RulesCategory rulesCategory, String pluginName, String description) {
131        this();
132        setName(name);
133        this.key = key;
134        this.configKey = key;
135        this.pluginName = pluginName;
136        this.description = description;
137      }
138    
139      /**
140       * @deprecated since 2.3. Use the factory method {@link #create()}
141       */
142      @Deprecated
143      public Rule(String name, String key, String configKey, RulesCategory rulesCategory, String pluginName, String description) {
144        this();
145        setName(name);
146        this.key = key;
147        this.configKey = configKey;
148        this.pluginName = pluginName;
149        this.description = description;
150      }
151    
152      public Integer getId() {
153        return id;
154      }
155    
156      /**
157       * @deprecated since 2.3. visibility should be decreased to protected or package
158       */
159      @Deprecated
160      public void setId(Integer id) {
161        this.id = id;
162      }
163    
164      public String getName() {
165        return name;
166      }
167    
168      /**
169       * Sets the rule name
170       */
171      public Rule setName(String name) {
172        this.name = removeNewLineCharacters(name);
173        return this;
174      }
175    
176      public String getKey() {
177        return key;
178      }
179    
180      /**
181       * Sets the rule key
182       */
183      public Rule setKey(String key) {
184        this.key = key;
185        return this;
186      }
187    
188      /**
189       * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
190       */
191      @Deprecated
192      public RulesCategory getRulesCategory() {
193        return NONE;
194      }
195    
196      /**
197       * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
198       */
199      @Deprecated
200      public Rule setRulesCategory(RulesCategory rulesCategory) {
201        return this;
202      }
203    
204      /**
205       * @deprecated since 2.5 use {@link #getRepositoryKey()} instead
206       */
207      @Deprecated
208      public String getPluginName() {
209        return pluginName;
210      }
211    
212      /**
213       * @deprecated since 2.5 use {@link #setRepositoryKey(String)} instead
214       */
215      @Deprecated
216      public Rule setPluginName(String pluginName) {
217        this.pluginName = pluginName;
218        return this;
219      }
220    
221      public String getConfigKey() {
222        return configKey;
223      }
224    
225      /**
226       * Sets the configuration key
227       */
228      public Rule setConfigKey(String configKey) {
229        this.configKey = configKey;
230        return this;
231      }
232    
233      public String getDescription() {
234        return description;
235      }
236    
237      /**
238       * Sets the rule description
239       */
240      public Rule setDescription(String description) {
241        this.description = StringUtils.strip(description);
242        return this;
243      }
244    
245      public Boolean isEnabled() {
246        return enabled;
247      }
248    
249      /**
250       * Do not call. Used only by sonar.
251       */
252      public Rule setEnabled(Boolean b) {
253        this.enabled = b;
254        return this;
255      }
256    
257      public List<RuleParam> getParams() {
258        return params;
259      }
260    
261      public RuleParam getParam(String key) {
262        for (RuleParam param : params) {
263          if (StringUtils.equals(key, param.getKey())) {
264            return param;
265          }
266        }
267        return null;
268      }
269    
270      /**
271       * Sets the rule parameters
272       */
273      public Rule setParams(List<RuleParam> params) {
274        this.params.clear();
275        for (RuleParam param : params) {
276          param.setRule(this);
277          this.params.add(param);
278        }
279        return this;
280      }
281    
282      public RuleParam createParameter() {
283        RuleParam parameter = new RuleParam()
284            .setRule(this);
285        params.add(parameter);
286        return parameter;
287      }
288    
289      public RuleParam createParameter(String key) {
290        RuleParam parameter = new RuleParam()
291            .setKey(key)
292            .setRule(this);
293        params.add(parameter);
294        return parameter;
295      }
296    
297      /**
298       * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
299       */
300      @Deprecated
301      public Integer getCategoryId() {
302        return null;
303      }
304    
305      /**
306       * @since 2.5
307       */
308      public RulePriority getSeverity() {
309        return priority;
310      }
311    
312      /**
313       * @param severity severity to set, if null, uses the default priority.
314       * @since 2.5
315       */
316      public Rule setSeverity(RulePriority severity) {
317        if (severity == null) {
318          this.priority = DEFAULT_PRIORITY;
319        } else {
320          this.priority = severity;
321        }
322        return this;
323      }
324    
325      /**
326       * @deprecated since 2.5 use {@link #getSeverity()} instead. See http://jira.codehaus.org/browse/SONAR-1829
327       */
328      @Deprecated
329      public RulePriority getPriority() {
330        return priority;
331      }
332    
333      /**
334       * Sets the rule priority. If null, uses the default priority
335       * 
336       * @deprecated since 2.5 use {@link #setSeverity(RulePriority)} instead. See http://jira.codehaus.org/browse/SONAR-1829
337       */
338      @Deprecated
339      public Rule setPriority(RulePriority priority) {
340        return setSeverity(priority);
341      }
342    
343      public String getRepositoryKey() {
344        return pluginName;
345      }
346    
347      public Rule setRepositoryKey(String s) {
348        this.pluginName = s;
349        return this;
350      }
351    
352      public Rule setUniqueKey(String repositoryKey, String key) {
353        return setRepositoryKey(repositoryKey).setKey(key).setConfigKey(key);
354      }
355    
356      public Cardinality getCardinality() {
357        return cardinality;
358      }
359    
360      public Rule setCardinality(Cardinality c) {
361        this.cardinality = c;
362        return this;
363      }
364    
365      public Rule getParent() {
366        return parent;
367      }
368    
369      public Rule setParent(Rule parent) {
370        this.parent = parent;
371        return this;
372      }
373    
374      @Override
375      public boolean equals(Object obj) {
376        if (!(obj instanceof Rule)) {
377          return false;
378        }
379        if (this == obj) {
380          return true;
381        }
382        Rule other = (Rule) obj;
383        return new EqualsBuilder()
384            .append(pluginName, other.getRepositoryKey())
385            .append(key, other.getKey())
386            .isEquals();
387      }
388    
389      @Override
390      public int hashCode() {
391        return new HashCodeBuilder(17, 37)
392            .append(pluginName)
393            .append(key)
394            .toHashCode();
395      }
396    
397      @Override
398      public String toString() {
399        return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
400      }
401    
402      private String removeNewLineCharacters(String text) {
403        String removedCRLF = StringUtils.remove(text, "\n");
404        removedCRLF = StringUtils.remove(removedCRLF, "\r");
405        removedCRLF = StringUtils.remove(removedCRLF, "\n\r");
406        removedCRLF = StringUtils.remove(removedCRLF, "\r\n");
407        return removedCRLF;
408      }
409    
410      public static Rule create() {
411        return new Rule();
412      }
413    
414      /**
415       * Create with all required fields
416       */
417      public static Rule create(String repositoryKey, String key, String name) {
418        return new Rule().setUniqueKey(repositoryKey, key).setName(name);
419      }
420    
421      /**
422       * Create with all required fields
423       * @since 2.10
424       */
425      public static Rule create(String repositoryKey, String key) {
426        return new Rule().setUniqueKey(repositoryKey, key);
427      }
428    }