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