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.builder.ReflectionToStringBuilder; 023import org.sonar.api.resources.Resource; 024import org.sonar.api.utils.Logs; 025 026import 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 */ 031public 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}