]> source.dussan.org Git - sonarqube.git/blob
e8d534d3ff36adf4095d74f0f18879b143c1ba75
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2019 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.ce.task.projectanalysis.measure;
21
22 import java.math.BigDecimal;
23 import java.math.RoundingMode;
24 import java.util.Locale;
25 import java.util.Objects;
26 import java.util.Optional;
27 import javax.annotation.CheckForNull;
28 import javax.annotation.Nullable;
29 import org.sonar.ce.task.projectanalysis.component.Developer;
30
31 import static com.google.common.base.Preconditions.checkArgument;
32 import static com.google.common.base.Preconditions.checkState;
33 import static java.util.Objects.requireNonNull;
34
35 public final class Measure {
36
37   public enum ValueType {
38     NO_VALUE, BOOLEAN, INT, LONG, DOUBLE, STRING, LEVEL
39   }
40
41   public enum Level {
42     OK("Green"),
43     WARN("Orange"),
44     ERROR("Red");
45
46     private final String colorName;
47
48     Level(String colorName) {
49       this.colorName = colorName;
50     }
51
52     public String getColorName() {
53       return colorName;
54     }
55
56     public static Optional<Level> toLevel(@Nullable String level) {
57       if (level == null) {
58         return Optional.empty();
59       }
60
61       try {
62         return Optional.of(Level.valueOf(level));
63       } catch (IllegalArgumentException e) {
64         return Optional.empty();
65       }
66     }
67   }
68
69   private final ValueType valueType;
70   @CheckForNull
71   private final Developer developer;
72   @CheckForNull
73   private final Double value;
74   @CheckForNull
75   private final String data;
76   @CheckForNull
77   private final Level dataLevel;
78   @CheckForNull
79   private final QualityGateStatus qualityGateStatus;
80   @CheckForNull
81   private final Double variation;
82
83   private Measure(ValueType valueType, @Nullable Developer developer,
84     @Nullable Double value, @Nullable String data, @Nullable Level dataLevel,
85     @Nullable QualityGateStatus qualityGateStatus, @Nullable Double variation) {
86     this.valueType = valueType;
87     this.developer = developer;
88     this.value = value;
89     this.data = data;
90     this.dataLevel = dataLevel;
91     this.qualityGateStatus = qualityGateStatus;
92     this.variation = variation;
93   }
94
95   public static NewMeasureBuilder newMeasureBuilder() {
96     return new NewMeasureBuilder();
97   }
98
99   public static UpdateMeasureBuilder updatedMeasureBuilder(Measure measure) {
100     return new UpdateMeasureBuilder(measure);
101   }
102
103   public static final class NewMeasureBuilder {
104     private Developer developer;
105     private QualityGateStatus qualityGateStatus;
106     private Double variation;
107
108     /**
109      * Sets the developer this measure is associated to.
110      *
111      */
112     public NewMeasureBuilder forDeveloper(Developer developer) {
113       this.developer = developer;
114       return this;
115     }
116
117     public NewMeasureBuilder setQualityGateStatus(QualityGateStatus qualityGateStatus) {
118       this.qualityGateStatus = requireNonNull(qualityGateStatus, "QualityGateStatus can not be set to null");
119       return this;
120     }
121
122     public NewMeasureBuilder setVariation(double variation) {
123       this.variation = variation;
124       return this;
125     }
126
127     public Measure create(boolean value, @Nullable String data) {
128       return new Measure(ValueType.BOOLEAN, developer, value ? 1.0d : 0.0d, data, null, qualityGateStatus, variation);
129     }
130
131     public Measure create(boolean value) {
132       return create(value, null);
133     }
134
135     public Measure create(int value, @Nullable String data) {
136       return new Measure(ValueType.INT, developer, (double) value, data, null, qualityGateStatus, variation);
137     }
138
139     public Measure create(int value) {
140       return create(value, null);
141     }
142
143     public Measure create(long value, @Nullable String data) {
144       return new Measure(ValueType.LONG, developer, (double) value, data, null, qualityGateStatus, variation);
145     }
146
147     public Measure create(long value) {
148       return create(value, null);
149     }
150
151     public Measure create(double value, int decimalScale, @Nullable String data) {
152       checkArgument(!Double.isNaN(value), "NaN is not allowed as a Measure value");
153       double scaledValue = scale(value, decimalScale);
154       return new Measure(ValueType.DOUBLE, developer, scaledValue, data, null, qualityGateStatus, variation);
155     }
156
157     public Measure create(double value, int decimalScale) {
158       return create(value, decimalScale, null);
159     }
160
161     public Measure create(String value) {
162       return new Measure(ValueType.STRING, developer, null, requireNonNull(value), null, qualityGateStatus, variation);
163     }
164
165     public Measure create(Level level) {
166       return new Measure(ValueType.LEVEL, developer, null, null, requireNonNull(level), qualityGateStatus, variation);
167     }
168
169     public Measure createNoValue() {
170       return new Measure(ValueType.NO_VALUE, developer, null, null, null, qualityGateStatus, variation);
171     }
172
173     private static double scale(double value, int decimalScale) {
174       BigDecimal bd = BigDecimal.valueOf(value);
175       return bd.setScale(decimalScale, RoundingMode.HALF_UP).doubleValue();
176     }
177   }
178
179   public static final class UpdateMeasureBuilder {
180     private final Measure source;
181     private QualityGateStatus qualityGateStatus;
182     private Double variation;
183
184     public UpdateMeasureBuilder(Measure source) {
185       this.source = requireNonNull(source, "Can not create a measure from null");
186     }
187
188     /**
189      * Sets the QualityGateStatus of the updated Measure to create.
190      *
191      * @throws NullPointerException if the specified {@link QualityGateStatus} is {@code null}
192      * @throws UnsupportedOperationException if the source measure already has a {@link QualityGateStatus}
193      */
194     public UpdateMeasureBuilder setQualityGateStatus(QualityGateStatus qualityGateStatus) {
195       if (source.qualityGateStatus != null) {
196         throw new UnsupportedOperationException("QualityGate status can not be changed if already set on source Measure");
197       }
198       this.qualityGateStatus = requireNonNull(qualityGateStatus, "QualityGateStatus can not be set to null");
199       return this;
200     }
201
202     /**
203      * Sets the variation of the updated Measure to create.
204      *
205      * @throws UnsupportedOperationException if the source measure already has a variation
206      */
207     public UpdateMeasureBuilder setVariation(double variation) {
208       if (source.variation != null) {
209         throw new UnsupportedOperationException("Variation can not be changed if already set on source Measure");
210       }
211       this.variation = variation;
212       return this;
213     }
214
215     public Measure create() {
216       return new Measure(source.valueType, source.developer,
217         source.value, source.data, source.dataLevel,
218         source.qualityGateStatus == null ? qualityGateStatus : source.qualityGateStatus,
219         source.variation == null ? variation : source.variation);
220     }
221   }
222
223   @CheckForNull
224   public Developer getDeveloper() {
225     return developer;
226   }
227
228   /**
229    * The type of value stored in the measure.
230    */
231   public ValueType getValueType() {
232     return valueType;
233   }
234
235   /**
236    * The value of this measure as a boolean if the type is {@link Measure.ValueType#BOOLEAN}.
237    *
238    * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#BOOLEAN}
239    */
240   public boolean getBooleanValue() {
241     checkValueType(ValueType.BOOLEAN);
242     return value == 1.0d;
243   }
244
245   /**
246    * The value of this measure as a int if the type is {@link Measure.ValueType#INT}.
247    *
248    * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#INT}
249    */
250   public int getIntValue() {
251     checkValueType(ValueType.INT);
252     return value.intValue();
253   }
254
255   /**
256    * The value of this measure as a long if the type is {@link Measure.ValueType#LONG}.
257    *
258    * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LONG}
259    */
260   public long getLongValue() {
261     checkValueType(ValueType.LONG);
262     return value.longValue();
263   }
264
265   /**
266    * The value of this measure as a double if the type is {@link Measure.ValueType#DOUBLE}.
267    *
268    * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#DOUBLE}
269    */
270   public double getDoubleValue() {
271     checkValueType(ValueType.DOUBLE);
272     return value;
273   }
274
275   /**
276    * The value of this measure as a String if the type is {@link Measure.ValueType#STRING}.
277    *
278    * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#STRING}
279    */
280   public String getStringValue() {
281     checkValueType(ValueType.STRING);
282     return data;
283   }
284
285   /**
286    * The value of this measure as a Level if the type is {@link Measure.ValueType#LEVEL}.
287    *
288    * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LEVEL}
289    */
290   public Level getLevelValue() {
291     checkValueType(ValueType.LEVEL);
292     return dataLevel;
293   }
294
295   /**
296    * The data of this measure if it exists.
297    * <p>
298    * If the measure type is {@link Measure.ValueType#STRING}, the value returned by this function is the same as {@link #getStringValue()}.
299    * </p>
300    */
301   public String getData() {
302     return data;
303   }
304
305   private void checkValueType(ValueType expected) {
306     if (valueType != expected) {
307       throw new IllegalStateException(
308         String.format(
309           "value can not be converted to %s because current value type is a %s",
310           expected.toString().toLowerCase(Locale.US),
311           valueType));
312     }
313   }
314
315   /**
316    * Any Measure, which ever is its value type, can have a QualityGate status.
317    */
318   public boolean hasQualityGateStatus() {
319     return this.qualityGateStatus != null;
320   }
321
322   /**
323    * The QualityGate status for this measure.
324    * <strong>Don't call this method unless you've checked the result of {@link #hasQualityGateStatus()} first</strong>
325    *
326    * @throws IllegalStateException if the measure has no QualityGate status
327    */
328   public QualityGateStatus getQualityGateStatus() {
329     checkState(qualityGateStatus != null, "Measure does not have an QualityGate status");
330     return this.qualityGateStatus;
331   }
332
333   /**
334    * Any Measure, which ever is its value type, can have a variation.
335    */
336   public boolean hasVariation() {
337     return variation != null;
338   }
339
340   /**
341    * The variation of this measure.
342    *
343    * @throws IllegalStateException if the measure has no variation
344    */
345   public double getVariation() {
346     checkState(variation != null, "Measure does not have variation");
347     return variation;
348   }
349
350   /**
351    * a Metric is equal to another Metric if it has the same ruleId/characteristicId paar (both being potentially
352    * {@code null} but only one of them can be non {@code null}).
353    */
354   @Override
355   public boolean equals(@Nullable Object o) {
356     if (this == o) {
357       return true;
358     }
359     if (o == null || getClass() != o.getClass()) {
360       return false;
361     }
362     Measure measure = (Measure) o;
363     return Objects.equals(developer, measure.developer);
364   }
365
366   @Override
367   public int hashCode() {
368     return Objects.hash(developer);
369   }
370
371   @Override
372   public String toString() {
373     return com.google.common.base.MoreObjects.toStringHelper(this)
374       .add("valueType", valueType)
375       .add("developer", developer)
376       .add("value", value)
377       .add("data", data)
378       .add("dataLevel", dataLevel)
379       .add("qualityGateStatus", qualityGateStatus)
380       .add("variations", variation)
381       .toString();
382   }
383
384 }