
org.sonar.server.computation.measure.Measure Maven / Gradle / Ivy
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.measure;
import com.google.common.base.Optional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Locale;
import java.util.Objects;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.server.computation.component.Developer;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
public final class Measure {
public enum ValueType {
NO_VALUE, BOOLEAN, INT, LONG, DOUBLE, STRING, LEVEL
}
public enum Level {
OK("Green"),
WARN("Orange"),
ERROR("Red");
private final String colorName;
Level(String colorName) {
this.colorName = colorName;
}
public String getColorName() {
return colorName;
}
public static Optional toLevel(@Nullable String level) {
if (level == null) {
return Optional.absent();
}
try {
return Optional.of(Level.valueOf(level));
} catch (IllegalArgumentException e) {
return Optional.absent();
}
}
}
private final ValueType valueType;
@CheckForNull
private final Developer developer;
@CheckForNull
private final Double value;
@CheckForNull
private final String data;
@CheckForNull
private final Level dataLevel;
@CheckForNull
private final String description;
@CheckForNull
private final QualityGateStatus qualityGateStatus;
@CheckForNull
private final MeasureVariations variations;
private Measure(ValueType valueType, @Nullable Developer developer,
@Nullable Double value, @Nullable String data, @Nullable Level dataLevel,
@Nullable String description, @Nullable QualityGateStatus qualityGateStatus, @Nullable MeasureVariations variations) {
this.valueType = valueType;
this.developer = developer;
this.value = value;
this.data = data;
this.dataLevel = dataLevel;
this.description = description;
this.qualityGateStatus = qualityGateStatus;
this.variations = variations;
}
public static NewMeasureBuilder newMeasureBuilder() {
return new NewMeasureBuilder();
}
public static UpdateMeasureBuilder updatedMeasureBuilder(Measure measure) {
return new UpdateMeasureBuilder(measure);
}
public static final class NewMeasureBuilder {
private Developer developer;
private String description;
private QualityGateStatus qualityGateStatus;
private MeasureVariations variations;
/**
* Sets the developer this measure is associated to.
*
*/
public NewMeasureBuilder forDeveloper(Developer developer) {
this.developer = developer;
return this;
}
/**
* Sets the description of the measure
*
* @throws NullPointerException if the specified argument is {@code null}
*/
public NewMeasureBuilder setDescription(String description) {
this.description = requireNonNull(description, "description can not be set to null");
return this;
}
public NewMeasureBuilder setQualityGateStatus(QualityGateStatus qualityGateStatus) {
this.qualityGateStatus = requireNonNull(qualityGateStatus, "QualityGateStatus can not be set to null");
return this;
}
public NewMeasureBuilder setVariations(MeasureVariations variations) {
this.variations = requireNonNull(variations, "Variations can not be set to null");
return this;
}
public Measure create(boolean value, @Nullable String data) {
return new Measure(ValueType.BOOLEAN, developer, value ? 1.0d : 0.0d, data, null, description, qualityGateStatus, variations);
}
public Measure create(boolean value) {
return create(value, null);
}
public Measure create(int value, @Nullable String data) {
return new Measure(ValueType.INT, developer, (double) value, data, null, description, qualityGateStatus, variations);
}
public Measure create(int value) {
return create(value, null);
}
public Measure create(long value, @Nullable String data) {
return new Measure(ValueType.LONG, developer, (double) value, data, null, description, qualityGateStatus, variations);
}
public Measure create(long value) {
return create(value, null);
}
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, developer, scaledValue, data, null, description, qualityGateStatus, variations);
}
public Measure create(double value, int decimalScale) {
return create(value, decimalScale, null);
}
public Measure create(String value) {
return new Measure(ValueType.STRING, developer, null, requireNonNull(value), null, description, qualityGateStatus, variations);
}
public Measure create(Level level) {
return new Measure(ValueType.LEVEL, developer, null, null, requireNonNull(level), description, qualityGateStatus, variations);
}
public Measure createNoValue() {
return new Measure(ValueType.NO_VALUE, developer, null, null, null, description, qualityGateStatus, variations);
}
private static double scale(double value, int decimalScale) {
BigDecimal bd = BigDecimal.valueOf(value);
return bd.setScale(decimalScale, RoundingMode.HALF_UP).doubleValue();
}
}
public static final class UpdateMeasureBuilder {
private final Measure source;
private QualityGateStatus qualityGateStatus;
private MeasureVariations variations;
public UpdateMeasureBuilder(Measure source) {
this.source = requireNonNull(source, "Can not create a measure from null");
}
/**
* Sets the QualityGateStatus of the updated Measure to create.
*
* @throws NullPointerException if the specified {@link QualityGateStatus} is {@code null}
* @throws UnsupportedOperationException if the source measure already has a {@link QualityGateStatus}
*/
public UpdateMeasureBuilder setQualityGateStatus(QualityGateStatus qualityGateStatus) {
if (source.qualityGateStatus != null) {
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");
return this;
}
/**
* Sets the MeasureVariations of the updated Measure to create.
*
* @throws NullPointerException if the specified {@link MeasureVariations} is {@code null}
* @throws UnsupportedOperationException if the source measure already has a {@link MeasureVariations}
*/
public UpdateMeasureBuilder setVariations(MeasureVariations variations) {
if (source.variations != null) {
throw new UnsupportedOperationException("Variations can not be changed if already set on source Measure");
}
this.variations = requireNonNull(variations, "Variations can not be set to null");
return this;
}
public Measure create() {
return new Measure(source.valueType, source.developer,
source.value, source.data, source.dataLevel,
source.description,
source.qualityGateStatus == null ? qualityGateStatus : source.qualityGateStatus,
source.variations == null ? variations : source.variations);
}
}
@CheckForNull
public Developer getDeveloper() {
return developer;
}
/**
* 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 == 1.0d;
}
/**
* 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.
*
* If the measure type is {@link Measure.ValueType#STRING}, the value returned by this function is the same as {@link #getStringValue()}.
*
*/
public String getData() {
return data;
}
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
));
}
}
/**
* 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.
* Don't call this method unless you've checked the result of {@link #hasQualityGateStatus()} first
*
* @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 Variations.
*/
public boolean hasVariations() {
return variations != null;
}
/**
* The variations of this measure.
*
* @throws IllegalStateException if the measure has no MeasureVariations
*/
public MeasureVariations getVariations() {
checkState(variations != null, "Measure does not have variations");
return variations;
}
/**
* The optional description of the measure. Relevant for manual measures.
*/
@CheckForNull
public String getDescription() {
return description;
}
/**
* a Metric is equal to another Metric if it has the same ruleId/characteristicId paar (both being potentially
* {@code null} but only one of them can be non {@code null}).
*/
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Measure measure = (Measure) o;
return Objects.equals(developer, measure.developer);
}
@Override
public int hashCode() {
return Objects.hash(developer);
}
@Override
public String toString() {
return com.google.common.base.Objects.toStringHelper(this)
.add("valueType", valueType)
.add("developer", developer)
.add("value", value)
.add("data", data)
.add("dataLevel", dataLevel)
.add("qualityGateStatus", qualityGateStatus)
.add("variations", variations)
.add("description", description)
.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy