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