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 }