001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2009 SonarSource SA
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 /**
202 * @return the date of the measure, i.e. the date the measure was taken. Used only in TimeMachine queries
203 */
204 public Date getDate() {
205 return date;
206 }
207
208 /**
209 * Sets the date of the measure - Used only in TimeMachine queries
210 *
211 * @param date the date
212 * @return the measure object instance
213 */
214 public Measure setDate(Date date) {
215 this.date = date;
216 return this;
217 }
218
219 /**
220 * @return the value of the measure as a double
221 */
222 public Double getValue() {
223 return value;
224 }
225
226 /**
227 * @return the value of the measure as an int
228 */
229 public Integer getIntValue() {
230 if (value == null) {
231 return null;
232 }
233 return value.intValue();
234 }
235
236 /**
237 * Sets the measure value with the default precision of 1
238 *
239 * @param v the measure value
240 * @return the measure object instance
241 */
242 public Measure setValue(Double v) {
243 return setValue(v, DEFAULT_PRECISION);
244 }
245
246 /**
247 * Sets the measure value as an int
248 *
249 * @param i the value
250 * @return the measure object instance
251 */
252 public Measure setIntValue(Integer i) {
253 if (i == null) {
254 this.value = null;
255 } else {
256 this.value = Double.valueOf(i);
257 }
258 return this;
259 }
260
261 /**
262 * Sets the measure value with a given precision
263 *
264 * @param v the measure value
265 * @param precision the measure value precision
266 * @return the measure object instance
267 */
268 public Measure setValue(Double v, int precision) {
269 if (v != null) {
270 if (Double.isNaN(v)) {
271 throw new IllegalArgumentException("Measure value can not be NaN");
272 }
273 this.value = scaleValue(v, precision);
274 } else {
275 this.value = null;
276 }
277 return this;
278 }
279
280 private double scaleValue(double value, int scale) {
281 BigDecimal bd = BigDecimal.valueOf(value);
282 return bd.setScale(scale, RoundingMode.HALF_UP).doubleValue();
283 }
284
285 /**
286 * @return the data field of the measure
287 */
288 public String getData() {
289 return data;
290 }
291
292 /**
293 * Sets the data field of the measure.
294 *
295 * @param s the data
296 * @return the measure object instance
297 */
298 public Measure setData(String s) {
299 if (s != null && s.length() >= MAX_TEXT_SIZE && !metric.isDataType()) {
300 throw new IllegalArgumentException("Data is too long for non-data metric : size=" + s.length() + ", max=" + MAX_TEXT_SIZE);
301 }
302 this.data = s;
303 return this;
304 }
305
306 /**
307 * Sets an alert level as the data field
308 *
309 * @param level the alert level
310 * @return the measure object instance
311 */
312 public Measure setData(Metric.Level level) {
313 if (level == null) {
314 this.data = null;
315 } else {
316 this.data = level.toString();
317 }
318 return this;
319 }
320
321 /**
322 * @return the description of the measure
323 */
324 public String getDescription() {
325 return description;
326 }
327
328 /**
329 * Sets the measure description
330 *
331 * @param description the description
332 * @return the measure object instance
333 */
334 public Measure setDescription(String description) {
335 this.description = description;
336 return this;
337 }
338
339 /**
340 * @return the alert status of the measure
341 */
342 public Metric.Level getAlertStatus() {
343 return alertStatus;
344 }
345
346 /**
347 * Set the alert status of the measure
348 *
349 * @param status the status
350 * @return the measure object instance
351 */
352 public Measure setAlertStatus(Metric.Level status) {
353 this.alertStatus = status;
354 return this;
355 }
356
357 /**
358 * @return the text associated to the alert on the measure
359 */
360 public String getAlertText() {
361 return alertText;
362 }
363
364 /**
365 * Sets the text associated to the alert on the measure
366 *
367 * @param alertText the text
368 * @return the measure object instance
369 */
370 public Measure setAlertText(String alertText) {
371 this.alertText = alertText;
372 return this;
373 }
374
375 /**
376 * Gets the measure tendency
377 *
378 * @return the tendency
379 */
380 public Integer getTendency() {
381 return tendency;
382 }
383
384 /**
385 * Sets the tendency for the measure - Internal use only
386 *
387 * @param tendency the tendency
388 * @return the measure object instance
389 */
390 public Measure setTendency(Integer tendency) {
391 this.tendency = tendency;
392 return this;
393 }
394
395 /**
396 * @return the measure id - Internal use only
397 */
398 public Long getId() {
399 return id;
400 }
401
402 /**
403 * Sets the measure id - Internal use only
404 *
405 * @param id the id
406 * @return the measure object instance
407 */
408 public Measure setId(Long id) {
409 this.id = id;
410 return this;
411 }
412
413 /**
414 * @return the first variation value
415 * @since 2.5
416 */
417 public Double getVariation1() {
418 return variation1;
419 }
420
421 /**
422 * Internal use only
423 *
424 * @since 2.5
425 */
426 public Measure setVariation1(Double d) {
427 this.variation1 = d;
428 return this;
429 }
430
431 /**
432 * @return the second variation value
433 * @since 2.5
434 */
435 public Double getVariation2() {
436 return variation2;
437 }
438
439 /**
440 * Internal use only
441 *
442 * @since 2.5
443 */
444 public Measure setVariation2(Double d) {
445 this.variation2 = d;
446 return this;
447 }
448
449 /**
450 * @return the third variation value
451 * @since 2.5
452 */
453 public Double getVariation3() {
454 return variation3;
455 }
456
457 /**
458 * Internal use only
459 *
460 * @since 2.5
461 */
462 public Measure setVariation3(Double d) {
463 this.variation3 = d;
464 return this;
465 }
466
467 /**
468 * @return the third variation value
469 * @since 2.5
470 */
471 public Double getVariation4() {
472 return variation4;
473 }
474
475 /**
476 * Internal use only
477 *
478 * @since 2.5
479 */
480 public Measure setVariation4(Double d) {
481 this.variation4 = d;
482 return this;
483 }
484
485 /**
486 * @return the third variation value
487 * @since 2.5
488 */
489 public Double getVariation5() {
490 return variation5;
491 }
492
493 /**
494 * Internal use only
495 *
496 * @since 2.5
497 */
498 public Measure setVariation5(Double d) {
499 this.variation5 = d;
500 return this;
501 }
502
503 /**
504 * @since 2.5
505 */
506 public Double getVariation(int index) {
507 switch (index) {
508 case 1:
509 return variation1;
510 case 2:
511 return variation2;
512 case 3:
513 return variation3;
514 case 4:
515 return variation4;
516 case 5:
517 return variation5;
518 default:
519 throw new IndexOutOfBoundsException("Index should be in range from 1 to 5");
520 }
521 }
522
523 /**
524 * Internal use only
525 *
526 * @since 2.5
527 */
528 public Measure setVariation(int index, Double d) {
529 switch (index) {
530 case 1:
531 variation1 = d;
532 break;
533 case 2:
534 variation2 = d;
535 break;
536 case 3:
537 variation3 = d;
538 break;
539 case 4:
540 variation4 = d;
541 break;
542 case 5:
543 variation5 = d;
544 break;
545 default:
546 throw new IndexOutOfBoundsException("Index should be in range from 1 to 5");
547 }
548 return this;
549 }
550
551 /**
552 * @return the url of the measure
553 */
554 public String getUrl() {
555 return url;
556 }
557
558 /**
559 * Sets the URL of the measure
560 *
561 * @param url the url
562 * @return the measure object instance
563 */
564 public Measure setUrl(String url) {
565 this.url = url;
566 return this;
567 }
568
569 /**
570 * @since 2.3
571 */
572 public final Characteristic getCharacteristic() {
573 return characteristic;
574 }
575
576 /**
577 * @since 2.3
578 */
579 public final Measure setCharacteristic(Characteristic characteristic) {
580 this.characteristic = characteristic;
581 return this;
582 }
583
584 @Override
585 public boolean equals(Object o) {
586 if (this == o) {
587 return true;
588 }
589 if (!(o.getClass().equals(Measure.class))) {
590 return false;
591 }
592
593 Measure measure = (Measure) o;
594 if (metricKey != null ? !metricKey.equals(measure.metricKey) : measure.metricKey != null) {
595 return false;
596 }
597 if (characteristic != null ? !characteristic.equals(measure.characteristic) : measure.characteristic != null) {
598 return false;
599 }
600 return true;
601 }
602
603 @Override
604 public int hashCode() {
605 int result = metricKey != null ? metricKey.hashCode() : 0;
606 result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0);
607 return result;
608 }
609
610 @Override
611 public String toString() {
612 return ReflectionToStringBuilder.toString(this);
613 }
614 }