You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Measure.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. import java.math.BigDecimal;
  22. import java.math.RoundingMode;
  23. import java.util.Locale;
  24. import java.util.Optional;
  25. import javax.annotation.CheckForNull;
  26. import javax.annotation.Nullable;
  27. import static com.google.common.base.Preconditions.checkArgument;
  28. import static com.google.common.base.Preconditions.checkState;
  29. import static java.util.Objects.requireNonNull;
  30. public final class Measure {
  31. public enum ValueType {
  32. NO_VALUE, BOOLEAN, INT, LONG, DOUBLE, STRING, LEVEL
  33. }
  34. public enum Level {
  35. OK("Green"),
  36. ERROR("Red"),
  37. /**
  38. * @deprecated since 7.6, warning quality gates doesn't exist anymore on new analysis
  39. */
  40. @Deprecated
  41. WARN("Orange");
  42. private final String colorName;
  43. Level(String colorName) {
  44. this.colorName = colorName;
  45. }
  46. public String getColorName() {
  47. return colorName;
  48. }
  49. public static Optional<Level> toLevel(@Nullable String level) {
  50. if (level == null) {
  51. return Optional.empty();
  52. }
  53. try {
  54. return Optional.of(Level.valueOf(level));
  55. } catch (IllegalArgumentException e) {
  56. return Optional.empty();
  57. }
  58. }
  59. }
  60. private final ValueType valueType;
  61. @CheckForNull
  62. private final Double value;
  63. @CheckForNull
  64. private final String data;
  65. @CheckForNull
  66. private final Level dataLevel;
  67. @CheckForNull
  68. private final QualityGateStatus qualityGateStatus;
  69. @CheckForNull
  70. private final Double variation;
  71. private Measure(ValueType valueType,
  72. @Nullable Double value, @Nullable String data, @Nullable Level dataLevel,
  73. @Nullable QualityGateStatus qualityGateStatus, @Nullable Double variation) {
  74. this.valueType = valueType;
  75. this.value = value;
  76. this.data = data;
  77. this.dataLevel = dataLevel;
  78. this.qualityGateStatus = qualityGateStatus;
  79. this.variation = variation;
  80. }
  81. public static NewMeasureBuilder newMeasureBuilder() {
  82. return new NewMeasureBuilder();
  83. }
  84. public static UpdateMeasureBuilder updatedMeasureBuilder(Measure measure) {
  85. return new UpdateMeasureBuilder(measure);
  86. }
  87. public static final class NewMeasureBuilder {
  88. private QualityGateStatus qualityGateStatus;
  89. private Double variation;
  90. public NewMeasureBuilder setQualityGateStatus(QualityGateStatus qualityGateStatus) {
  91. this.qualityGateStatus = requireNonNull(qualityGateStatus, "QualityGateStatus can not be set to null");
  92. return this;
  93. }
  94. public NewMeasureBuilder setVariation(double variation) {
  95. this.variation = variation;
  96. return this;
  97. }
  98. public Measure create(boolean value, @Nullable String data) {
  99. return new Measure(ValueType.BOOLEAN, value ? 1.0D : 0.0D, data, null, qualityGateStatus, variation);
  100. }
  101. public Measure create(boolean value) {
  102. return create(value, null);
  103. }
  104. public Measure create(int value, @Nullable String data) {
  105. return new Measure(ValueType.INT, (double) value, data, null, qualityGateStatus, variation);
  106. }
  107. public Measure create(int value) {
  108. return create(value, null);
  109. }
  110. public Measure create(long value, @Nullable String data) {
  111. return new Measure(ValueType.LONG, (double) value, data, null, qualityGateStatus, variation);
  112. }
  113. public Measure create(long value) {
  114. return create(value, null);
  115. }
  116. public Measure create(double value, int decimalScale, @Nullable String data) {
  117. checkArgument(!Double.isNaN(value), "NaN is not allowed as a Measure value");
  118. double scaledValue = scale(value, decimalScale);
  119. return new Measure(ValueType.DOUBLE, scaledValue, data, null, qualityGateStatus, variation);
  120. }
  121. public Measure create(double value, int decimalScale) {
  122. return create(value, decimalScale, null);
  123. }
  124. public Measure create(String value) {
  125. return new Measure(ValueType.STRING, null, requireNonNull(value), null, qualityGateStatus, variation);
  126. }
  127. public Measure create(Level level) {
  128. return new Measure(ValueType.LEVEL, null, null, requireNonNull(level), qualityGateStatus, variation);
  129. }
  130. public Measure createNoValue() {
  131. return new Measure(ValueType.NO_VALUE, null, null, null, qualityGateStatus, variation);
  132. }
  133. private static double scale(double value, int decimalScale) {
  134. BigDecimal bd = BigDecimal.valueOf(value);
  135. return bd.setScale(decimalScale, RoundingMode.HALF_UP).doubleValue();
  136. }
  137. }
  138. public static final class UpdateMeasureBuilder {
  139. private final Measure source;
  140. private QualityGateStatus qualityGateStatus;
  141. private Double variation;
  142. public UpdateMeasureBuilder(Measure source) {
  143. this.source = requireNonNull(source, "Can not create a measure from null");
  144. }
  145. /**
  146. * Sets the QualityGateStatus of the updated Measure to create.
  147. *
  148. * @throws NullPointerException if the specified {@link QualityGateStatus} is {@code null}
  149. * @throws UnsupportedOperationException if the source measure already has a {@link QualityGateStatus}
  150. */
  151. public UpdateMeasureBuilder setQualityGateStatus(QualityGateStatus qualityGateStatus) {
  152. if (source.qualityGateStatus != null) {
  153. throw new UnsupportedOperationException("QualityGate status can not be changed if already set on source Measure");
  154. }
  155. this.qualityGateStatus = requireNonNull(qualityGateStatus, "QualityGateStatus can not be set to null");
  156. return this;
  157. }
  158. /**
  159. * Sets the variation of the updated Measure to create.
  160. *
  161. * @throws UnsupportedOperationException if the source measure already has a variation
  162. */
  163. public UpdateMeasureBuilder setVariation(double variation) {
  164. if (source.variation != null) {
  165. throw new UnsupportedOperationException("Variation can not be changed if already set on source Measure");
  166. }
  167. this.variation = variation;
  168. return this;
  169. }
  170. public Measure create() {
  171. return new Measure(source.valueType,
  172. source.value, source.data, source.dataLevel,
  173. source.qualityGateStatus == null ? qualityGateStatus : source.qualityGateStatus,
  174. source.variation == null ? variation : source.variation);
  175. }
  176. }
  177. /**
  178. * The type of value stored in the measure.
  179. */
  180. public ValueType getValueType() {
  181. return valueType;
  182. }
  183. /**
  184. * The value of this measure as a boolean if the type is {@link Measure.ValueType#BOOLEAN}.
  185. *
  186. * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#BOOLEAN}
  187. */
  188. public boolean getBooleanValue() {
  189. checkValueType(ValueType.BOOLEAN);
  190. return value != null && value.intValue() == 1;
  191. }
  192. /**
  193. * The value of this measure as a int if the type is {@link Measure.ValueType#INT}.
  194. *
  195. * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#INT}
  196. */
  197. public int getIntValue() {
  198. checkValueType(ValueType.INT);
  199. return value.intValue();
  200. }
  201. /**
  202. * The value of this measure as a long if the type is {@link Measure.ValueType#LONG}.
  203. *
  204. * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LONG}
  205. */
  206. public long getLongValue() {
  207. checkValueType(ValueType.LONG);
  208. return value.longValue();
  209. }
  210. /**
  211. * The value of this measure as a double if the type is {@link Measure.ValueType#DOUBLE}.
  212. *
  213. * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#DOUBLE}
  214. */
  215. public double getDoubleValue() {
  216. checkValueType(ValueType.DOUBLE);
  217. return value;
  218. }
  219. /**
  220. * The value of this measure as a String if the type is {@link Measure.ValueType#STRING}.
  221. *
  222. * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#STRING}
  223. */
  224. public String getStringValue() {
  225. checkValueType(ValueType.STRING);
  226. return data;
  227. }
  228. /**
  229. * The value of this measure as a Level if the type is {@link Measure.ValueType#LEVEL}.
  230. *
  231. * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LEVEL}
  232. */
  233. public Level getLevelValue() {
  234. checkValueType(ValueType.LEVEL);
  235. return dataLevel;
  236. }
  237. /**
  238. * The data of this measure if it exists.
  239. * <p>
  240. * If the measure type is {@link Measure.ValueType#STRING}, the value returned by this function is the same as {@link #getStringValue()}.
  241. * </p>
  242. */
  243. public String getData() {
  244. return data;
  245. }
  246. private void checkValueType(ValueType expected) {
  247. if (valueType != expected) {
  248. throw new IllegalStateException(
  249. String.format(
  250. "value can not be converted to %s because current value type is a %s",
  251. expected.toString().toLowerCase(Locale.US),
  252. valueType));
  253. }
  254. }
  255. /**
  256. * Any Measure, which ever is its value type, can have a QualityGate status.
  257. */
  258. public boolean hasQualityGateStatus() {
  259. return this.qualityGateStatus != null;
  260. }
  261. /**
  262. * The QualityGate status for this measure.
  263. * <strong>Don't call this method unless you've checked the result of {@link #hasQualityGateStatus()} first</strong>
  264. *
  265. * @throws IllegalStateException if the measure has no QualityGate status
  266. */
  267. public QualityGateStatus getQualityGateStatus() {
  268. checkState(qualityGateStatus != null, "Measure does not have an QualityGate status");
  269. return this.qualityGateStatus;
  270. }
  271. /**
  272. * Any Measure, which ever is its value type, can have a variation.
  273. */
  274. public boolean hasVariation() {
  275. return variation != null;
  276. }
  277. /**
  278. * The variation of this measure.
  279. *
  280. * @throws IllegalStateException if the measure has no variation
  281. */
  282. public double getVariation() {
  283. checkState(variation != null, "Measure does not have variation");
  284. return variation;
  285. }
  286. @Override
  287. public String toString() {
  288. return com.google.common.base.MoreObjects.toStringHelper(this)
  289. .add("valueType", valueType)
  290. .add("value", value)
  291. .add("data", data)
  292. .add("dataLevel", dataLevel)
  293. .add("qualityGateStatus", qualityGateStatus)
  294. .add("variations", variation)
  295. .toString();
  296. }
  297. }