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 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 * @return true if the violation has been switched off 242 */ 243 public boolean isSwitchedOff() { 244 return switchedOff; 245 } 246 247 @Override 248 public boolean equals(Object obj) { 249 if (!(obj instanceof Violation)) { 250 return false; 251 } 252 if (this == obj) { 253 return true; 254 } 255 Violation other = (Violation) obj; 256 return new EqualsBuilder().append(rule, other.getRule()).append(resource, other.getResource()).isEquals(); 257 } 258 259 @Override 260 public int hashCode() { 261 return new HashCodeBuilder(17, 37).append(getRule()).append(getResource()).toHashCode(); 262 } 263 264 @Override 265 public String toString() { 266 return ReflectionToStringBuilder.toString(this); 267 } 268 269 public static Violation create(ActiveRule activeRule, Resource resource) { 270 return new Violation(activeRule.getRule()).setResource(resource); 271 } 272 273 public static Violation create(Rule rule, Resource resource) { 274 return new Violation(rule).setResource(resource); 275 } 276 277 }