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