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