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