001/* 002 * SonarQube 003 * Copyright (C) 2009-2017 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program 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 * This program 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 License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.measures; 021 022import com.google.common.annotations.Beta; 023import java.io.Serializable; 024import java.util.Date; 025import javax.annotation.CheckForNull; 026import javax.annotation.Nullable; 027import org.apache.commons.lang.builder.ReflectionToStringBuilder; 028import org.apache.commons.lang.math.NumberUtils; 029import org.sonar.api.batch.sensor.SensorContext; 030 031/** 032 * A class to handle measures. 033 * 034 * @since 1.10 035 * @deprecated since 5.6. To create a new measure on scanner side use {@link SensorContext#newMeasure()} 036 */ 037@Deprecated 038public class Measure<G extends Serializable> implements Serializable { 039 private static final String INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5 = "Index should be in range from 1 to 5"; 040 041 protected static final int MAX_TEXT_SIZE = 96; 042 043 /** 044 * Default precision when saving a float type metric 045 * @deprecated in 5.3. Decimal scale is provided by metric, not by measure. 046 */ 047 @Deprecated 048 public static final int DEFAULT_PRECISION = 1; 049 050 protected String metricKey; 051 protected Metric<G> metric; 052 protected Double value; 053 protected String data; 054 protected String description; 055 protected Metric.Level alertStatus; 056 protected String alertText; 057 protected Date date; 058 protected Double variation1; 059 protected Double variation2; 060 protected Double variation3; 061 protected Double variation4; 062 protected Double variation5; 063 protected String url; 064 protected Integer personId; 065 protected PersistenceMode persistenceMode = PersistenceMode.FULL; 066 067 public Measure(String metricKey) { 068 this.metricKey = metricKey; 069 } 070 071 /** 072 * Creates a measure with a metric 073 * 074 * @param metric the metric 075 */ 076 public Measure(Metric metric) { 077 this.metric = metric; 078 this.metricKey = metric.getKey(); 079 } 080 081 /** 082 * Creates a measure with a metric and a value 083 * 084 * @param metric the metric 085 * @param value its value 086 */ 087 public Measure(Metric metric, Double value) { 088 this.metric = metric; 089 this.metricKey = metric.getKey(); 090 setValue(value); 091 } 092 093 /** 094 * Creates a measure with a metric, a value and a precision for the value 095 * 096 * @param metric the metric 097 * @param value its value 098 * @param precision the value precision 099 */ 100 public Measure(Metric metric, Double value, int precision) { 101 this.metric = metric; 102 this.metricKey = metric.getKey(); 103 setValue(value, precision); 104 } 105 106 /** 107 * Creates a measure with a metric, a value and a data field 108 * 109 * @param metric the metric 110 * @param value the value 111 * @param data the data field 112 */ 113 public Measure(Metric metric, Double value, String data) { 114 this.metric = metric; 115 this.metricKey = metric.getKey(); 116 setValue(value); 117 setData(data); 118 } 119 120 /** 121 * * Creates a measure with a metric and a data field 122 * 123 * @param metric the metric 124 * @param data the data field 125 */ 126 public Measure(Metric metric, String data) { 127 this.metric = metric; 128 this.metricKey = metric.getKey(); 129 setData(data); 130 } 131 132 /** 133 * Creates a measure with a metric and an alert level 134 * 135 * @param metric the metric 136 * @param level the alert level 137 */ 138 public Measure(Metric metric, @Nullable Metric.Level level) { 139 this.metric = metric; 140 this.metricKey = metric.getKey(); 141 if (level != null) { 142 this.data = level.toString(); 143 } 144 } 145 146 /** 147 * Creates an empty measure 148 */ 149 public Measure() { 150 } 151 152 /** 153 * Gets the persistence mode of the measure. Default persistence mode is FULL, except when instantiating the measure with a String 154 * parameter. 155 */ 156 public PersistenceMode getPersistenceMode() { 157 return persistenceMode; 158 } 159 160 /** 161 * <p> 162 * Sets the persistence mode of a measure. 163 * 164 * <p> 165 * <b>WARNING : </b>Being able to reuse measures saved in memory is only possible within the same tree. In a multi-module project for 166 * example, a measure save in memory at the module level will not be accessible by the root project. In that case, database should be 167 * used. 168 * 169 * 170 * @param mode the mode 171 * @return the measure object instance 172 */ 173 public Measure<G> setPersistenceMode(@Nullable PersistenceMode mode) { 174 if (mode == null) { 175 this.persistenceMode = PersistenceMode.FULL; 176 } else { 177 this.persistenceMode = mode; 178 } 179 return this; 180 } 181 182 /** 183 * @return return the measures underlying metric 184 */ 185 public Metric<G> getMetric() { 186 return metric; 187 } 188 189 public String getMetricKey() { 190 return metricKey; 191 } 192 193 /** 194 * Set the underlying metric 195 * 196 * @param metric the metric 197 * @return the measure object instance 198 */ 199 public Measure<G> setMetric(Metric<G> metric) { 200 this.metric = metric; 201 this.metricKey = metric.getKey(); 202 return this; 203 } 204 205 /** 206 * @return transforms and returns the data fields as a level of alert 207 */ 208 public Metric.Level getDataAsLevel() { 209 if (data != null) { 210 return Metric.Level.valueOf(data); 211 } 212 return null; 213 } 214 215 public boolean hasData() { 216 return data != null; 217 } 218 219 /** 220 * @return the date of the measure, i.e. the date the measure was taken. Used only in TimeMachine queries 221 */ 222 public Date getDate() { 223 return date; 224 } 225 226 /** 227 * Sets the date of the measure - Used only in TimeMachine queries 228 * 229 * @param date the date 230 * @return the measure object instance 231 */ 232 public Measure<G> setDate(Date date) { 233 this.date = date; 234 return this; 235 } 236 237 /** 238 * @return the value of the measure as a double 239 */ 240 @CheckForNull 241 public Double getValue() { 242 return value; 243 } 244 245 /** 246 * For internal use. 247 */ 248 public G value() { 249 if (value == null) { 250 return null; 251 } 252 switch (getMetric().getType()) { 253 case BOOL: 254 return (G) Boolean.valueOf(Double.doubleToRawLongBits(value) != 0L); 255 case INT: 256 case MILLISEC: 257 case RATING: 258 return (G) Integer.valueOf(value.intValue()); 259 case FLOAT: 260 case PERCENT: 261 case STRING: 262 case LEVEL: 263 case DATA: 264 case DISTRIB: 265 return (G) data; 266 case WORK_DUR: 267 return (G) Long.valueOf(value.longValue()); 268 default: 269 if (getMetric().isNumericType() || getMetric().isDataType()) { 270 return (G) value; 271 } 272 throw new UnsupportedOperationException("Unsupported type :" + getMetric().getType()); 273 } 274 } 275 276 /** 277 * @return the value of the measure as an int 278 */ 279 public Integer getIntValue() { 280 if (value == null) { 281 return null; 282 } 283 return value.intValue(); 284 } 285 286 /** 287 * Sets the measure value with the default precision of 1 288 * 289 * @param v the measure value 290 * @return the measure object instance 291 */ 292 public Measure<G> setValue(@Nullable Double v) { 293 return setValue(v, DEFAULT_PRECISION); 294 } 295 296 /** 297 * For internal use 298 */ 299 public Measure<G> setRawValue(@Nullable Double v) { 300 this.value = v; 301 return this; 302 } 303 304 /** 305 * Sets the measure value as an int 306 * 307 * @param i the value 308 * @return the measure object instance 309 */ 310 public Measure<G> setIntValue(@Nullable Integer i) { 311 if (i == null) { 312 this.value = null; 313 } else { 314 this.value = Double.valueOf(i); 315 } 316 return this; 317 } 318 319 /** 320 * Sets the measure value with a given precision 321 * 322 * @return {@code this} 323 * @deprecated in 5.3. The decimal scale is given by the metric, not by the measure. Anyway this parameter was enforced to 1 before version 5.3. 324 */ 325 @Deprecated 326 public Measure<G> setValue(@Nullable Double v, int decimalScale) { 327 if (v != null) { 328 if (Double.isNaN(v)) { 329 throw new IllegalArgumentException("Measure value can not be NaN"); 330 } 331 this.value = v; 332 } else { 333 this.value = null; 334 } 335 return this; 336 } 337 338 /** 339 * @return the data field of the measure 340 */ 341 @CheckForNull 342 public String getData() { 343 return data; 344 } 345 346 /** 347 * Sets the data field of the measure. 348 * 349 * @param s the data 350 * @return the measure object instance 351 */ 352 public Measure<G> setData(String s) { 353 this.data = s; 354 return this; 355 } 356 357 /** 358 * Sets an alert level as the data field 359 * 360 * @param level the alert level 361 * @return the measure object instance 362 */ 363 public Measure<G> setData(@Nullable Metric.Level level) { 364 if (level == null) { 365 this.data = null; 366 } else { 367 this.data = level.toString(); 368 } 369 return this; 370 } 371 372 /** 373 * @since 2.7 374 */ 375 public Measure<G> unsetData() { 376 this.data = null; 377 return this; 378 } 379 380 /** 381 * @return the description of the measure 382 */ 383 public String getDescription() { 384 return description; 385 } 386 387 /** 388 * Sets the measure description 389 * 390 * @param description the description 391 * @return the measure object instance 392 */ 393 public Measure<G> setDescription(String description) { 394 this.description = description; 395 return this; 396 } 397 398 /** 399 * @return the alert status of the measure 400 */ 401 public Metric.Level getAlertStatus() { 402 return alertStatus; 403 } 404 405 /** 406 * Set the alert status of the measure 407 * 408 * @param status the status 409 * @return the measure object instance 410 */ 411 public Measure<G> setAlertStatus(@Nullable Metric.Level status) { 412 this.alertStatus = status; 413 return this; 414 } 415 416 /** 417 * @return the text associated to the alert on the measure 418 */ 419 public String getAlertText() { 420 return alertText; 421 } 422 423 /** 424 * Sets the text associated to the alert on the measure 425 * 426 * @param alertText the text 427 * @return the measure object instance 428 */ 429 public Measure<G> setAlertText(@Nullable String alertText) { 430 this.alertText = alertText; 431 return this; 432 } 433 434 /** 435 * Concept of measure trend is dropped. 436 * @deprecated since 5.2. See https://jira.sonarsource.com/browse/SONAR-6392 437 * @return {@code null} since version 5.2 438 */ 439 @Deprecated 440 @CheckForNull 441 public Integer getTendency() { 442 return null; 443 } 444 445 /** 446 * Concept of measure trend is dropped. This method does nothing. 447 * @deprecated since 5.2. See https://jira.sonarsource.com/browse/SONAR-6392 448 * @return the measure object instance 449 */ 450 @Deprecated 451 public Measure<G> setTendency(@Nullable Integer tendency) { 452 return this; 453 } 454 455 /** 456 * @return the first variation value 457 * @since 2.5 458 */ 459 public Double getVariation1() { 460 return variation1; 461 } 462 463 /** 464 * Internal use only 465 * 466 * @since 2.5 467 */ 468 public Measure<G> setVariation1(@Nullable Double d) { 469 this.variation1 = d; 470 return this; 471 } 472 473 /** 474 * @return the second variation value 475 * @since 2.5 476 */ 477 public Double getVariation2() { 478 return variation2; 479 } 480 481 /** 482 * Internal use only 483 * 484 * @since 2.5 485 */ 486 public Measure<G> setVariation2(@Nullable Double d) { 487 this.variation2 = d; 488 return this; 489 } 490 491 /** 492 * @return the third variation value 493 * @since 2.5 494 */ 495 public Double getVariation3() { 496 return variation3; 497 } 498 499 /** 500 * Internal use only 501 * 502 * @since 2.5 503 */ 504 public Measure<G> setVariation3(@Nullable Double d) { 505 this.variation3 = d; 506 return this; 507 } 508 509 /** 510 * @return the third variation value 511 * @since 2.5 512 */ 513 public Double getVariation4() { 514 return variation4; 515 } 516 517 /** 518 * Internal use only 519 * 520 * @since 2.5 521 */ 522 public Measure<G> setVariation4(@Nullable Double d) { 523 this.variation4 = d; 524 return this; 525 } 526 527 /** 528 * @return the third variation value 529 * @since 2.5 530 */ 531 public Double getVariation5() { 532 return variation5; 533 } 534 535 /** 536 * Internal use only 537 * 538 * @since 2.5 539 */ 540 public Measure<G> setVariation5(@Nullable Double d) { 541 this.variation5 = d; 542 return this; 543 } 544 545 /** 546 * @since 2.5 547 */ 548 public Double getVariation(int index) { 549 switch (index) { 550 case 1: 551 return variation1; 552 case 2: 553 return variation2; 554 case 3: 555 return variation3; 556 case 4: 557 return variation4; 558 case 5: 559 return variation5; 560 default: 561 throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5); 562 } 563 } 564 565 /** 566 * Internal use only 567 * 568 * @since 2.5 569 */ 570 public Measure<G> setVariation(int index, Double d) { 571 switch (index) { 572 case 1: 573 variation1 = d; 574 break; 575 case 2: 576 variation2 = d; 577 break; 578 case 3: 579 variation3 = d; 580 break; 581 case 4: 582 variation4 = d; 583 break; 584 case 5: 585 variation5 = d; 586 break; 587 default: 588 throw new IndexOutOfBoundsException(INDEX_SHOULD_BE_IN_RANGE_FROM_1_TO_5); 589 } 590 return this; 591 } 592 593 /** 594 * @return the url of the measure 595 */ 596 public String getUrl() { 597 return url; 598 } 599 600 /** 601 * Sets the URL of the measure 602 * 603 * @param url the url 604 * @return the measure object instance 605 */ 606 public Measure<G> setUrl(String url) { 607 this.url = url; 608 return this; 609 } 610 611 /** 612 * @since 2.14 613 */ 614 @CheckForNull 615 @Beta 616 public Integer getPersonId() { 617 return personId; 618 } 619 620 /** 621 * @since 2.14 622 */ 623 @Beta 624 public Measure<G> setPersonId(@Nullable Integer i) { 625 this.personId = i; 626 return this; 627 } 628 629 /** 630 * @since 3.2 631 */ 632 public boolean isBestValue() { 633 Double bestValue = metric.getBestValue(); 634 return metric.isOptimizedBestValue() == Boolean.TRUE 635 && bestValue != null 636 && (value == null || NumberUtils.compare(bestValue, value) == 0) 637 && allNull(alertStatus, description, url, data) 638 && isZeroVariation(variation1, variation2, variation3, variation4, variation5); 639 } 640 641 private static boolean isZeroVariation(Double... variations) { 642 for (Double variation : variations) { 643 if (variation != null && NumberUtils.compare(variation, 0.0) != 0) { 644 return false; 645 } 646 } 647 return true; 648 } 649 650 private static boolean allNull(Object... values) { 651 for (Object value : values) { 652 if (null != value) { 653 return false; 654 } 655 } 656 return true; 657 } 658 659 @Override 660 public boolean equals(Object o) { 661 if (this == o) { 662 return true; 663 } 664 if (o == null || getClass() != o.getClass()) { 665 return false; 666 } 667 668 Measure measure = (Measure) o; 669 if (metricKey != null ? !metricKey.equals(measure.metricKey) : (measure.metricKey != null)) { 670 return false; 671 } 672 return !(personId != null ? !personId.equals(measure.personId) : (measure.personId != null)); 673 } 674 675 @Override 676 public int hashCode() { 677 int result = metricKey != null ? metricKey.hashCode() : 0; 678 result = 31 * result + (personId != null ? personId.hashCode() : 0); 679 return result; 680 } 681 682 @Override 683 public String toString() { 684 return ReflectionToStringBuilder.toString(this); 685 } 686 687}