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