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 */
020package org.sonar.api.rules;
021
022import org.apache.commons.lang.StringUtils;
023import org.apache.commons.lang.builder.EqualsBuilder;
024import org.apache.commons.lang.builder.HashCodeBuilder;
025import org.apache.commons.lang.builder.ToStringBuilder;
026import org.apache.commons.lang.builder.ToStringStyle;
027import org.sonar.api.database.DatabaseProperties;
028import org.sonar.check.Cardinality;
029
030import javax.persistence.*;
031
032import java.util.ArrayList;
033import java.util.List;
034
035@Entity
036@Table(name = "rules")
037public 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}