001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2009 SonarSource SA 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.measures; 021 022 import org.apache.commons.lang.builder.ToStringBuilder; 023 import org.sonar.api.qualitymodel.Characteristic; 024 025 import java.math.BigDecimal; 026 import java.math.RoundingMode; 027 import java.util.Date; 028 029 /** 030 * A class to handle measures. 031 * <p/> 032 * 033 * @since 1.10 034 */ 035 public class Measure { 036 protected static final int MAX_TEXT_SIZE = 96; 037 038 /** 039 * Default precision when saving a float type metric 040 */ 041 public final static int DEFAULT_PRECISION = 1; 042 043 private Long id; // for internal use 044 protected Metric metric; 045 protected Double value; 046 protected String data; 047 protected String description; 048 protected Metric.Level alertStatus; 049 protected String alertText; 050 protected Integer tendency; 051 protected Date date; 052 protected Double diff1, diff2, diff3; 053 protected String url; 054 protected Characteristic characteristic; 055 protected PersistenceMode persistenceMode = PersistenceMode.FULL; 056 057 /** 058 * Creates a measure with a metric 059 * 060 * @param metric the metric 061 */ 062 public Measure(Metric metric) { 063 this.metric = metric; 064 } 065 066 /** 067 * Creates a measure with a metric and a value 068 * 069 * @param metric the metric 070 * @param value its value 071 */ 072 public Measure(Metric metric, Double value) { 073 this.metric = metric; 074 setValue(value); 075 } 076 077 /** 078 * Creates a measure with a metric, a value and a precision for the value 079 * 080 * @param metric the metric 081 * @param value its value 082 * @param precision the value precision 083 */ 084 public Measure(Metric metric, Double value, int precision) { 085 this.metric = metric; 086 setValue(value, precision); 087 } 088 089 /** 090 * Creates a measure with a metric, a value and a data field 091 * 092 * @param metric the metric 093 * @param value the value 094 * @param data the data field 095 */ 096 public Measure(Metric metric, Double value, String data) { 097 this.metric = metric; 098 setValue(value); 099 setData(data); 100 } 101 102 /** 103 * * Creates a measure with a metric and a data field 104 * 105 * @param metric the metric 106 * @param data the data field 107 */ 108 public Measure(Metric metric, String data) { 109 this.metric = metric; 110 setData(data); 111 } 112 113 /** 114 * Creates a measure with a metric and an alert level 115 * 116 * @param metric the metric 117 * @param level the alert level 118 */ 119 public Measure(Metric metric, Metric.Level level) { 120 this.metric = metric; 121 if (level != null) { 122 this.data = level.toString(); 123 } 124 } 125 126 /** 127 * Creates an empty measure 128 */ 129 public Measure() { 130 } 131 132 /** 133 * Gets the persistence mode of the measure. Default persistence mode is FULL, 134 * except when instantiating the measure with a String parameter. 135 */ 136 public PersistenceMode getPersistenceMode() { 137 return persistenceMode; 138 } 139 140 /** 141 * <p>Sets the persistence mode of a measure.</p> 142 * <p><b>WARNING : </b>Being able to reuse measures saved in memory is only possible within the same tree. 143 * In a multi-module project for example, a measure save in memory at the module level will not be accessible by 144 * the root project. In that case, database should be used. 145 * </p> 146 * 147 * @param mode the mode 148 * @return the measure object instance 149 */ 150 public Measure setPersistenceMode(PersistenceMode mode) { 151 this.persistenceMode = mode; 152 return this; 153 } 154 155 /** 156 * @return return the measures underlying metric 157 */ 158 public Metric getMetric() { 159 return metric; 160 } 161 162 /** 163 * Set the underlying metric 164 * 165 * @param metric the metric 166 * @return the measure object instance 167 */ 168 public Measure setMetric(Metric metric) { 169 this.metric = metric; 170 return this; 171 } 172 173 /** 174 * @return transforms and returns the data fields as a level of alert 175 */ 176 public Metric.Level getDataAsLevel() { 177 if (data != null) { 178 return Metric.Level.valueOf(data); 179 } 180 return null; 181 } 182 183 /** 184 * @return the date of the measure, i.e. the date the measure was taken. Used only in TimeMachine queries 185 */ 186 public Date getDate() { 187 return date; 188 } 189 190 /** 191 * Sets the date of the measure - Used only in TimeMachine queries 192 * 193 * @param date the date 194 * @return the measure object instance 195 */ 196 public Measure setDate(Date date) { 197 this.date = date; 198 return this; 199 } 200 201 /** 202 * @return the value of the measure as a double 203 */ 204 public Double getValue() { 205 return value; 206 } 207 208 /** 209 * @return the value of the measure as an int 210 */ 211 public Integer getIntValue() { 212 if (value == null) { 213 return null; 214 } 215 return value.intValue(); 216 } 217 218 /** 219 * Sets the measure value with the default precision of 1 220 * 221 * @param v the measure value 222 * @return the measure object instance 223 */ 224 public Measure setValue(Double v) { 225 return setValue(v, DEFAULT_PRECISION); 226 } 227 228 /** 229 * Sets the measure value as an int 230 * 231 * @param i the value 232 * @return the measure object instance 233 */ 234 public Measure setIntValue(Integer i) { 235 if (i == null) { 236 this.value = null; 237 } else { 238 this.value = Double.valueOf(i); 239 } 240 return this; 241 } 242 243 /** 244 * Sets the measure value with a given precision 245 * 246 * @param v the measure value 247 * @param precision the measure value precision 248 * @return the measure object instance 249 */ 250 public Measure setValue(Double v, int precision) { 251 if (v != null) { 252 if (Double.isNaN(v)) { 253 throw new IllegalArgumentException("Measure value can not be NaN"); 254 } 255 this.value = scaleValue(v, precision); 256 } else { 257 this.value = null; 258 } 259 return this; 260 } 261 262 private double scaleValue(double value, int scale) { 263 BigDecimal bd = BigDecimal.valueOf(value); 264 return bd.setScale(scale, RoundingMode.HALF_UP).doubleValue(); 265 } 266 267 /** 268 * @return the data field of the measure 269 */ 270 public String getData() { 271 return data; 272 } 273 274 /** 275 * Sets the data field of the measure. 276 * 277 * @param s the data 278 * @return the measure object instance 279 */ 280 public Measure setData(String s) { 281 if (s != null && s.length() >= MAX_TEXT_SIZE && !metric.isDataType()) { 282 throw new IllegalArgumentException("Data is too long for non-data metric : size=" + s.length() + ", max=" + MAX_TEXT_SIZE); 283 } 284 this.data = s; 285 return this; 286 } 287 288 /** 289 * Sets an alert level as the data field 290 * 291 * @param level the alert level 292 * @return the measure object instance 293 */ 294 public Measure setData(Metric.Level level) { 295 if (level == null) { 296 this.data = null; 297 } else { 298 this.data = level.toString(); 299 } 300 return this; 301 } 302 303 /** 304 * @return the description of the measure 305 */ 306 public String getDescription() { 307 return description; 308 } 309 310 /** 311 * Sets the measure description 312 * 313 * @param description the description 314 * @return the measure object instance 315 */ 316 public Measure setDescription(String description) { 317 this.description = description; 318 return this; 319 } 320 321 /** 322 * @return the alert status of the measure 323 */ 324 public Metric.Level getAlertStatus() { 325 return alertStatus; 326 } 327 328 /** 329 * Set the alert status of the measure 330 * 331 * @param status the status 332 * @return the measure object instance 333 */ 334 public Measure setAlertStatus(Metric.Level status) { 335 this.alertStatus = status; 336 return this; 337 } 338 339 /** 340 * @return the text associated to the alert on the measure 341 */ 342 public String getAlertText() { 343 return alertText; 344 } 345 346 /** 347 * Sets the text associated to the alert on the measure 348 * 349 * @param alertText the text 350 * @return the measure object instance 351 */ 352 public Measure setAlertText(String alertText) { 353 this.alertText = alertText; 354 return this; 355 } 356 357 /** 358 * Gets the measure tendency 359 * 360 * @return the tendency 361 */ 362 public Integer getTendency() { 363 return tendency; 364 } 365 366 /** 367 * Sets the tendency for the measure 368 * 369 * @param tendency the tendency 370 * @return the measure object instance 371 */ 372 public Measure setTendency(Integer tendency) { 373 this.tendency = tendency; 374 return this; 375 } 376 377 /** 378 * @return the measure id - Internal use only 379 */ 380 public Long getId() { 381 return id; 382 } 383 384 /** 385 * Sets the measure id - Internal use only 386 * 387 * @param id the id 388 * @return the measure object instance 389 */ 390 public Measure setId(Long id) { 391 this.id = id; 392 return this; 393 } 394 395 /** 396 * @return the first differential value of the measure 397 */ 398 public Double getDiffValue1() { 399 return diff1; 400 } 401 402 /** 403 * Sets the first differential value of the measure 404 * 405 * @param diff1 the diff 406 * @return the measure object instance 407 */ 408 public Measure setDiffValue1(Double diff1) { 409 this.diff1 = diff1; 410 return this; 411 } 412 413 /** 414 * @return the second differential value of the measure 415 */ 416 public Double getDiffValue2() { 417 return diff2; 418 } 419 420 /** 421 * Sets the second differential value of the measure 422 * 423 * @param diff2 the diff 424 * @return the measure object instance 425 */ 426 public Measure setDiffValue2(Double diff2) { 427 this.diff2 = diff2; 428 return this; 429 } 430 431 /** 432 * @return the third differential value of the measure 433 */ 434 public Double getDiffValue3() { 435 return diff3; 436 } 437 438 /** 439 * Sets the third differential value of the measure 440 * 441 * @param diff3 the diff 442 * @return the measure object instance 443 */ 444 public Measure setDiffValue3(Double diff3) { 445 this.diff3 = diff3; 446 return this; 447 } 448 449 /** 450 * @return the url of the measure 451 */ 452 public String getUrl() { 453 return url; 454 } 455 456 /** 457 * Sets the URL of the measure 458 * 459 * @param url the url 460 * @return the measure object instance 461 */ 462 public Measure setUrl(String url) { 463 this.url = url; 464 return this; 465 } 466 467 public final Characteristic getCharacteristic() { 468 return characteristic; 469 } 470 471 public final Measure setCharacteristic(Characteristic characteristic) { 472 this.characteristic = characteristic; 473 return this; 474 } 475 476 477 // @Override 478 // public boolean equals(Object obj) { 479 // if (!(obj.getClass().equals(Measure.class))) { 480 // return false; 481 // } 482 // if (this == obj) { 483 // return true; 484 // } 485 // Measure rhs = (Measure) obj; 486 // return new EqualsBuilder() 487 // .append(metric, rhs.getMetric()) 488 // .append(characteristic, rhs.getCharacteristic()) 489 // .isEquals(); 490 // } 491 // 492 // @Override 493 // public int hashCode() { 494 // return (metric != null ? metric.hashCode() : 0); 495 // } 496 // 497 498 499 @Override 500 public boolean equals(Object o) { 501 if (this == o) { 502 return true; 503 } 504 if (!(o.getClass().equals(Measure.class))) { 505 return false; 506 } 507 508 Measure measure = (Measure) o; 509 if (metric != null ? !metric.equals(measure.metric) : measure.metric != null) { 510 return false; 511 } 512 if (characteristic != null ? !characteristic.equals(measure.characteristic) : measure.characteristic != null) { 513 return false; 514 } 515 return true; 516 } 517 518 @Override 519 public int hashCode() { 520 int result = metric != null ? metric.hashCode() : 0; 521 result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0); 522 return result; 523 } 524 525 @Override 526 public String toString() { 527 return new ToStringBuilder(this). 528 append("id", id). 529 append("metric", metric). 530 append("value", value). 531 append("data", data). 532 append("description", description). 533 append("alertStatus", alertStatus). 534 append("alertText", alertText). 535 append("tendency", tendency). 536 append("characteristic", characteristic). 537 append("diff1", diff1). 538 append("diff2", diff2). 539 append("diff3", diff3). 540 toString(); 541 } 542 543 public boolean hasOptionalData() { 544 return getAlertStatus() != null || 545 getAlertText() != null || 546 getDescription() != null || 547 getDiffValue1() != null || 548 getDiffValue2() != null || 549 getDiffValue3() != null || 550 getData() != null || 551 getTendency() != null || 552 getUrl() != null; 553 } 554 }