import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
-public final class Measure {
+public interface Measure {
- public enum ValueType {
+ enum ValueType {
NO_VALUE, BOOLEAN, INT, LONG, DOUBLE, STRING, LEVEL
}
- public enum Level {
+ enum Level {
OK("Green"),
ERROR("Red"),
}
}
- private final ValueType valueType;
- @CheckForNull
- private final Double value;
- @CheckForNull
- private final String data;
- @CheckForNull
- private final Level dataLevel;
- @CheckForNull
- private final QualityGateStatus qualityGateStatus;
- @CheckForNull
- private final Double variation;
-
- private Measure(ValueType valueType, @Nullable Double value, @Nullable String data, @Nullable Level dataLevel,
- @Nullable QualityGateStatus qualityGateStatus, @Nullable Double variation) {
- this.valueType = valueType;
- this.value = DoubleCache.intern(value);
- this.data = data;
- this.dataLevel = dataLevel;
- this.qualityGateStatus = qualityGateStatus;
- this.variation = variation;
- }
+ /**
+ * The type of value stored in the measure.
+ */
+ ValueType getValueType();
+
+ /**
+ * The value of this measure as a boolean if the type is {@link Measure.ValueType#BOOLEAN}.
+ *
+ * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#BOOLEAN}
+ */
+ boolean getBooleanValue();
+
+ /**
+ * The value of this measure as a int if the type is {@link Measure.ValueType#INT}.
+ *
+ * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#INT}
+ */
+ int getIntValue();
+
+ /**
+ * The value of this measure as a long if the type is {@link Measure.ValueType#LONG}.
+ *
+ * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LONG}
+ */
+ long getLongValue();
+
+ /**
+ * The value of this measure as a double if the type is {@link Measure.ValueType#DOUBLE}.
+ *
+ * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#DOUBLE}
+ */
+ double getDoubleValue();
+
+ /**
+ * The value of this measure as a String if the type is {@link Measure.ValueType#STRING}.
+ *
+ * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#STRING}
+ */
+ String getStringValue();
+
+ /**
+ * The value of this measure as a Level if the type is {@link Measure.ValueType#LEVEL}.
+ *
+ * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LEVEL}
+ */
+ Level getLevelValue();
+
+ /**
+ * The data of this measure if it exists.
+ * <p>
+ * If the measure type is {@link Measure.ValueType#STRING}, the value returned by this function is the same as {@link #getStringValue()}.
+ * </p>
+ */
+ String getData();
+
+ /**
+ * Any Measure, which ever is its value type, can have a QualityGate status.
+ */
+ boolean hasQualityGateStatus();
+
+ /**
+ * The QualityGate status for this measure.
+ * <strong>Don't call this method unless you've checked the result of {@link #hasQualityGateStatus()} first</strong>
+ *
+ * @throws IllegalStateException if the measure has no QualityGate status
+ */
+ QualityGateStatus getQualityGateStatus();
+
+ /**
+ * Any Measure, which ever is its value type, can have a variation.
+ */
+ boolean hasVariation();
+
+ /**
+ * The variation of this measure.
+ *
+ * @throws IllegalStateException if the measure has no variation
+ */
+ double getVariation();
- public static NewMeasureBuilder newMeasureBuilder() {
+ static NewMeasureBuilder newMeasureBuilder() {
return new NewMeasureBuilder();
}
- public static UpdateMeasureBuilder updatedMeasureBuilder(Measure measure) {
+ static UpdateMeasureBuilder updatedMeasureBuilder(Measure measure) {
return new UpdateMeasureBuilder(measure);
}
- public static final class NewMeasureBuilder {
+ class MeasureImpl implements Measure {
+ private final ValueType valueType;
+ @CheckForNull
+ private final Double value;
+ @CheckForNull
+ private final String data;
+ @CheckForNull
+ private final Level dataLevel;
+ @CheckForNull
+ private final QualityGateStatus qualityGateStatus;
+ @CheckForNull
+ private final Double variation;
+
+ private MeasureImpl(ValueType valueType, @Nullable Double value, @Nullable String data, @Nullable Level dataLevel,
+ @Nullable QualityGateStatus qualityGateStatus, @Nullable Double variation) {
+ this.valueType = valueType;
+ this.value = DoubleCache.intern(value);
+ this.data = data;
+ this.dataLevel = dataLevel;
+ this.qualityGateStatus = qualityGateStatus;
+ this.variation = variation;
+ }
+
+ @Override
+ public ValueType getValueType() {
+ return valueType;
+ }
+
+ @Override
+ public boolean getBooleanValue() {
+ checkValueType(ValueType.BOOLEAN, valueType);
+ return value != null && value.intValue() == 1;
+ }
+
+ @Override
+ public int getIntValue() {
+ checkValueType(ValueType.INT, valueType);
+ return value.intValue();
+ }
+
+ @Override
+ public long getLongValue() {
+ checkValueType(ValueType.LONG, valueType);
+ return value.longValue();
+ }
+
+ @Override
+ public double getDoubleValue() {
+ checkValueType(ValueType.DOUBLE, valueType);
+ return value;
+ }
+
+ @Override
+ public String getStringValue() {
+ checkValueType(ValueType.STRING, valueType);
+ return data;
+ }
+
+ @Override
+ public Level getLevelValue() {
+ checkValueType(ValueType.LEVEL, valueType);
+ return dataLevel;
+ }
+
+ @Override
+ public String getData() {
+ return data;
+ }
+
+ @Override
+ public boolean hasQualityGateStatus() {
+ return this.qualityGateStatus != null;
+ }
+
+ @Override
+ public QualityGateStatus getQualityGateStatus() {
+ checkState(qualityGateStatus != null, "Measure does not have an QualityGate status");
+ return this.qualityGateStatus;
+ }
+
+ @Override
+ public boolean hasVariation() {
+ return variation != null;
+ }
+
+ @Override
+ public double getVariation() {
+ checkState(variation != null, "Measure does not have variation");
+ return variation;
+ }
+
+ private static void checkValueType(ValueType expected, ValueType valueType) {
+ if (valueType != expected) {
+ throw new IllegalStateException(
+ String.format(
+ "value can not be converted to %s because current value type is a %s",
+ expected.toString().toLowerCase(Locale.US),
+ valueType));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return com.google.common.base.MoreObjects.toStringHelper(this)
+ .add("valueType", valueType)
+ .add("value", value)
+ .add("data", data)
+ .add("dataLevel", dataLevel)
+ .add("qualityGateStatus", qualityGateStatus)
+ .add("variations", variation)
+ .toString();
+ }
+ }
+
+ class ValueMeasureImpl implements Measure {
+ private final ValueType valueType;
+ @CheckForNull
+ private final Double value;
+
+ private ValueMeasureImpl(ValueType valueType, @Nullable Double value) {
+ this.valueType = valueType;
+ this.value = DoubleCache.intern(value);
+ }
+
+ @Override
+ public ValueType getValueType() {
+ return valueType;
+ }
+
+ @Override
+ public boolean getBooleanValue() {
+ MeasureImpl.checkValueType(ValueType.BOOLEAN, valueType);
+ return value != null && value.intValue() == 1;
+ }
+
+ @Override
+ public int getIntValue() {
+ MeasureImpl.checkValueType(ValueType.INT, valueType);
+ return value.intValue();
+ }
+
+ @Override
+ public long getLongValue() {
+ MeasureImpl.checkValueType(ValueType.LONG, valueType);
+ return value.longValue();
+ }
+
+ @Override
+ public double getDoubleValue() {
+ MeasureImpl.checkValueType(ValueType.DOUBLE, valueType);
+ return value;
+ }
+
+ @Override
+ public String getStringValue() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public Level getLevelValue() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public String getData() {
+ return null;
+ }
+
+ @Override
+ public boolean hasQualityGateStatus() {
+ return false;
+ }
+
+ @Override
+ public QualityGateStatus getQualityGateStatus() {
+ throw new IllegalStateException("Measure does not have an QualityGate status");
+ }
+
+ @Override
+ public boolean hasVariation() {
+ return false;
+ }
+
+ @Override
+ public double getVariation() {
+ throw new IllegalStateException("Measure does not have variation");
+
+ }
+
+ @Override
+ public String toString() {
+ return com.google.common.base.MoreObjects.toStringHelper(this)
+ .add("valueType", valueType)
+ .add("value", value)
+ .toString();
+ }
+ }
+
+ class NoValueVariationMeasureImpl implements Measure {
+ @Nullable
+ private Double variation;
+ private ValueType valueType = ValueType.NO_VALUE;
+
+ private NoValueVariationMeasureImpl(@Nullable Double variation) {
+ this.variation = variation;
+ }
+
+ @Override
+ public ValueType getValueType() {
+ return ValueType.NO_VALUE;
+ }
+
+ @Override
+ public boolean getBooleanValue() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public int getIntValue() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public long getLongValue() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public double getDoubleValue() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public String getStringValue() {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public Level getLevelValue() {
+ throw new IllegalStateException();
+
+ }
+
+ @Override
+ public String getData() {
+ return null;
+ }
+
+ @Override
+ public boolean hasQualityGateStatus() {
+ return false;
+ }
+
+ @Override
+ public QualityGateStatus getQualityGateStatus() {
+ throw new IllegalStateException("Measure does not have an QualityGate status");
+ }
+
+ @Override
+ public boolean hasVariation() {
+ return variation != null;
+ }
+
+ @Override
+ public double getVariation() {
+ checkState(variation != null, "Measure does not have variation");
+ return variation;
+ }
+
+ @Override
+ public String toString() {
+ return com.google.common.base.MoreObjects.toStringHelper(this)
+ .add("valueType", valueType)
+ .add("variations", variation)
+ .toString();
+ }
+ }
+
+ class NewMeasureBuilder {
private QualityGateStatus qualityGateStatus;
private Double variation;
}
public Measure create(boolean value, @Nullable String data) {
- return new Measure(ValueType.BOOLEAN, value ? 1.0D : 0.0D, data, null, qualityGateStatus, variation);
+ return createInternal(ValueType.BOOLEAN, value ? 1.0D : 0.0D, data);
}
public Measure create(boolean value) {
}
public Measure create(int value, @Nullable String data) {
- return new Measure(ValueType.INT, (double) value, data, null, qualityGateStatus, variation);
+ return createInternal(ValueType.INT, (double) value, data);
}
public Measure create(int value) {
}
public Measure create(long value, @Nullable String data) {
- return new Measure(ValueType.LONG, (double) value, data, null, qualityGateStatus, variation);
+ return createInternal(ValueType.LONG, (double) value, data);
}
public Measure create(long value) {
public Measure create(double value, int decimalScale, @Nullable String data) {
checkArgument(!Double.isNaN(value), "NaN is not allowed as a Measure value");
double scaledValue = scale(value, decimalScale);
- return new Measure(ValueType.DOUBLE, scaledValue, data, null, qualityGateStatus, variation);
+ return createInternal(ValueType.DOUBLE, scaledValue, data);
+ }
+
+ private Measure createInternal(ValueType type, double value, @Nullable String data) {
+ if (data == null && qualityGateStatus == null && variation == null) {
+ return new ValueMeasureImpl(type, value);
+
+ }
+ return new MeasureImpl(type, value, data, null, qualityGateStatus, variation);
}
public Measure create(double value, int decimalScale) {
}
public Measure create(String value) {
- return new Measure(ValueType.STRING, null, requireNonNull(value), null, qualityGateStatus, variation);
+ return new MeasureImpl(ValueType.STRING, null, requireNonNull(value), null, qualityGateStatus, variation);
}
public Measure create(Level level) {
- return new Measure(ValueType.LEVEL, null, null, requireNonNull(level), qualityGateStatus, variation);
+ return new MeasureImpl(ValueType.LEVEL, null, null, requireNonNull(level), qualityGateStatus, variation);
}
public Measure createNoValue() {
- return new Measure(ValueType.NO_VALUE, null, null, null, qualityGateStatus, variation);
+ if (qualityGateStatus == null) {
+ return new NoValueVariationMeasureImpl(variation);
+ }
+ return new MeasureImpl(ValueType.NO_VALUE, null, null, null, qualityGateStatus, variation);
}
private static double scale(double value, int decimalScale) {
}
}
- public static final class UpdateMeasureBuilder {
+ final class UpdateMeasureBuilder {
private final Measure source;
private QualityGateStatus qualityGateStatus;
private Double variation;
* @throws UnsupportedOperationException if the source measure already has a {@link QualityGateStatus}
*/
public UpdateMeasureBuilder setQualityGateStatus(QualityGateStatus qualityGateStatus) {
- if (source.qualityGateStatus != null) {
+ if (source.hasQualityGateStatus()) {
throw new UnsupportedOperationException("QualityGate status can not be changed if already set on source Measure");
}
this.qualityGateStatus = requireNonNull(qualityGateStatus, "QualityGateStatus can not be set to null");
* @throws UnsupportedOperationException if the source measure already has a variation
*/
public UpdateMeasureBuilder setVariation(double variation) {
- if (source.variation != null) {
+ if (source.hasVariation()) {
throw new UnsupportedOperationException("Variation can not be changed if already set on source Measure");
}
this.variation = variation;
}
public Measure create() {
- return new Measure(source.valueType,
- source.value, source.data, source.dataLevel,
- source.qualityGateStatus == null ? qualityGateStatus : source.qualityGateStatus,
- source.variation == null ? variation : source.variation);
- }
- }
-
- /**
- * The type of value stored in the measure.
- */
- public ValueType getValueType() {
- return valueType;
- }
-
- /**
- * The value of this measure as a boolean if the type is {@link Measure.ValueType#BOOLEAN}.
- *
- * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#BOOLEAN}
- */
- public boolean getBooleanValue() {
- checkValueType(ValueType.BOOLEAN);
- return value != null && value.intValue() == 1;
- }
-
- /**
- * The value of this measure as a int if the type is {@link Measure.ValueType#INT}.
- *
- * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#INT}
- */
- public int getIntValue() {
- checkValueType(ValueType.INT);
- return value.intValue();
- }
-
- /**
- * The value of this measure as a long if the type is {@link Measure.ValueType#LONG}.
- *
- * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LONG}
- */
- public long getLongValue() {
- checkValueType(ValueType.LONG);
- return value.longValue();
- }
-
- /**
- * The value of this measure as a double if the type is {@link Measure.ValueType#DOUBLE}.
- *
- * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#DOUBLE}
- */
- public double getDoubleValue() {
- checkValueType(ValueType.DOUBLE);
- return value;
- }
-
- /**
- * The value of this measure as a String if the type is {@link Measure.ValueType#STRING}.
- *
- * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#STRING}
- */
- public String getStringValue() {
- checkValueType(ValueType.STRING);
- return data;
- }
-
- /**
- * The value of this measure as a Level if the type is {@link Measure.ValueType#LEVEL}.
- *
- * @throws IllegalStateException if the value type of the measure is not {@link Measure.ValueType#LEVEL}
- */
- public Level getLevelValue() {
- checkValueType(ValueType.LEVEL);
- return dataLevel;
- }
-
- /**
- * The data of this measure if it exists.
- * <p>
- * If the measure type is {@link Measure.ValueType#STRING}, the value returned by this function is the same as {@link #getStringValue()}.
- * </p>
- */
- public String getData() {
- return data;
- }
+ Double value;
+ switch (source.getValueType()) {
+ case DOUBLE:
+ value = source.getDoubleValue();
+ break;
+ case INT:
+ value = (double) source.getIntValue();
+ break;
+ case LONG:
+ value = (double) source.getLongValue();
+ break;
+ case BOOLEAN:
+ value = source.getBooleanValue() ? 1.0 : 0.0;
+ break;
+ case NO_VALUE:
+ default:
+ value = null;
+ break;
+ }
+ Level level = source.getValueType() == ValueType.LEVEL ? source.getLevelValue() : null;
+ QualityGateStatus status = source.hasQualityGateStatus() ? source.getQualityGateStatus() : qualityGateStatus;
+ boolean hasVar = source.hasVariation();
- private void checkValueType(ValueType expected) {
- if (valueType != expected) {
- throw new IllegalStateException(
- String.format(
- "value can not be converted to %s because current value type is a %s",
- expected.toString().toLowerCase(Locale.US),
- valueType));
+ Double var = hasVar ? source.getVariation() : variation;
+ return new MeasureImpl(source.getValueType(), value, source.getData(), level, status, var);
}
}
-
- /**
- * Any Measure, which ever is its value type, can have a QualityGate status.
- */
- public boolean hasQualityGateStatus() {
- return this.qualityGateStatus != null;
- }
-
- /**
- * The QualityGate status for this measure.
- * <strong>Don't call this method unless you've checked the result of {@link #hasQualityGateStatus()} first</strong>
- *
- * @throws IllegalStateException if the measure has no QualityGate status
- */
- public QualityGateStatus getQualityGateStatus() {
- checkState(qualityGateStatus != null, "Measure does not have an QualityGate status");
- return this.qualityGateStatus;
- }
-
- /**
- * Any Measure, which ever is its value type, can have a variation.
- */
- public boolean hasVariation() {
- return variation != null;
- }
-
- /**
- * The variation of this measure.
- *
- * @throws IllegalStateException if the measure has no variation
- */
- public double getVariation() {
- checkState(variation != null, "Measure does not have variation");
- return variation;
- }
-
- @Override
- public String toString() {
- return com.google.common.base.MoreObjects.toStringHelper(this)
- .add("valueType", valueType)
- .add("value", value)
- .add("data", data)
- .add("dataLevel", dataLevel)
- .add("qualityGateStatus", qualityGateStatus)
- .add("variations", variation)
- .toString();
- }
-
}