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