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.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
044 /**
045 * Creates of a violation from a rule. Will need to define the resource later on
046 *
047 * @deprecated since 2.3. Use the factory method create()
048 */
049 @Deprecated
050 public Violation(Rule rule) {
051 this.rule = rule;
052 }
053
054 /**
055 * Creates a fully qualified violation
056 *
057 * @param rule
058 * the rule that has been violated
059 * @param resource
060 * the resource the violation should be attached to
061 * @deprecated since 2.3. Use the factory method create()
062 */
063 @Deprecated
064 public Violation(Rule rule, Resource resource) {
065 this.resource = resource;
066 this.rule = rule;
067 }
068
069 public Resource getResource() {
070 return resource;
071 }
072
073 /**
074 * Sets the resource the violation applies to
075 *
076 * @return the current object
077 */
078 public Violation setResource(Resource resource) {
079 this.resource = resource;
080 return this;
081 }
082
083 public Rule getRule() {
084 return rule;
085 }
086
087 /**
088 * Sets the rule violated
089 *
090 * @return the current object
091 */
092 public Violation setRule(Rule rule) {
093 this.rule = rule;
094 return this;
095 }
096
097 public String getMessage() {
098 return message;
099 }
100
101 /**
102 * Sets the violation message
103 *
104 * @return the current object
105 */
106 public Violation setMessage(String message) {
107 this.message = message;
108 return this;
109 }
110
111 /**
112 * @return line number (numeration starts from 1), or <code>null</code> if violation doesn't belong to concrete line
113 * @see #hasLineId()
114 */
115 public Integer getLineId() {
116 return lineId;
117 }
118
119 /**
120 * Sets the violation line.
121 *
122 * @param lineId line number (numeration starts from 1), or <code>null</code> if violation doesn't belong to concrete line
123 * @return the current object
124 */
125 public Violation setLineId(Integer lineId) {
126 if (lineId != null && lineId < 1) {
127 // TODO this normalization was added in 2.8, throw exception in future versions - see http://jira.codehaus.org/browse/SONAR-2386
128 Logs.INFO.warn("line must not be less than 1 - in future versions this will cause IllegalArgumentException");
129 this.lineId = null;
130 } else {
131 this.lineId = lineId;
132 }
133 return this;
134 }
135
136 /**
137 * @return <code>true<code> if violation belongs to concrete line
138 * @since 2.8
139 */
140 public boolean hasLineId() {
141 return lineId != null;
142 }
143
144 /**
145 * @since 2.5
146 */
147 public RulePriority getSeverity() {
148 return severity;
149 }
150
151 /**
152 * For internal use only.
153 *
154 * @since 2.5
155 */
156 public Violation setSeverity(RulePriority severity) {
157 this.severity = severity;
158 return this;
159 }
160
161 /**
162 * @deprecated since 2.5 use {@link #getSeverity()} instead. See http://jira.codehaus.org/browse/SONAR-1829
163 */
164 @Deprecated
165 public RulePriority getPriority() {
166 return severity;
167 }
168
169 /**
170 * For internal use only
171 *
172 * @deprecated since 2.5 use {@link #setSeverity(RulePriority)} instead. See http://jira.codehaus.org/browse/SONAR-1829
173 */
174 @Deprecated
175 public Violation setPriority(RulePriority priority) {
176 this.severity = priority;
177 return this;
178 }
179
180 /**
181 * @see #setCost(Double)
182 * @since 2.4
183 */
184 public Double getCost() {
185 return cost;
186 }
187
188 /**
189 * The cost to fix a violation can't be precisely computed without this information. Let's take the following example : a rule forbids to
190 * have methods whose complexity is greater than 10. Without this field "cost", the same violation is created with a method whose
191 * 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
192 * fix the method whose complexity is 15, and 3h5mn is required to fix the method whose complexity is 100.
193 *
194 * @since 2.4
195 */
196 public Violation setCost(Double d) {
197 if (d == null || d >= 0) {
198 this.cost = d;
199 return this;
200 } else {
201 throw new IllegalArgumentException("Cost to fix violation can't be negative or NaN");
202 }
203 }
204
205 /**
206 * @since 2.5
207 */
208 public Date getCreatedAt() {
209 return createdAt;
210 }
211
212 /**
213 * For internal use only
214 *
215 * @since 2.5
216 */
217 public Violation setCreatedAt(Date createdAt) {
218 this.createdAt = createdAt;
219 return this;
220 }
221
222 /**
223 * Switches off the current violation. This is a kind of "mute", which means the violation exists but won't be counted as an active
224 * violation (and thus, won't be counted in the total number of violations). It's usually used for false-positives.
225 *
226 * The extensions which call this method must be executed
227 *
228 * @since 2.8
229 * @param b
230 * if true, the violation is considered OFF
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 * @since 2.9
267 */
268 public boolean isNew() {
269 return isNew;
270 }
271
272 /**
273 * For internal use only. MUST NOT BE SET FROM PLUGINS.
274 * @since 2.9
275 */
276 public Violation setNew(boolean b) {
277 isNew = b;
278 return this;
279 }
280
281 @Override
282 public String toString() {
283 return ReflectionToStringBuilder.toString(this);
284 }
285
286 public static Violation create(ActiveRule activeRule, Resource resource) {
287 return new Violation(activeRule.getRule()).setResource(resource);
288 }
289
290 public static Violation create(Rule rule, Resource resource) {
291 return new Violation(rule).setResource(resource);
292 }
293
294 }