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.builder.EqualsBuilder;
023    import org.apache.commons.lang.builder.HashCodeBuilder;
024    import org.apache.commons.lang.builder.ReflectionToStringBuilder;
025    import org.sonar.api.resources.Resource;
026    import org.sonar.api.utils.Logs;
027    
028    import java.util.Date;
029    
030    /**
031     * A class that represents a violation. A violation happens when a resource does not respect a defined rule.
032     */
033    public class Violation {
034    
035      private Resource resource;
036      private Rule rule;
037      private String message;
038      private RulePriority severity;
039      private Integer lineId;
040      private Double cost;
041      private Date createdAt;
042      private boolean switchedOff=false;
043      private String checksum;
044      private boolean isNew=false;
045    
046      /**
047       * Creates of a violation from a rule. Will need to define the resource later on
048       * 
049       * @deprecated since 2.3. Use the factory method create()
050       */
051      @Deprecated
052      public Violation(Rule rule) {
053        this.rule = rule;
054      }
055    
056      /**
057       * Creates a fully qualified violation
058       * 
059       * @param rule
060       *          the rule that has been violated
061       * @param resource
062       *          the resource the violation should be attached to
063       * @deprecated since 2.3. Use the factory method create()
064       */
065      @Deprecated
066      public Violation(Rule rule, Resource resource) {
067        this.resource = resource;
068        this.rule = rule;
069      }
070    
071      public Resource getResource() {
072        return resource;
073      }
074    
075      /**
076       * Sets the resource the violation applies to
077       * 
078       * @return the current object
079       */
080      public Violation setResource(Resource resource) {
081        this.resource = resource;
082        return this;
083      }
084    
085      public Rule getRule() {
086        return rule;
087      }
088    
089      /**
090       * Sets the rule violated
091       * 
092       * @return the current object
093       */
094      public Violation setRule(Rule rule) {
095        this.rule = rule;
096        return this;
097      }
098    
099      public String getMessage() {
100        return message;
101      }
102    
103      /**
104       * Sets the violation message
105       * 
106       * @return the current object
107       */
108      public Violation setMessage(String message) {
109        this.message = message;
110        return this;
111      }
112    
113      /**
114       * @return line number (numeration starts from 1), or <code>null</code> if violation doesn't belong to concrete line
115       * @see #hasLineId()
116       */
117      public Integer getLineId() {
118        return lineId;
119      }
120    
121      /**
122       * Sets the violation line.
123       * 
124       * @param lineId line number (numeration starts from 1), or <code>null</code> if violation doesn't belong to concrete line
125       * @return the current object
126       */
127      public Violation setLineId(Integer lineId) {
128        if (lineId != null && lineId < 1) {
129          // TODO this normalization was added in 2.8, throw exception in future versions - see http://jira.codehaus.org/browse/SONAR-2386
130          Logs.INFO.warn("line must not be less than 1 - in future versions this will cause IllegalArgumentException");
131          this.lineId = null;
132        } else {
133          this.lineId = lineId;
134        }
135        return this;
136      }
137    
138      /**
139       * @return <code>true<code> if violation belongs to concrete line
140       * @since 2.8
141       */
142      public boolean hasLineId() {
143        return lineId != null;
144      }
145    
146      /**
147       * @since 2.5
148       */
149      public RulePriority getSeverity() {
150        return severity;
151      }
152    
153      /**
154       * For internal use only.
155       * 
156       * @since 2.5
157       */
158      public Violation setSeverity(RulePriority severity) {
159        this.severity = severity;
160        return this;
161      }
162    
163      /**
164       * @deprecated since 2.5 use {@link #getSeverity()} instead. See http://jira.codehaus.org/browse/SONAR-1829
165       */
166      @Deprecated
167      public RulePriority getPriority() {
168        return severity;
169      }
170    
171      /**
172       * For internal use only
173       * 
174       * @deprecated since 2.5 use {@link #setSeverity(RulePriority)} instead. See http://jira.codehaus.org/browse/SONAR-1829
175       */
176      @Deprecated
177      public Violation setPriority(RulePriority priority) {
178        this.severity = priority;
179        return this;
180      }
181    
182      /**
183       * @see #setCost(Double)
184       * @since 2.4
185       */
186      public Double getCost() {
187        return cost;
188      }
189    
190      /**
191       * The cost to fix a violation can't be precisely computed without this information. Let's take the following example : a rule forbids to
192       * have methods whose complexity is greater than 10. Without this field "cost", the same violation is created with a method whose
193       * complexity is 15 and a method whose complexity is 100. If the cost to fix one point of complexity is 0.05h, then 15mn is necessary to
194       * fix the method whose complexity is 15, and 3h5mn is required to fix the method whose complexity is 100.
195       * 
196       * @since 2.4
197       */
198      public Violation setCost(Double d) {
199        if (d == null || d >= 0) {
200          this.cost = d;
201          return this;
202        } else {
203          throw new IllegalArgumentException("Cost to fix violation can't be negative or NaN");
204        }
205      }
206    
207      /**
208       * @since 2.5
209       */
210      public Date getCreatedAt() {
211        return createdAt;
212      }
213    
214      /**
215       * For internal use only
216       * 
217       * @since 2.5
218       */
219      public Violation setCreatedAt(Date createdAt) {
220        this.createdAt = createdAt;
221        return this;
222      }
223    
224      /**
225       * Switches off the current violation. This is a kind of "mute", which means the violation exists but won't be counted as an active
226       * violation (and thus, won't be counted in the total number of violations). It's usually used for false-positives.
227       *
228       * The extensions which call this method must be executed
229       * 
230       * @since 2.8
231       * @param b
232       *          if true, the violation is considered OFF
233       */
234      public Violation setSwitchedOff(boolean b) {
235        this.switchedOff = b;
236        return this;
237      }
238    
239      /**
240       * Tells whether this violation is ON or OFF.
241       * 
242       * @since 2.8
243       */
244      public boolean isSwitchedOff() {
245        return switchedOff;
246      }
247    
248      /**
249       * Checksum is available in decorators executed after the barrier {@link org.sonar.api.batch.DecoratorBarriers#END_OF_VIOLATION_TRACKING}
250       */
251      public String getChecksum() {
252        return checksum;
253      }
254    
255      /**
256       * For internal use only. Checksum is automatically set by Sonar. Plugins must not call this method.
257       */
258      public Violation setChecksum(String s) {
259        this.checksum = s;
260        return this;
261      }
262    
263      /**
264       * A violation is considered as "new" if it has been created after the reference analysis
265       * (the "previous" analysis).
266       * This method must be used only by post-jobs and decorators depending on the barrier
267       * {@link org.sonar.api.batch.DecoratorBarriers#END_OF_VIOLATION_TRACKING}
268       * @since 2.9
269       */
270      public boolean isNew() {
271        return isNew;
272      }
273    
274      /**
275       * For internal use only. MUST NOT BE SET FROM PLUGINS.
276       * @since 2.9
277       */
278      public Violation setNew(boolean b) {
279        isNew = b;
280        return this;
281      }
282    
283      @Override
284      public String toString() {
285        return ReflectionToStringBuilder.toString(this);
286      }
287    
288      public static Violation create(ActiveRule activeRule, Resource resource) {
289        return new Violation(activeRule.getRule()).setResource(resource);
290      }
291    
292      public static Violation create(Rule rule, Resource resource) {
293        return new Violation(rule).setResource(resource);
294      }
295    
296    }