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