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