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    }