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 == null || getClass() != o.getClass()) {
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    }