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 */
020package org.sonar.api.measures;
021
022import com.google.common.annotations.Beta;
023import org.apache.commons.lang.builder.ReflectionToStringBuilder;
024import org.sonar.api.qualitymodel.Characteristic;
025
026import java.math.BigDecimal;
027import java.math.RoundingMode;
028import java.util.Date;
029
030/**
031 * A class to handle measures.
032 *
033 * @since 1.10
034 */
035public 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}