@@ -27,7 +27,7 @@ import org.sonar.server.computation.component.Component; | |||
/** | |||
* This repository contains issues for only one component at a time. It's populated by {@link IntegrateIssuesVisitor} and | |||
* it's mainly used by {@link org.sonar.server.computation.measure.api.MeasureComputerImplementationContext} in order for a {@link MeasureComputer} | |||
* it's mainly used by {@link org.sonar.api.ce.measure.MeasureComputer.MeasureComputerContext} in order for a {@link MeasureComputer} | |||
* to access to the issues of a component. | |||
* | |||
* This repository must NEVER contains more issues than in issues from one component order to not consume to much memory. |
@@ -20,7 +20,7 @@ | |||
package org.sonar.server.computation.measure; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.server.computation.measure.api.MeasureComputerWrapper; | |||
public interface MeasureComputersHolder { | |||
@@ -29,5 +29,5 @@ public interface MeasureComputersHolder { | |||
* | |||
* @throws IllegalStateException if the measure computers haven't been initialized | |||
*/ | |||
Iterable<MeasureComputer> getMeasureComputers(); | |||
Iterable<MeasureComputerWrapper> getMeasureComputers(); | |||
} |
@@ -22,7 +22,7 @@ package org.sonar.server.computation.measure; | |||
import com.google.common.base.Predicates; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.server.computation.measure.api.MeasureComputerWrapper; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static com.google.common.collect.FluentIterable.from; | |||
@@ -31,16 +31,16 @@ import static java.util.Objects.requireNonNull; | |||
public class MeasureComputersHolderImpl implements MutableMeasureComputersHolder { | |||
@CheckForNull | |||
private Iterable<MeasureComputer> measureComputers; | |||
private Iterable<MeasureComputerWrapper> measureComputers; | |||
@Override | |||
public Iterable<MeasureComputer> getMeasureComputers() { | |||
public Iterable<MeasureComputerWrapper> getMeasureComputers() { | |||
checkState(this.measureComputers != null, "Measure computers have not been initialized yet"); | |||
return measureComputers; | |||
} | |||
@Override | |||
public void setMeasureComputers(Iterable<MeasureComputer> measureComputers) { | |||
public void setMeasureComputers(Iterable<MeasureComputerWrapper> measureComputers) { | |||
requireNonNull(measureComputers, "Measure computers cannot be null"); | |||
checkState(this.measureComputers == null, "Measure computers have already been initialized"); | |||
this.measureComputers = from(measureComputers).filter(Predicates.notNull()).toList(); |
@@ -27,7 +27,8 @@ import org.sonar.server.computation.component.CrawlerDepthLimit; | |||
import org.sonar.server.computation.component.SettingsRepository; | |||
import org.sonar.server.computation.component.TypeAwareVisitorAdapter; | |||
import org.sonar.server.computation.issue.ComponentIssuesRepository; | |||
import org.sonar.server.computation.measure.api.MeasureComputerImplementationContext; | |||
import org.sonar.server.computation.measure.api.MeasureComputerContextImpl; | |||
import org.sonar.server.computation.measure.api.MeasureComputerWrapper; | |||
import org.sonar.server.computation.metric.MetricRepository; | |||
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; | |||
@@ -55,11 +56,12 @@ public class MeasureComputersVisitor extends TypeAwareVisitorAdapter { | |||
@Override | |||
public void visitAny(org.sonar.server.computation.component.Component component) { | |||
for (MeasureComputer computer : measureComputersHolder.getMeasureComputers()) { | |||
LOGGER.trace("Measure computer '{}' is computing component {}", computer.getImplementation(), component); | |||
MeasureComputerImplementationContext measureComputerContext = new MeasureComputerImplementationContext(component, computer, | |||
settings, measureRepository, metricRepository, componentIssuesRepository); | |||
computer.getImplementation().compute(measureComputerContext); | |||
MeasureComputerContextImpl context = new MeasureComputerContextImpl(component, settings, measureRepository, metricRepository, componentIssuesRepository); | |||
for (MeasureComputerWrapper measureComputerWrapper : measureComputersHolder.getMeasureComputers()) { | |||
context.setDefinition(measureComputerWrapper.getDefinition()); | |||
MeasureComputer measureComputer = measureComputerWrapper.getComputer(); | |||
LOGGER.trace("Measure computer '{}' is computing component {}", measureComputer, component); | |||
measureComputer.compute(context); | |||
} | |||
} | |||
} |
@@ -19,7 +19,7 @@ | |||
*/ | |||
package org.sonar.server.computation.measure; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.server.computation.measure.api.MeasureComputerWrapper; | |||
/** | |||
* A {@link MeasureComputersHolder} which value can be set only once. | |||
@@ -32,5 +32,5 @@ public interface MutableMeasureComputersHolder extends MeasureComputersHolder { | |||
* @throws NullPointerException if the specified Iterable is {@code null} | |||
* @throws IllegalStateException if the holder has already been initialized | |||
*/ | |||
void setMeasureComputers(Iterable<MeasureComputer> measureComputers); | |||
void setMeasureComputers(Iterable<MeasureComputerWrapper> measureComputers); | |||
} |
@@ -33,7 +33,6 @@ import javax.annotation.Nullable; | |||
import org.sonar.api.ce.measure.Component; | |||
import org.sonar.api.ce.measure.Issue; | |||
import org.sonar.api.ce.measure.Measure; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.api.ce.measure.Settings; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.server.computation.component.SettingsRepository; | |||
@@ -43,11 +42,12 @@ import org.sonar.server.computation.metric.Metric; | |||
import org.sonar.server.computation.metric.MetricRepository; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerContext; | |||
import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition; | |||
import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; | |||
public class MeasureComputerImplementationContext implements MeasureComputer.Implementation.Context { | |||
public class MeasureComputerContextImpl implements MeasureComputerContext { | |||
private final MeasureComputer measureComputer; | |||
private final SettingsRepository settings; | |||
private final MeasureRepository measureRepository; | |||
private final MetricRepository metricRepository; | |||
@@ -56,18 +56,17 @@ public class MeasureComputerImplementationContext implements MeasureComputer.Imp | |||
private final Component component; | |||
private final List<DefaultIssue> componentIssues; | |||
private final Set<String> allowedMetrics; | |||
private MeasureComputerDefinition definition; | |||
private Set<String> allowedMetrics; | |||
public MeasureComputerImplementationContext(org.sonar.server.computation.component.Component component, MeasureComputer measureComputer, | |||
SettingsRepository settings, MeasureRepository measureRepository, MetricRepository metricRepository, ComponentIssuesRepository componentIssuesRepository) { | |||
this.measureComputer = measureComputer; | |||
public MeasureComputerContextImpl(org.sonar.server.computation.component.Component component, SettingsRepository settings, | |||
MeasureRepository measureRepository, MetricRepository metricRepository, ComponentIssuesRepository componentIssuesRepository) { | |||
this.settings = settings; | |||
this.internalComponent = component; | |||
this.measureRepository = measureRepository; | |||
this.metricRepository = metricRepository; | |||
this.component = newComponent(component); | |||
this.componentIssues = componentIssuesRepository.getIssues(component); | |||
this.allowedMetrics = allowedMetric(measureComputer); | |||
} | |||
private Component newComponent(org.sonar.server.computation.component.Component component) { | |||
@@ -79,10 +78,20 @@ public class MeasureComputerImplementationContext implements MeasureComputer.Imp | |||
null); | |||
} | |||
private static Set<String> allowedMetric(MeasureComputer measureComputer) { | |||
/** | |||
* Definition needs to be reset each time a new computer is processed. | |||
* Defining it by a setter allows to reduce the number of this class to be created (one per component instead of one per component and per computer). | |||
*/ | |||
public MeasureComputerContextImpl setDefinition(MeasureComputerDefinition definition) { | |||
this.definition = definition; | |||
this.allowedMetrics = allowedMetric(definition); | |||
return this; | |||
} | |||
private static Set<String> allowedMetric(MeasureComputerDefinition definition) { | |||
Set<String> allowedMetrics = new HashSet<>(); | |||
allowedMetrics.addAll(measureComputer.getInputMetrics()); | |||
allowedMetrics.addAll(measureComputer.getOutputMetrics()); | |||
allowedMetrics.addAll(definition.getInputMetrics()); | |||
allowedMetrics.addAll(definition.getOutputMetrics()); | |||
return allowedMetrics; | |||
} | |||
@@ -160,12 +169,12 @@ public class MeasureComputerImplementationContext implements MeasureComputer.Imp | |||
} | |||
private void validateInputMetric(String metric) { | |||
checkArgument(allowedMetrics.contains(metric), "Only metrics in %s can be used to load measures", measureComputer.getInputMetrics()); | |||
checkArgument(allowedMetrics.contains(metric), "Only metrics in %s can be used to load measures", definition.getInputMetrics()); | |||
} | |||
private void validateAddMeasure(Metric metric) { | |||
checkArgument(measureComputer.getOutputMetrics().contains(metric.getKey()), "Only metrics in %s can be used to add measures. Metric '%s' is not allowed.", | |||
measureComputer.getOutputMetrics(), metric.getKey()); | |||
checkArgument(definition.getOutputMetrics().contains(metric.getKey()), "Only metrics in %s can be used to add measures. Metric '%s' is not allowed.", | |||
definition.getOutputMetrics(), metric.getKey()); | |||
if (measureRepository.getRawMeasure(internalComponent, metric).isPresent()) { | |||
throw new UnsupportedOperationException(String.format("A measure on metric '%s' already exists on component '%s'", metric.getKey(), internalComponent.getKey())); | |||
} |
@@ -22,22 +22,21 @@ package org.sonar.server.computation.measure.api; | |||
import com.google.common.collect.ImmutableSet; | |||
import java.util.Set; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.util.Objects.requireNonNull; | |||
public class MeasureComputerImpl implements MeasureComputer { | |||
public class MeasureComputerDefinitionImpl implements MeasureComputer.MeasureComputerDefinition { | |||
private final Set<String> inputMetricKeys; | |||
private final Set<String> outputMetrics; | |||
private final Implementation implementation; | |||
public MeasureComputerImpl(MeasureComputerBuilderImpl builder) { | |||
private MeasureComputerDefinitionImpl(BuilderImpl builder) { | |||
this.inputMetricKeys = ImmutableSet.copyOf(builder.inputMetricKeys); | |||
this.outputMetrics = ImmutableSet.copyOf(builder.outputMetrics); | |||
this.implementation = builder.measureComputerImplementation; | |||
} | |||
@Override | |||
@@ -50,11 +49,6 @@ public class MeasureComputerImpl implements MeasureComputer { | |||
return outputMetrics; | |||
} | |||
@Override | |||
public Implementation getImplementation() { | |||
return implementation; | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
@@ -64,7 +58,7 @@ public class MeasureComputerImpl implements MeasureComputer { | |||
return false; | |||
} | |||
MeasureComputerImpl that = (MeasureComputerImpl) o; | |||
MeasureComputerDefinitionImpl that = (MeasureComputerDefinitionImpl) o; | |||
if (!inputMetricKeys.equals(that.inputMetricKeys)) { | |||
return false; | |||
@@ -81,43 +75,35 @@ public class MeasureComputerImpl implements MeasureComputer { | |||
@Override | |||
public String toString() { | |||
return "MeasureComputerImpl{" + | |||
return "MeasureComputerDefinitionImpl{" + | |||
"inputMetricKeys=" + inputMetricKeys + | |||
", outputMetrics=" + outputMetrics + | |||
", implementation=" + implementation + | |||
'}'; | |||
} | |||
public static class MeasureComputerBuilderImpl implements MeasureComputerBuilder { | |||
public static class BuilderImpl implements Builder { | |||
private String[] inputMetricKeys = new String[] {}; | |||
@CheckForNull | |||
private String[] outputMetrics; | |||
private Implementation measureComputerImplementation; | |||
@Override | |||
public MeasureComputerBuilder setInputMetrics(String... inputMetrics) { | |||
public Builder setInputMetrics(String... inputMetrics) { | |||
this.inputMetricKeys = validateInputMetricKeys(inputMetrics); | |||
return this; | |||
} | |||
@Override | |||
public MeasureComputerBuilder setOutputMetrics(String... outputMetrics) { | |||
public Builder setOutputMetrics(String... outputMetrics) { | |||
this.outputMetrics = validateOutputMetricKeys(outputMetrics); | |||
return this; | |||
} | |||
@Override | |||
public MeasureComputerBuilder setImplementation(Implementation impl) { | |||
this.measureComputerImplementation = validateImplementation(impl); | |||
return this; | |||
} | |||
@Override | |||
public MeasureComputer build() { | |||
public MeasureComputer.MeasureComputerDefinition build() { | |||
validateInputMetricKeys(this.inputMetricKeys); | |||
validateOutputMetricKeys(this.outputMetrics); | |||
validateImplementation(this.measureComputerImplementation); | |||
return new MeasureComputerImpl(this); | |||
return new MeasureComputerDefinitionImpl(this); | |||
} | |||
private static String[] validateInputMetricKeys(@Nullable String[] inputMetrics) { | |||
@@ -127,20 +113,16 @@ public class MeasureComputerImpl implements MeasureComputer { | |||
} | |||
private static String[] validateOutputMetricKeys(@Nullable String[] outputMetrics) { | |||
checkArgument(outputMetrics != null && outputMetrics.length > 0, "At least one output metric must be defined"); | |||
requireNonNull(outputMetrics, "Output metrics cannot be null"); | |||
checkArgument(outputMetrics.length > 0, "At least one output metric must be defined"); | |||
checkNotNull(outputMetrics); | |||
return outputMetrics; | |||
} | |||
private static Implementation validateImplementation(Implementation impl) { | |||
return requireNonNull(impl, "The implementation is missing"); | |||
} | |||
} | |||
private static void checkNotNull(String[] metrics){ | |||
private static void checkNotNull(String[] metrics) { | |||
for (String metric : metrics) { | |||
requireNonNull(metric, "Null metric is not allowed"); | |||
} | |||
} | |||
} |
@@ -1,89 +0,0 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.api; | |||
import com.google.common.collect.ImmutableSet; | |||
import com.google.common.collect.Sets; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.api.ce.measure.MeasureComputerProvider; | |||
public class MeasureComputerProviderContext implements MeasureComputerProvider.Context { | |||
private final List<MeasureComputer> measureComputers = new ArrayList<>(); | |||
private final Map<String, MeasureComputer> computerByOutputMetrics = new HashMap<>(); | |||
@Override | |||
public MeasureComputerProvider.Context add(MeasureComputer inputMeasureComputer) { | |||
MeasureComputer measureComputer = validateMeasureComputer(inputMeasureComputer); | |||
checkOutputMetricsNotAlreadyDefinedByAnotherComputer(measureComputer); | |||
this.measureComputers.add(measureComputer); | |||
for (String metric : measureComputer.getOutputMetrics()) { | |||
computerByOutputMetrics.put(metric, measureComputer); | |||
} | |||
return this; | |||
} | |||
private MeasureComputer validateMeasureComputer(MeasureComputer measureComputer) { | |||
if (measureComputer instanceof MeasureComputerImpl) { | |||
return measureComputer; | |||
} | |||
// If the computer has not been created by the builder, we recreate it to make sure it's valid | |||
Set<String> inputMetrics = measureComputer.getInputMetrics(); | |||
Set<String> outputMetrics = measureComputer.getOutputMetrics(); | |||
return newMeasureComputerBuilder() | |||
.setInputMetrics(inputMetrics.toArray(new String[inputMetrics.size()])) | |||
.setOutputMetrics(outputMetrics.toArray(new String[outputMetrics.size()])) | |||
.setImplementation(measureComputer.getImplementation()) | |||
.build(); | |||
} | |||
public List<MeasureComputer> getMeasureComputers() { | |||
return measureComputers; | |||
} | |||
private void checkOutputMetricsNotAlreadyDefinedByAnotherComputer(MeasureComputer measureComputer) { | |||
Set<String> duplicated = ImmutableSet.copyOf(Sets.intersection(computerByOutputMetrics.keySet(), measureComputer.getOutputMetrics())); | |||
if (!duplicated.isEmpty()) { | |||
throw new UnsupportedOperationException(generateErrorMsg(duplicated)); | |||
} | |||
} | |||
private String generateErrorMsg(Set<String> duplicated){ | |||
StringBuilder errorMsg = new StringBuilder(); | |||
for (String duplicationMetric : duplicated) { | |||
MeasureComputer otherComputer = computerByOutputMetrics.get(duplicationMetric); | |||
errorMsg.append(String.format( | |||
"The output metric '%s' is already declared by another computer. This computer has these input metrics '%s' and these output metrics '%s'. ", | |||
duplicationMetric, otherComputer.getInputMetrics(), otherComputer.getOutputMetrics())); | |||
} | |||
return errorMsg.toString(); | |||
} | |||
@Override | |||
public MeasureComputer.MeasureComputerBuilder newMeasureComputerBuilder() { | |||
return new MeasureComputerImpl.MeasureComputerBuilderImpl(); | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.api; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition; | |||
import static java.util.Objects.requireNonNull; | |||
@Immutable | |||
public class MeasureComputerWrapper { | |||
private final MeasureComputer computer; | |||
private final MeasureComputerDefinition definition; | |||
public MeasureComputerWrapper(MeasureComputer computer, MeasureComputerDefinition definition) { | |||
this.computer = requireNonNull(computer); | |||
this.definition = requireNonNull(definition); | |||
} | |||
public MeasureComputer getComputer() { | |||
return computer; | |||
} | |||
public MeasureComputerDefinition getDefinition() { | |||
return definition; | |||
} | |||
@Override | |||
public String toString() { | |||
return computer.toString(); | |||
} | |||
} |
@@ -21,9 +21,10 @@ | |||
package org.sonar.server.computation.step; | |||
import com.google.common.base.Function; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.base.Predicates; | |||
import com.google.common.collect.FluentIterable; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
@@ -31,124 +32,118 @@ import java.util.Set; | |||
import javax.annotation.Nonnull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.api.ce.measure.MeasureComputerProvider; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.measures.Metrics; | |||
import org.sonar.api.utils.dag.DirectAcyclicGraph; | |||
import org.sonar.server.computation.measure.MutableMeasureComputersHolder; | |||
import org.sonar.server.computation.measure.api.MeasureComputerProviderContext; | |||
import org.sonar.server.computation.measure.api.MeasureComputerDefinitionImpl; | |||
import org.sonar.server.computation.measure.api.MeasureComputerWrapper; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition; | |||
import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinitionContext; | |||
public class FeedMeasureComputers implements ComputationStep { | |||
private static final Set<String> CORE_METRIC_KEYS = FluentIterable.from(CoreMetrics.getMetrics()).transform(MetricToKey.INSTANCE).toSet(); | |||
private static final Set<String> CORE_METRIC_KEYS = from(CoreMetrics.getMetrics()).transform(MetricToKey.INSTANCE).toSet(); | |||
private Set<String> pluginMetricKeys; | |||
private final MutableMeasureComputersHolder measureComputersHolder; | |||
private final Metrics[] metricsRepositories; | |||
private final MeasureComputerProvider[] measureComputerProviders; | |||
private final MeasureComputer[] measureComputers; | |||
public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, Metrics[] metricsRepositories, MeasureComputerProvider[] measureComputerProviders) { | |||
public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, Metrics[] metricsRepositories, MeasureComputer[] measureComputers) { | |||
this.measureComputersHolder = measureComputersHolder; | |||
this.measureComputerProviders = measureComputerProviders; | |||
this.metricsRepositories = metricsRepositories; | |||
this.measureComputers = measureComputers; | |||
this.pluginMetricKeys = from(Arrays.asList(metricsRepositories)) | |||
.transformAndConcat(MetricsToMetricList.INSTANCE) | |||
.transform(MetricToKey.INSTANCE) | |||
.toSet(); | |||
} | |||
/** | |||
* Constructor override used by Pico to instantiate the class when no plugin is defining metrics | |||
*/ | |||
public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, MeasureComputerProvider[] measureComputerProviders) { | |||
this(measureComputersHolder, new Metrics[] {}, measureComputerProviders); | |||
public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, MeasureComputer[] measureComputers) { | |||
this(measureComputersHolder, new Metrics[] {}, measureComputers); | |||
} | |||
/** | |||
* Constructor override used by Pico to instantiate the class when no plugin is defining measure computers | |||
*/ | |||
public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, Metrics[] metricsRepositories) { | |||
this(measureComputersHolder, metricsRepositories, new MeasureComputerProvider[] {}); | |||
this(measureComputersHolder, metricsRepositories, new MeasureComputer[]{}); | |||
} | |||
/** | |||
* Constructor override used by Pico to instantiate the class when no plugin is defining metrics neither measure computers | |||
*/ | |||
public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder) { | |||
this(measureComputersHolder, new Metrics[] {}, new MeasureComputerProvider[] {}); | |||
this(measureComputersHolder, new Metrics[] {}, new MeasureComputer[] {}); | |||
} | |||
@Override | |||
public void execute() { | |||
MeasureComputerProviderContext context = new MeasureComputerProviderContext(); | |||
for (MeasureComputerProvider provider : measureComputerProviders) { | |||
provider.register(context); | |||
} | |||
validateInputMetrics(context.getMeasureComputers()); | |||
measureComputersHolder.setMeasureComputers(sortComputers(context.getMeasureComputers())); | |||
List<MeasureComputerWrapper> wrappers = from(Arrays.asList(measureComputers)).transform(ToMeasureWrapper.INSTANCE).toList(); | |||
validateMetrics(wrappers); | |||
measureComputersHolder.setMeasureComputers(sortComputers(wrappers)); | |||
} | |||
private static Iterable<MeasureComputer> sortComputers(List<MeasureComputer> computers) { | |||
Map<String, MeasureComputer> computersByOutputMetric = new HashMap<>(); | |||
Map<String, MeasureComputer> computersByInputMetric = new HashMap<>(); | |||
feedComputersByMetric(computers, computersByOutputMetric, computersByInputMetric); | |||
private static Iterable<MeasureComputerWrapper> sortComputers(List<MeasureComputerWrapper> wrappers) { | |||
Map<String, MeasureComputerWrapper> computersByOutputMetric = new HashMap<>(); | |||
Map<String, MeasureComputerWrapper> computersByInputMetric = new HashMap<>(); | |||
feedComputersByMetric(wrappers, computersByOutputMetric, computersByInputMetric); | |||
ToComputerByKey toComputerByOutputMetricKey = new ToComputerByKey(computersByOutputMetric); | |||
ToComputerByKey toComputerByInputMetricKey = new ToComputerByKey(computersByInputMetric); | |||
DirectAcyclicGraph dag = new DirectAcyclicGraph(); | |||
for (MeasureComputer computer : computers) { | |||
for (MeasureComputerWrapper computer : wrappers) { | |||
dag.add(computer); | |||
for (MeasureComputer dependency : getDependencies(computer, toComputerByOutputMetricKey)) { | |||
for (MeasureComputerWrapper dependency : getDependencies(computer, toComputerByOutputMetricKey)) { | |||
dag.add(computer, dependency); | |||
} | |||
for (MeasureComputer generates : getDependents(computer, toComputerByInputMetricKey)) { | |||
for (MeasureComputerWrapper generates : getDependents(computer, toComputerByInputMetricKey)) { | |||
dag.add(generates, computer); | |||
} | |||
} | |||
return dag.sort(); | |||
} | |||
private static void feedComputersByMetric(List<MeasureComputer> computers, Map<String, MeasureComputer> computersByOutputMetric, | |||
Map<String, MeasureComputer> computersByInputMetric) { | |||
for (MeasureComputer computer : computers) { | |||
for (String outputMetric : computer.getOutputMetrics()) { | |||
private static void feedComputersByMetric(List<MeasureComputerWrapper> wrappers, Map<String, MeasureComputerWrapper> computersByOutputMetric, | |||
Map<String, MeasureComputerWrapper> computersByInputMetric) { | |||
for (MeasureComputerWrapper computer : wrappers) { | |||
for (String outputMetric : computer.getDefinition().getOutputMetrics()) { | |||
computersByOutputMetric.put(outputMetric, computer); | |||
} | |||
for (String inputMetric : computer.getInputMetrics()) { | |||
for (String inputMetric : computer.getDefinition().getInputMetrics()) { | |||
computersByInputMetric.put(inputMetric, computer); | |||
} | |||
} | |||
} | |||
private void validateInputMetrics(List<MeasureComputer> computers) { | |||
Set<String> pluginMetricKeys = FluentIterable.from(Arrays.asList(metricsRepositories)) | |||
.transformAndConcat(MetricsToMetricList.INSTANCE) | |||
.transform(MetricToKey.INSTANCE) | |||
.toSet(); | |||
// TODO would be nice to generate an error containing all bad input metrics | |||
for (MeasureComputer computer : computers) { | |||
for (String metric : computer.getInputMetrics()) { | |||
if (!pluginMetricKeys.contains(metric) && !CORE_METRIC_KEYS.contains(metric)) { | |||
throw new IllegalStateException(String.format("Metric '%s' cannot be used as an input metric as it's no a core metric and no plugin declare this metric", metric)); | |||
} | |||
} | |||
} | |||
private void validateMetrics(List<MeasureComputerWrapper> wrappers) { | |||
from(wrappers).transformAndConcat(ToInputMetrics.INSTANCE).filter(new ValidateInputMetric()).size(); | |||
from(wrappers).transformAndConcat(ToOutputMetrics.INSTANCE).filter(new ValidateOutputMetric()).size(); | |||
} | |||
private static Iterable<MeasureComputer> getDependencies(MeasureComputer measureComputer, ToComputerByKey toComputerByOutputMetricKey) { | |||
private static Iterable<MeasureComputerWrapper> getDependencies(MeasureComputerWrapper measureComputer, ToComputerByKey toComputerByOutputMetricKey) { | |||
// Remove null computer because a computer can depend on a metric that is only generated by a sensor or on a core metrics | |||
return FluentIterable.from(measureComputer.getInputMetrics()).transform(toComputerByOutputMetricKey).filter(Predicates.notNull()); | |||
return from(measureComputer.getDefinition().getInputMetrics()).transform(toComputerByOutputMetricKey).filter(Predicates.notNull()); | |||
} | |||
private static Iterable<MeasureComputer> getDependents(MeasureComputer measureComputer, ToComputerByKey toComputerByInputMetricKey) { | |||
return FluentIterable.from(measureComputer.getInputMetrics()).transform(toComputerByInputMetricKey); | |||
private static Iterable<MeasureComputerWrapper> getDependents(MeasureComputerWrapper measureComputer, ToComputerByKey toComputerByInputMetricKey) { | |||
return from(measureComputer.getDefinition().getInputMetrics()).transform(toComputerByInputMetricKey); | |||
} | |||
private static class ToComputerByKey implements Function<String, MeasureComputer> { | |||
private final Map<String, MeasureComputer> computersByMetric; | |||
private static class ToComputerByKey implements Function<String, MeasureComputerWrapper> { | |||
private final Map<String, MeasureComputerWrapper> computersByMetric; | |||
private ToComputerByKey(Map<String, MeasureComputer> computersByMetric) { | |||
private ToComputerByKey(Map<String, MeasureComputerWrapper> computersByMetric) { | |||
this.computersByMetric = computersByMetric; | |||
} | |||
@Override | |||
public MeasureComputer apply(@Nonnull String metricKey) { | |||
public MeasureComputerWrapper apply(@Nonnull String metricKey) { | |||
return computersByMetric.get(metricKey); | |||
} | |||
} | |||
@@ -172,6 +167,73 @@ public class FeedMeasureComputers implements ComputationStep { | |||
} | |||
} | |||
private enum ToMeasureWrapper implements Function<MeasureComputer, MeasureComputerWrapper> { | |||
INSTANCE; | |||
private final MeasureComputerDefinitionContextImpl context = new MeasureComputerDefinitionContextImpl(); | |||
@Override | |||
public MeasureComputerWrapper apply(@Nonnull MeasureComputer measureComputer) { | |||
MeasureComputerDefinition def = measureComputer.define(context); | |||
// If the computer has not been created by the builder, we recreate it to make sure it's valid | |||
Set<String> inputMetrics = def.getInputMetrics(); | |||
Set<String> outputMetrics = def.getOutputMetrics(); | |||
MeasureComputerDefinition validateDef = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics(from(inputMetrics).toArray(String.class)) | |||
.setOutputMetrics(from(outputMetrics).toArray(String.class)) | |||
.build(); | |||
return new MeasureComputerWrapper(measureComputer, validateDef); | |||
} | |||
} | |||
private enum ToInputMetrics implements Function<MeasureComputerWrapper, Collection<String>> { | |||
INSTANCE; | |||
@Override | |||
public Collection<String> apply(@Nonnull MeasureComputerWrapper input) { | |||
return input.getDefinition().getInputMetrics(); | |||
} | |||
} | |||
private class ValidateInputMetric implements Predicate<String> { | |||
@Override | |||
public boolean apply(@Nullable String metric) { | |||
if (!pluginMetricKeys.contains(metric) && !CORE_METRIC_KEYS.contains(metric)) { | |||
throw new IllegalStateException(String.format("Metric '%s' cannot be used as an input metric as it's not a core metric and no plugin declare this metric", metric)); | |||
} | |||
return true; | |||
} | |||
} | |||
private enum ToOutputMetrics implements Function<MeasureComputerWrapper, Collection<String>> { | |||
INSTANCE; | |||
@Override | |||
public Collection<String> apply(@Nonnull MeasureComputerWrapper input) { | |||
return input.getDefinition().getOutputMetrics(); | |||
} | |||
} | |||
private class ValidateOutputMetric implements Predicate<String> { | |||
@Override | |||
public boolean apply(@Nullable String metric) { | |||
if (CORE_METRIC_KEYS.contains(metric)) { | |||
throw new IllegalStateException(String.format("Metric '%s' cannot be used as an output metric as it's a core metric", metric)); | |||
} | |||
if (!pluginMetricKeys.contains(metric)) { | |||
throw new IllegalStateException(String.format("Metric '%s' cannot be used as an output metric as no plugin declare this metric", metric)); | |||
} | |||
return true; | |||
} | |||
} | |||
private static class MeasureComputerDefinitionContextImpl implements MeasureComputerDefinitionContext { | |||
@Override | |||
public MeasureComputerDefinition.Builder newDefinitionBuilder() { | |||
return new MeasureComputerDefinitionImpl.BuilderImpl(); | |||
} | |||
} | |||
@Override | |||
public String getDescription() { | |||
return "Feed measure computers"; |
@@ -25,7 +25,7 @@ import java.util.Collections; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.server.computation.measure.api.MeasureComputerWrapper; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -39,7 +39,7 @@ public class MeasureComputersHolderImplTest { | |||
@Test | |||
public void get_measure_computers() throws Exception { | |||
MeasureComputer measureComputer = mock(MeasureComputer.class); | |||
MeasureComputerWrapper measureComputer = mock(MeasureComputerWrapper.class); | |||
underTest.setMeasureComputers(Collections.singletonList(measureComputer)); | |||
assertThat(underTest.getMeasureComputers()).containsOnly(measureComputer); | |||
@@ -55,7 +55,7 @@ public class MeasureComputersHolderImplTest { | |||
@Test | |||
public void set_measure_computers_supports_empty_arg_is_empty() { | |||
underTest.setMeasureComputers(ImmutableList.<MeasureComputer>of()); | |||
underTest.setMeasureComputers(ImmutableList.<MeasureComputerWrapper>of()); | |||
assertThat(underTest.getMeasureComputers()).isEmpty(); | |||
} | |||
@@ -65,7 +65,7 @@ public class MeasureComputersHolderImplTest { | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("Measure computers have already been initialized"); | |||
MeasureComputer measureComputer = mock(MeasureComputer.class); | |||
MeasureComputerWrapper measureComputer = mock(MeasureComputerWrapper.class); | |||
underTest.setMeasureComputers(Collections.singletonList(measureComputer)); | |||
underTest.setMeasureComputers(Collections.singletonList(measureComputer)); | |||
} |
@@ -30,7 +30,8 @@ import org.sonar.server.computation.component.Component; | |||
import org.sonar.server.computation.component.ComponentVisitor; | |||
import org.sonar.server.computation.component.VisitorsCrawler; | |||
import org.sonar.server.computation.issue.ComponentIssuesRepository; | |||
import org.sonar.server.computation.measure.api.MeasureComputerImpl; | |||
import org.sonar.server.computation.measure.api.MeasureComputerDefinitionImpl; | |||
import org.sonar.server.computation.measure.api.MeasureComputerWrapper; | |||
import org.sonar.server.computation.metric.MetricRepositoryRule; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
@@ -105,26 +106,32 @@ public class MeasureComputersVisitorTest { | |||
measureRepository.addRawMeasure(ROOT_REF, NCLOC_KEY, newMeasureBuilder().create(50)); | |||
measureRepository.addRawMeasure(ROOT_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(7)); | |||
final MeasureComputer.MeasureComputerDefinition definition = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics(NCLOC_KEY, COMMENT_LINES_KEY) | |||
.setOutputMetrics(NEW_METRIC_KEY) | |||
.build(); | |||
measureComputersHolder.setMeasureComputers(newArrayList( | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
.setInputMetrics(NCLOC_KEY, COMMENT_LINES_KEY) | |||
.setOutputMetrics(NEW_METRIC_KEY) | |||
.setImplementation( | |||
new MeasureComputer.Implementation() { | |||
@Override | |||
public void compute(Context ctx) { | |||
org.sonar.api.ce.measure.Measure ncloc = ctx.getMeasure(NCLOC_KEY); | |||
org.sonar.api.ce.measure.Measure comment = ctx.getMeasure(COMMENT_LINES_KEY); | |||
if (ncloc != null && comment != null) { | |||
ctx.addMeasure(NEW_METRIC_KEY, ncloc.getIntValue() + comment.getIntValue()); | |||
} | |||
new MeasureComputerWrapper( | |||
new MeasureComputer() { | |||
@Override | |||
public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) { | |||
return definition; | |||
} | |||
@Override | |||
public void compute(MeasureComputerContext context) { | |||
org.sonar.api.ce.measure.Measure ncloc = context.getMeasure(NCLOC_KEY); | |||
org.sonar.api.ce.measure.Measure comment = context.getMeasure(COMMENT_LINES_KEY); | |||
if (ncloc != null && comment != null) { | |||
context.addMeasure(NEW_METRIC_KEY, ncloc.getIntValue() + comment.getIntValue()); | |||
} | |||
} | |||
) | |||
.build() | |||
)); | |||
}, | |||
definition | |||
))); | |||
VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.<ComponentVisitor>asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, measureComputersHolder, componentIssuesRepository))); | |||
VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.<ComponentVisitor>asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, | |||
measureComputersHolder, componentIssuesRepository))); | |||
visitorsCrawler.visit(ROOT); | |||
assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).containsOnly(entryOf(NEW_METRIC_KEY, newMeasureBuilder().create(12))); | |||
@@ -147,8 +154,9 @@ public class MeasureComputersVisitorTest { | |||
measureRepository.addRawMeasure(ROOT_REF, NCLOC_KEY, newMeasureBuilder().create(50)); | |||
measureRepository.addRawMeasure(ROOT_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(7)); | |||
measureComputersHolder.setMeasureComputers(Collections.<MeasureComputer>emptyList()); | |||
VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.<ComponentVisitor>asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, measureComputersHolder, componentIssuesRepository))); | |||
measureComputersHolder.setMeasureComputers(Collections.<MeasureComputerWrapper>emptyList()); | |||
VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.<ComponentVisitor>asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, | |||
measureComputersHolder, componentIssuesRepository))); | |||
visitorsCrawler.visit(ROOT); | |||
assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).isEmpty(); |
@@ -24,7 +24,6 @@ import com.google.common.base.Optional; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Set; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
@@ -43,7 +42,6 @@ import org.sonar.server.computation.metric.Metric; | |||
import org.sonar.server.computation.metric.MetricImpl; | |||
import org.sonar.server.computation.metric.MetricRepositoryRule; | |||
import static com.google.common.collect.ImmutableSet.of; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.guava.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -53,7 +51,7 @@ import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; | |||
import static org.sonar.server.computation.component.ReportComponent.builder; | |||
import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; | |||
public class MeasureComputerImplementationContextTest { | |||
public class MeasureComputerContextImplTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@@ -98,7 +96,7 @@ public class MeasureComputerImplementationContextTest { | |||
@Test | |||
public void get_component() throws Exception { | |||
MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF); | |||
MeasureComputerContextImpl underTest = newContext(FILE_1_REF); | |||
assertThat(underTest.getComponent().getType()).isEqualTo(Component.Type.FILE); | |||
} | |||
@@ -108,7 +106,7 @@ public class MeasureComputerImplementationContextTest { | |||
serverSettings.setProperty("prop", "value"); | |||
when(settingsRepository.getSettings(FILE_1)).thenReturn(serverSettings); | |||
MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF); | |||
MeasureComputerContextImpl underTest = newContext(FILE_1_REF); | |||
assertThat(underTest.getSettings().getString("prop")).isEqualTo("value"); | |||
assertThat(underTest.getSettings().getString("unknown")).isNull(); | |||
} | |||
@@ -119,7 +117,7 @@ public class MeasureComputerImplementationContextTest { | |||
serverSettings.setProperty("prop", "1,3.4,8,50"); | |||
when(settingsRepository.getSettings(FILE_1)).thenReturn(serverSettings); | |||
MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF); | |||
MeasureComputerContextImpl underTest = newContext(FILE_1_REF); | |||
assertThat(underTest.getSettings().getStringArray("prop")).containsExactly("1", "3.4", "8", "50"); | |||
assertThat(underTest.getSettings().getStringArray("unknown")).isEmpty(); | |||
} | |||
@@ -128,7 +126,7 @@ public class MeasureComputerImplementationContextTest { | |||
public void get_measure() throws Exception { | |||
measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10)); | |||
MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF, of(NCLOC_KEY), of(COMMENT_LINES_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(FILE_1_REF, NCLOC_KEY, COMMENT_LINES_KEY); | |||
assertThat(underTest.getMeasure(NCLOC_KEY).getIntValue()).isEqualTo(10); | |||
} | |||
@@ -137,7 +135,7 @@ public class MeasureComputerImplementationContextTest { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("Only metrics in [another metric] can be used to load measures"); | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of("another metric"), of("debt")); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, "another metric", "debt"); | |||
underTest.getMeasure(NCLOC_KEY); | |||
} | |||
@@ -146,7 +144,7 @@ public class MeasureComputerImplementationContextTest { | |||
measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10)); | |||
measureRepository.addRawMeasure(FILE_2_REF, NCLOC_KEY, newMeasureBuilder().create(12)); | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(COMMENT_LINES_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, COMMENT_LINES_KEY); | |||
assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).hasSize(2); | |||
assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).extracting("intValue").containsOnly(10, 12); | |||
} | |||
@@ -156,7 +154,7 @@ public class MeasureComputerImplementationContextTest { | |||
measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10)); | |||
// No data on file 2 | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(COMMENT_LINES_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, COMMENT_LINES_KEY); | |||
assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).extracting("intValue").containsOnly(10); | |||
} | |||
@@ -164,7 +162,7 @@ public class MeasureComputerImplementationContextTest { | |||
public void not_fail_to_get_children_measures_on_output_metric() throws Exception { | |||
measureRepository.addRawMeasure(FILE_1_REF, INT_METRIC_KEY, newMeasureBuilder().create(10)); | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(INT_METRIC_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, INT_METRIC_KEY); | |||
assertThat(underTest.getChildrenMeasures(INT_METRIC_KEY)).hasSize(1); | |||
assertThat(underTest.getChildrenMeasures(INT_METRIC_KEY)).extracting("intValue").containsOnly(10); | |||
} | |||
@@ -174,13 +172,13 @@ public class MeasureComputerImplementationContextTest { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("Only metrics in [another metric] can be used to load measures"); | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of("another metric"), of("debt")); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, "another metric", "debt"); | |||
underTest.getChildrenMeasures(NCLOC_KEY); | |||
} | |||
@Test | |||
public void add_int_measure_create_measure_of_type_int_with_right_value() throws Exception { | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(INT_METRIC_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, INT_METRIC_KEY); | |||
underTest.addMeasure(INT_METRIC_KEY, 10); | |||
Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_KEY); | |||
@@ -190,7 +188,7 @@ public class MeasureComputerImplementationContextTest { | |||
@Test | |||
public void add_double_measure_create_measure_of_type_double_with_right_value() throws Exception { | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(DOUBLE_METRIC_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, DOUBLE_METRIC_KEY); | |||
underTest.addMeasure(DOUBLE_METRIC_KEY, 10d); | |||
Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, DOUBLE_METRIC_KEY); | |||
@@ -200,7 +198,7 @@ public class MeasureComputerImplementationContextTest { | |||
@Test | |||
public void add_long_measure_create_measure_of_type_long_with_right_value() throws Exception { | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(LONG_METRIC_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, LONG_METRIC_KEY); | |||
underTest.addMeasure(LONG_METRIC_KEY, 10L); | |||
Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, LONG_METRIC_KEY); | |||
@@ -210,7 +208,7 @@ public class MeasureComputerImplementationContextTest { | |||
@Test | |||
public void add_string_measure_create_measure_of_type_string_with_right_value() throws Exception { | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(STRING_METRIC_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, STRING_METRIC_KEY); | |||
underTest.addMeasure(STRING_METRIC_KEY, "data"); | |||
Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, STRING_METRIC_KEY); | |||
@@ -223,7 +221,7 @@ public class MeasureComputerImplementationContextTest { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("Only metrics in [int_metric_key] can be used to add measures. Metric 'double_metric_key' is not allowed."); | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(INT_METRIC_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, INT_METRIC_KEY); | |||
underTest.addMeasure(DOUBLE_METRIC_KEY, 10); | |||
} | |||
@@ -234,7 +232,7 @@ public class MeasureComputerImplementationContextTest { | |||
measureRepository.addRawMeasure(FILE_1_REF, INT_METRIC_KEY, newMeasureBuilder().create(20)); | |||
MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF, of(NCLOC_KEY), of(INT_METRIC_KEY)); | |||
MeasureComputerContextImpl underTest = newContext(FILE_1_REF, NCLOC_KEY, INT_METRIC_KEY); | |||
underTest.addMeasure(INT_METRIC_KEY, 10); | |||
} | |||
@@ -248,7 +246,7 @@ public class MeasureComputerImplementationContextTest { | |||
.setResolution("FIXED") | |||
.setDebt(Duration.create(10l)); | |||
MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, Arrays.asList(issue)); | |||
MeasureComputerContextImpl underTest = newContext(PROJECT_REF, Arrays.asList(issue)); | |||
assertThat(underTest.getIssues()).hasSize(1); | |||
org.sonar.api.ce.measure.Issue result = underTest.getIssues().get(0); | |||
@@ -260,37 +258,29 @@ public class MeasureComputerImplementationContextTest { | |||
assertThat(result.debt()).isEqualTo(Duration.create(10l)); | |||
} | |||
private MeasureComputer.Implementation.Context newContext(int componentRef) { | |||
return newContext(componentRef, Collections.<String>emptySet(), Collections.<String>emptySet()); | |||
private MeasureComputerContextImpl newContext(int componentRef) { | |||
return newContext(componentRef, NCLOC_KEY, COMMENT_LINES_KEY, Collections.<DefaultIssue>emptyList()); | |||
} | |||
private MeasureComputer.Implementation.Context newContext(int componentRef, List<DefaultIssue> issues) { | |||
return newContext(componentRef, Collections.<String>emptySet(), Collections.<String>emptySet(), issues); | |||
private MeasureComputerContextImpl newContext(int componentRef, List<DefaultIssue> issues) { | |||
return newContext(componentRef, NCLOC_KEY, COMMENT_LINES_KEY, issues); | |||
} | |||
private MeasureComputer.Implementation.Context newContext(int componentRef, final Set<String> inputMetrics, final Set<String> outputMetrics) { | |||
return newContext(componentRef, inputMetrics, outputMetrics, Collections.<DefaultIssue>emptyList()); | |||
private MeasureComputerContextImpl newContext(int componentRef, String inputMetric, String outputMetric) { | |||
return newContext(componentRef, inputMetric, outputMetric, Collections.<DefaultIssue>emptyList()); | |||
} | |||
private MeasureComputer.Implementation.Context newContext(int componentRef, final Set<String> inputMetrics, final Set<String> outputMetrics, List<DefaultIssue> issues) { | |||
private MeasureComputerContextImpl newContext(int componentRef, String inputMetric, String outputMetric, List<DefaultIssue> issues) { | |||
componentIssuesRepository.setIssues(componentRef, issues); | |||
MeasureComputer measureComputer = new MeasureComputer() { | |||
@Override | |||
public Set<String> getInputMetrics() { | |||
return inputMetrics; | |||
} | |||
@Override | |||
public Set<String> getOutputMetrics() { | |||
return outputMetrics; | |||
} | |||
@Override | |||
public Implementation getImplementation() { | |||
return null; | |||
} | |||
}; | |||
return new MeasureComputerImplementationContext(treeRootHolder.getComponentByRef(componentRef), measureComputer, | |||
MeasureComputer.MeasureComputerDefinition definition = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics(new String[] {inputMetric}) | |||
.setOutputMetrics(new String[] {outputMetric}) | |||
.build(); | |||
MeasureComputerContextImpl context = new MeasureComputerContextImpl(treeRootHolder.getComponentByRef(componentRef), | |||
settingsRepository, measureRepository, metricRepository, componentIssuesRepository); | |||
context.setDefinition(definition); | |||
return context; | |||
} | |||
} |
@@ -27,59 +27,42 @@ import org.sonar.api.ce.measure.MeasureComputer; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class MeasureComputerImplTest { | |||
private static final MeasureComputer.Implementation DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION = new MeasureComputer.Implementation() { | |||
@Override | |||
public void compute(MeasureComputer.Implementation.Context ctx) { | |||
// Nothing here for this test | |||
} | |||
@Override | |||
public String toString() { | |||
return "Test implementation"; | |||
} | |||
}; | |||
public class MeasureComputerDefinitionImplTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@Test | |||
public void build_measure_computer() throws Exception { | |||
public void build_measure_computer_definition() throws Exception { | |||
String inputMetric = "ncloc"; | |||
String outputMetric = "comment_density"; | |||
MeasureComputer measureComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
MeasureComputer.MeasureComputerDefinition measureComputer = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics(inputMetric) | |||
.setOutputMetrics(outputMetric) | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build(); | |||
assertThat(measureComputer.getInputMetrics()).containsOnly(inputMetric); | |||
assertThat(measureComputer.getOutputMetrics()).containsOnly(outputMetric); | |||
assertThat(measureComputer.getImplementation()).isEqualTo(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION); | |||
} | |||
@Test | |||
public void build_measure_computer_with_multiple_metrics() throws Exception { | |||
String[] inputMetrics = {"ncloc", "comment"}; | |||
String[] outputMetrics = {"comment_density_1", "comment_density_2"}; | |||
MeasureComputer measureComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
MeasureComputer.MeasureComputerDefinition measureComputer = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics(inputMetrics) | |||
.setOutputMetrics(outputMetrics) | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build(); | |||
assertThat(measureComputer.getInputMetrics()).containsOnly(inputMetrics); | |||
assertThat(measureComputer.getOutputMetrics()).containsOnly(outputMetrics); | |||
assertThat(measureComputer.getImplementation()).isEqualTo(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION); | |||
} | |||
@Test | |||
public void input_metrics_can_be_empty() throws Exception { | |||
MeasureComputer measureComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
MeasureComputer.MeasureComputerDefinition measureComputer = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics() | |||
.setOutputMetrics("comment_density_1", "comment_density_2") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build(); | |||
assertThat(measureComputer.getInputMetrics()).isEmpty(); | |||
@@ -87,9 +70,8 @@ public class MeasureComputerImplTest { | |||
@Test | |||
public void input_metrics_is_empty_when_not_set() throws Exception { | |||
MeasureComputer measureComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
MeasureComputer.MeasureComputerDefinition measureComputer = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setOutputMetrics("comment_density_1", "comment_density_2") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build(); | |||
assertThat(measureComputer.getInputMetrics()).isEmpty(); | |||
@@ -100,10 +82,9 @@ public class MeasureComputerImplTest { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("Input metrics cannot be null"); | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics(null) | |||
.setOutputMetrics("comment_density_1", "comment_density_2") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION); | |||
.setOutputMetrics("comment_density_1", "comment_density_2"); | |||
} | |||
@Test | |||
@@ -111,32 +92,29 @@ public class MeasureComputerImplTest { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("Null metric is not allowed"); | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("ncloc", null) | |||
.setOutputMetrics("comment_density_1", "comment_density_2") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION); | |||
.setOutputMetrics("comment_density_1", "comment_density_2"); | |||
} | |||
@Test | |||
public void fail_with_IAE_when_no_output_metrics() throws Exception { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("At least one output metric must be defined"); | |||
public void fail_with_NPE_when_no_output_metrics() throws Exception { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("Output metrics cannot be null"); | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("ncloc", "comment") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build(); | |||
} | |||
@Test | |||
public void fail_with_IAE_when_null_output_metrics() throws Exception { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("At least one output metric must be defined"); | |||
public void fail_with_NPE_when_null_output_metrics() throws Exception { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("Output metrics cannot be null"); | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("ncloc", "comment") | |||
.setOutputMetrics(null) | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION); | |||
.setOutputMetrics(null); | |||
} | |||
@Test | |||
@@ -144,10 +122,9 @@ public class MeasureComputerImplTest { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("Null metric is not allowed"); | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("ncloc", "comment") | |||
.setOutputMetrics("comment_density_1", null) | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION); | |||
.setOutputMetrics("comment_density_1", null); | |||
} | |||
@Test | |||
@@ -155,52 +132,26 @@ public class MeasureComputerImplTest { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("At least one output metric must be defined"); | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
.setInputMetrics("ncloc", "comment") | |||
.setOutputMetrics() | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION); | |||
} | |||
@Test | |||
public void fail_with_IAE_when_no_implementation() throws Exception { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("The implementation is missing"); | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("ncloc", "comment") | |||
.setOutputMetrics("comment_density_1", "comment_density_2") | |||
.build(); | |||
} | |||
@Test | |||
public void fail_with_IAE_when_null_implementation() throws Exception { | |||
thrown.expect(NullPointerException.class); | |||
thrown.expectMessage("The implementation is missing"); | |||
new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
.setInputMetrics("ncloc", "comment") | |||
.setOutputMetrics("comment_density_1", "comment_density_2") | |||
.setImplementation(null); | |||
.setOutputMetrics(); | |||
} | |||
@Test | |||
public void test_equals_and_hashcode() throws Exception { | |||
MeasureComputer computer = new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
MeasureComputer.MeasureComputerDefinition computer = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("ncloc", "comment") | |||
.setOutputMetrics("comment_density_1", "comment_density_2") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build(); | |||
MeasureComputer sameComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
MeasureComputer.MeasureComputerDefinition sameComputer = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("comment", "ncloc") | |||
.setOutputMetrics("comment_density_2", "comment_density_1") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build(); | |||
MeasureComputer anotherComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
MeasureComputer.MeasureComputerDefinition anotherComputer = new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("comment") | |||
.setOutputMetrics("debt") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build(); | |||
assertThat(computer).isEqualTo(computer); | |||
@@ -215,11 +166,11 @@ public class MeasureComputerImplTest { | |||
@Test | |||
public void test_to_string() throws Exception { | |||
assertThat(new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
assertThat(new MeasureComputerDefinitionImpl.BuilderImpl() | |||
.setInputMetrics("ncloc", "comment") | |||
.setOutputMetrics("comment_density_1", "comment_density_2") | |||
.setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION) | |||
.build().toString()) | |||
.isEqualTo("MeasureComputerImpl{inputMetricKeys=[ncloc, comment], outputMetrics=[comment_density_1, comment_density_2], implementation=Test implementation}"); | |||
.isEqualTo("MeasureComputerDefinitionImpl{inputMetricKeys=[ncloc, comment], outputMetrics=[comment_density_1, comment_density_2]}"); | |||
} | |||
} |
@@ -1,153 +0,0 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.api; | |||
import com.google.common.collect.ImmutableSet; | |||
import java.util.Collections; | |||
import java.util.Set; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class MeasureComputerProviderContextTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
MeasureComputerProviderContext underTest = new MeasureComputerProviderContext(); | |||
@Test | |||
public void return_empty_list() throws Exception { | |||
assertThat(underTest.getMeasureComputers()).isEmpty(); | |||
} | |||
@Test | |||
public void add_measure_computer() throws Exception { | |||
underTest.add(newMeasureComputer("debt_density")); | |||
assertThat(underTest.getMeasureComputers()).hasSize(1); | |||
} | |||
@Test | |||
public void add_measure_computers_sharing_same_input_metrics() throws Exception { | |||
underTest.add(newMeasureComputer(new String[]{"ncloc"}, new String[]{"debt_density"})); | |||
underTest.add(newMeasureComputer(new String[]{"ncloc"}, new String[]{"comment"})); | |||
assertThat(underTest.getMeasureComputers()).hasSize(2); | |||
} | |||
@Test | |||
public void fail_with_unsupported_operation_exception_when_output_metric_have_already_been_registered() throws Exception { | |||
thrown.expect(UnsupportedOperationException.class); | |||
thrown.expectMessage("The output metric 'debt_density' is already declared by another computer. This computer has these input metrics '[ncloc, debt]' and these output metrics '[debt_by_line, debt_density]"); | |||
underTest.add(newMeasureComputer("debt_by_line","debt_density")); | |||
underTest.add(newMeasureComputer("total_debt", "debt_density")); | |||
} | |||
@Test | |||
public void fail_with_unsupported_operation_exception_when_multiple_output_metrics_have_already_been_registered() throws Exception { | |||
thrown.expect(UnsupportedOperationException.class); | |||
thrown.expectMessage("The output metric 'debt_density' is already declared by another computer. This computer has these input metrics '[ncloc, debt]' and these output metrics '[debt_density]'. " + | |||
"The output metric 'debt_by_line' is already declared by another computer. This computer has these input metrics '[ncloc, debt]' and these output metrics '[debt_by_line]"); | |||
underTest.add(newMeasureComputer("debt_by_line")); | |||
underTest.add(newMeasureComputer("debt_density")); | |||
underTest.add(newMeasureComputer("debt_by_line", "debt_density")); | |||
} | |||
@Test | |||
public void create_measure_computer_without_using_the_builder() throws Exception { | |||
// Create a instance of MeasureComputer without using the builder | |||
MeasureComputer measureComputer = new MeasureComputer() { | |||
@Override | |||
public Set<String> getInputMetrics() { | |||
return ImmutableSet.of("ncloc", "debt"); | |||
} | |||
@Override | |||
public Set<String> getOutputMetrics() { | |||
return ImmutableSet.of("debt_density"); | |||
} | |||
@Override | |||
public Implementation getImplementation() { | |||
return new MeasureComputer.Implementation() { | |||
@Override | |||
public void compute(Context ctx) { | |||
} | |||
}; | |||
} | |||
}; | |||
underTest.add(measureComputer); | |||
assertThat(underTest.getMeasureComputers()).hasSize(1); | |||
} | |||
@Test | |||
public void fail_with_IAE_when_creating_measure_computer_without_using_the_builder_but_with_invalid_output_metrics() throws Exception { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("At least one output metric must be defined"); | |||
MeasureComputer measureComputer = new MeasureComputer() { | |||
@Override | |||
public Set<String> getInputMetrics() { | |||
return ImmutableSet.of("ncloc", "debt"); | |||
} | |||
@Override | |||
public Set<String> getOutputMetrics() { | |||
return Collections.emptySet(); | |||
} | |||
@Override | |||
public Implementation getImplementation() { | |||
return new MeasureComputer.Implementation() { | |||
@Override | |||
public void compute(Context ctx) {} | |||
}; | |||
} | |||
}; | |||
underTest.add(measureComputer); | |||
} | |||
private MeasureComputer newMeasureComputer(String... outputMetrics) { | |||
return newMeasureComputer(new String[]{"ncloc", "debt"}, outputMetrics); | |||
} | |||
private MeasureComputer newMeasureComputer(String[] inputMetrics, String[] outputMetrics) { | |||
return new MeasureComputerImpl.MeasureComputerBuilderImpl() | |||
.setInputMetrics(inputMetrics) | |||
.setOutputMetrics(outputMetrics) | |||
.setImplementation(new MeasureComputer.Implementation() { | |||
@Override | |||
public void compute(Context ctx) { | |||
// Nothing to do here for this test | |||
} | |||
}) | |||
.build(); | |||
} | |||
} |
@@ -20,22 +20,24 @@ | |||
package org.sonar.server.computation.step; | |||
import com.google.common.collect.ImmutableSet; | |||
import com.google.common.collect.Lists; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Set; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.ce.measure.MeasureComputer; | |||
import org.sonar.api.ce.measure.MeasureComputerProvider; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.measures.Metrics; | |||
import org.sonar.server.computation.measure.MeasureComputersHolderImpl; | |||
import org.sonar.server.computation.measure.api.MeasureComputerWrapper; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.util.Arrays.array; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; | |||
import static org.sonar.api.measures.Metric.ValueType.DATA; | |||
import static org.sonar.api.measures.Metric.ValueType.FLOAT; | |||
import static org.sonar.api.measures.Metric.ValueType.INT; | |||
@@ -55,14 +57,8 @@ public class FeedMeasureComputersTest { | |||
@Test | |||
public void support_core_metrics_as_input_metrics() throws Exception { | |||
MeasureComputer.Implementation implementation = mock(MeasureComputer.Implementation.class); | |||
MeasureComputerProvider[] providers = new MeasureComputerProvider[] { | |||
new NewMeasureComputerProvider( | |||
array(CoreMetrics.NCLOC_KEY), | |||
array(NEW_METRIC_1), | |||
implementation), | |||
}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers); | |||
MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NCLOC_KEY), array(NEW_METRIC_1))}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
assertThat(holder.getMeasureComputers()).hasSize(1); | |||
@@ -70,14 +66,8 @@ public class FeedMeasureComputersTest { | |||
@Test | |||
public void support_plugin_metrics_as_input_metrics() throws Exception { | |||
MeasureComputer.Implementation implementation = mock(MeasureComputer.Implementation.class); | |||
MeasureComputerProvider[] providers = new MeasureComputerProvider[] { | |||
new NewMeasureComputerProvider( | |||
array(NEW_METRIC_1), | |||
array(NEW_METRIC_2), | |||
implementation), | |||
}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers); | |||
MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NEW_METRIC_1), array(NEW_METRIC_2))}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
assertThat(holder.getMeasureComputers()).hasSize(1); | |||
@@ -85,64 +75,78 @@ public class FeedMeasureComputersTest { | |||
@Test | |||
public void sort_computers() throws Exception { | |||
MeasureComputer.Implementation implementation1 = mock(MeasureComputer.Implementation.class); | |||
MeasureComputer.Implementation implementation2 = mock(MeasureComputer.Implementation.class); | |||
MeasureComputer.Implementation implementation3 = mock(MeasureComputer.Implementation.class); | |||
MeasureComputerProvider[] providers = new MeasureComputerProvider[] { | |||
// Should be the last to be executed | |||
new NewMeasureComputerProvider( | |||
array(NEW_METRIC_3), | |||
array(NEW_METRIC_4), | |||
implementation3), | |||
// Should be the first to be executed | |||
new NewMeasureComputerProvider( | |||
array(NEW_METRIC_1), | |||
array(NEW_METRIC_2), | |||
implementation1), | |||
// Should be the second to be executed | |||
new NewMeasureComputerProvider( | |||
array(NEW_METRIC_2), | |||
array(NEW_METRIC_3), | |||
implementation2) | |||
}; | |||
// Should be the last to be executed | |||
MeasureComputer measureComputer1 = newMeasureComputer(array(NEW_METRIC_3), array(NEW_METRIC_4)); | |||
// Should be the first to be executed | |||
MeasureComputer measureComputer2 = newMeasureComputer(array(NEW_METRIC_1), array(NEW_METRIC_2)); | |||
// Should be the second to be executed | |||
MeasureComputer measureComputer3 = newMeasureComputer(array(NEW_METRIC_2), array(NEW_METRIC_3)); | |||
MeasureComputer[] computers = new MeasureComputer[] {measureComputer1, measureComputer2, measureComputer3}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
List<MeasureComputerWrapper> result = newArrayList(holder.getMeasureComputers()); | |||
assertThat(result).hasSize(3); | |||
assertThat(result.get(0).getComputer()).isEqualTo(measureComputer2); | |||
assertThat(result.get(1).getComputer()).isEqualTo(measureComputer3); | |||
assertThat(result.get(2).getComputer()).isEqualTo(measureComputer1); | |||
} | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers); | |||
@Test | |||
public void sort_computers_when_one_computer_has_no_input_metric() throws Exception { | |||
// Should be the last to be executed | |||
MeasureComputer measureComputer1 = newMeasureComputer(array(NEW_METRIC_3), array(NEW_METRIC_4)); | |||
// Should be the first to be executed | |||
MeasureComputer measureComputer2 = newMeasureComputer(new String[] {}, array(NEW_METRIC_2)); | |||
// Should be the second to be executed | |||
MeasureComputer measureComputer3 = newMeasureComputer(array(NEW_METRIC_2), array(NEW_METRIC_3)); | |||
MeasureComputer[] computers = new MeasureComputer[] {measureComputer1, measureComputer2, measureComputer3}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
List<MeasureComputer> computers = newArrayList(holder.getMeasureComputers()); | |||
assertThat(computers).hasSize(3); | |||
assertThat(computers.get(0).getImplementation()).isEqualTo(implementation1); | |||
assertThat(computers.get(1).getImplementation()).isEqualTo(implementation2); | |||
assertThat(computers.get(2).getImplementation()).isEqualTo(implementation3); | |||
List<MeasureComputerWrapper> result = newArrayList(holder.getMeasureComputers()); | |||
assertThat(result).hasSize(3); | |||
assertThat(result.get(0).getComputer()).isEqualTo(measureComputer2); | |||
assertThat(result.get(1).getComputer()).isEqualTo(measureComputer3); | |||
assertThat(result.get(2).getComputer()).isEqualTo(measureComputer1); | |||
} | |||
@Test | |||
public void fail_with_ISE_when_input_metric_is_unknown() throws Exception { | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("Metric 'unknown' cannot be used as an input metric as it's no a core metric and no plugin declare this metric"); | |||
thrown.expectMessage("Metric 'unknown' cannot be used as an input metric as it's not a core metric and no plugin declare this metric"); | |||
MeasureComputerProvider[] providers = new MeasureComputerProvider[] { | |||
new NewMeasureComputerProvider( | |||
array("unknown"), | |||
array(NEW_METRIC_4), | |||
mock(MeasureComputer.Implementation.class)), | |||
}; | |||
MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array("unknown"), array(NEW_METRIC_4))}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
} | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers); | |||
@Test | |||
public void fail_with_ISE_when_output_metric_is_not_define_by_plugin() throws Exception { | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("Metric 'unknown' cannot be used as an output metric as no plugin declare this metric"); | |||
MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NEW_METRIC_4), array("unknown"))}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void fail_with_ISE_when_output_metric_is_a_core_metric() throws Exception { | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("Metric 'ncloc' cannot be used as an output metric as it's a core metric"); | |||
MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NEW_METRIC_4), array(NCLOC_KEY))}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void not_fail_if_input_metrics_are_same_as_output_metrics() throws Exception { | |||
MeasureComputer.Implementation implementation = mock(MeasureComputer.Implementation.class); | |||
MeasureComputerProvider[] providers = new MeasureComputerProvider[] { | |||
new NewMeasureComputerProvider( | |||
array(NEW_METRIC_1), | |||
array(NEW_METRIC_1), | |||
implementation), | |||
}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers); | |||
MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NEW_METRIC_1), array(NEW_METRIC_1))}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
assertThat(holder.getMeasureComputers()).hasSize(1); | |||
@@ -156,21 +160,6 @@ public class FeedMeasureComputersTest { | |||
assertThat(holder.getMeasureComputers()).isEmpty(); | |||
} | |||
@Test | |||
public void support_no_plugin_metrics() throws Exception { | |||
MeasureComputer.Implementation implementation = mock(MeasureComputer.Implementation.class); | |||
MeasureComputerProvider[] providers = new MeasureComputerProvider[] { | |||
new NewMeasureComputerProvider( | |||
array(CoreMetrics.NCLOC_KEY), | |||
array(CoreMetrics.COMMENT_LINES_KEY), | |||
implementation), | |||
}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, providers); | |||
underTest.execute(); | |||
assertThat(holder.getMeasureComputers()).hasSize(1); | |||
} | |||
@Test | |||
public void return_empty_list_when_no_metrics_neither_measure_computers() throws Exception { | |||
ComputationStep underTest = new FeedMeasureComputers(holder); | |||
@@ -179,26 +168,65 @@ public class FeedMeasureComputersTest { | |||
assertThat(holder.getMeasureComputers()).isEmpty(); | |||
} | |||
private static class NewMeasureComputerProvider implements MeasureComputerProvider { | |||
@Test | |||
public void fail_with_ISE_when_no_metrics_are_defined_by_plugin_but_measure_computer_use_a_new_metric() throws Exception { | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("Metric 'metric1' cannot be used as an output metric as no plugin declare this metric"); | |||
MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NCLOC_KEY), array(NEW_METRIC_1))}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, computers); | |||
underTest.execute(); | |||
} | |||
private final String[] inputMetrics; | |||
private final String[] outputMetrics; | |||
private final MeasureComputer.Implementation measureComputerImplementation; | |||
@Test | |||
public void fail_with_IAE_when_creating_measure_computer_definition_without_using_the_builder_and_with_invalid_output_metrics() throws Exception { | |||
thrown.expect(IllegalArgumentException.class); | |||
thrown.expectMessage("At least one output metric must be defined"); | |||
MeasureComputer measureComputer = new MeasureComputer() { | |||
@Override | |||
public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) { | |||
// Create a instance of MeasureComputerDefinition without using the builder | |||
return new MeasureComputer.MeasureComputerDefinition(){ | |||
@Override | |||
public Set<String> getInputMetrics() { | |||
return ImmutableSet.of(NCLOC_KEY); | |||
} | |||
@Override | |||
public Set<String> getOutputMetrics() { | |||
// Empty output metric is not allowed ! | |||
return Collections.emptySet(); | |||
} | |||
}; | |||
} | |||
@Override | |||
public void compute(MeasureComputerContext context) { | |||
// Nothing needs to be done as we're only testing metada | |||
} | |||
}; | |||
public NewMeasureComputerProvider(String[] inputMetrics, String[] outputMetrics, MeasureComputer.Implementation measureComputerImplementation) { | |||
this.inputMetrics = inputMetrics; | |||
this.outputMetrics = outputMetrics; | |||
this.measureComputerImplementation = measureComputerImplementation; | |||
} | |||
MeasureComputer[] computers = new MeasureComputer[] {measureComputer}; | |||
ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers); | |||
underTest.execute(); | |||
} | |||
@Override | |||
public void register(Context ctx) { | |||
ctx.add(ctx.newMeasureComputerBuilder() | |||
.setInputMetrics(inputMetrics) | |||
.setOutputMetrics(outputMetrics) | |||
.setImplementation(measureComputerImplementation) | |||
.build()); | |||
} | |||
private static MeasureComputer newMeasureComputer(final String[] inputMetrics, final String[] outputMetrics) { | |||
return new MeasureComputer() { | |||
@Override | |||
public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) { | |||
return defContext.newDefinitionBuilder() | |||
.setInputMetrics(inputMetrics) | |||
.setOutputMetrics(outputMetrics) | |||
.build(); | |||
} | |||
@Override | |||
public void compute(MeasureComputerContext context) { | |||
// Nothing needs to be done as we're only testing metada | |||
} | |||
}; | |||
} | |||
private static class TestMetrics implements Metrics { |
@@ -24,8 +24,7 @@ import org.sonar.api.resources.Resource; | |||
/** | |||
* @since 1.10 | |||
* @deprecated since 5.2 there's no more decorator on batch side | |||
* TODO add link to new API | |||
* @deprecated since 5.2 there's no more decorator on batch side. Use {@link org.sonar.api.ce.measure.MeasureComputer} instead | |||
*/ | |||
@BatchSide | |||
@ExtensionPoint |
@@ -22,6 +22,11 @@ package org.sonar.api.ce.measure; | |||
import javax.annotation.CheckForNull; | |||
/** | |||
* Component that can be used in a {@link MeasureComputer} | |||
* | |||
* @since 5.2 | |||
*/ | |||
public interface Component { | |||
enum Type { |
@@ -24,6 +24,11 @@ import javax.annotation.CheckForNull; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.utils.Duration; | |||
/** | |||
* Issue that can be used in a {@link MeasureComputer} | |||
* | |||
* @since 5.2 | |||
*/ | |||
public interface Issue { | |||
String key(); |
@@ -20,6 +20,11 @@ | |||
package org.sonar.api.ce.measure; | |||
/** | |||
* Measure used in {@link MeasureComputer} | |||
* | |||
* @since 5.2 | |||
*/ | |||
public interface Measure { | |||
/** |
@@ -23,136 +23,198 @@ package org.sonar.api.ce.measure; | |||
import java.util.List; | |||
import java.util.Set; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.api.ExtensionPoint; | |||
import org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition.Builder; | |||
import org.sonar.api.server.ServerSide; | |||
/** | |||
* This class is used to define which metrics are required to compute some measures on some given metrics, and to define the implementation of the measures computation | |||
* Define how to compute new measures on some metrics declared by {@link org.sonar.api.measures.Metrics}. | |||
* <p/> | |||
* This interface replaces the deprecated class org.sonar.api.batch.Decorator. | |||
* <p/> | |||
* <h3>How to use</h3> | |||
* <pre> | |||
* public class MyMeasureComputer implements MeasureComputer { | |||
* | |||
* {@literal @}Override | |||
* public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) { | |||
* return defContext.newDefinitionBuilder() | |||
* | |||
* // Input metrics can be empty, for instance if only issues will be read | |||
* .setInputMetrics("ncloc") | |||
* | |||
* // Output metrics must contains at least one metric | |||
* .setOutputMetrics("my_new_metric") | |||
* | |||
* .build(); | |||
* } | |||
* | |||
* {@literal @}Override | |||
* public void compute(MeasureComputerContext context) { | |||
* int ncloc = context.getMeasure("ncloc"); | |||
* List<Issue> issues = context.getIssues(); | |||
* if (ncloc != null && !issues.isEmpty()) { | |||
* double value = issues.size() / ncloc; | |||
* context.addMeasure("my_new_metric", value); | |||
* } | |||
* } | |||
* } | |||
* </pre> | |||
* <p/> | |||
* <h3>How to test</h3> | |||
* <pre> | |||
* public class MyMeasureComputerTest { | |||
* | |||
* MyMeasureComputer underTest = new MyMeasureComputer(); | |||
* | |||
* @Test | |||
* public void test_definition() { | |||
* TestMeasureComputerDefinitionContext defContext = new TestMeasureComputerDefinitionContext(); | |||
* MeasureComputerDefinition def = underTest.define(defContext); | |||
* assertThat(def).isNotNull(); | |||
* assertThat(def.getInputMetrics()).containsOnly("ncloc"); | |||
* assertThat(def.getOutputMetrics()).containsOnly("my_new_metric"); | |||
* } | |||
* | |||
* @Test | |||
* public void sum_ncloc_and_issues() { | |||
* TestMeasureComputerContext context = new TestMeasureComputerContext(underTest); | |||
* context.addMeasure("ncloc", 2); | |||
* context.setIssues(Arrays.asList(new TestIssue.Builder().setKey("ABCD").build())); | |||
* underTest.compute(context); | |||
* | |||
* assertThat(context.getMeasureValue("my_new_metric")).isEqualTo(0.5); | |||
* } | |||
* </pre> | |||
* | |||
* @since 5.2 | |||
*/ | |||
@ServerSide | |||
@ExtensionPoint | |||
public interface MeasureComputer { | |||
/** | |||
* Return the metric keys that can be read using {@link Implementation.Context}. | |||
* | |||
* Can never be empty as it's checked in the builder | |||
* Use to define which metrics are required to compute some measures on some given metrics | |||
*/ | |||
Set<String> getInputMetrics(); | |||
MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext); | |||
/** | |||
* Return the metric keys that can be create using {@link Implementation.Context}. | |||
* | |||
* Can never ne empty as it's checked om the builder | |||
* Context specific to the definition of the measure computer | |||
*/ | |||
Set<String> getOutputMetrics(); | |||
Implementation getImplementation(); | |||
interface MeasureComputerBuilder { | |||
/** | |||
* Input metrics can be empty (for instance when only issues are needed) | |||
* @throws NullPointerException if inputMetrics is null | |||
* @throws NullPointerException if the metrics contains a {@code null} | |||
* */ | |||
MeasureComputerBuilder setInputMetrics(String... inputMetrics); | |||
interface MeasureComputerDefinitionContext { | |||
Builder newDefinitionBuilder(); | |||
} | |||
interface MeasureComputerDefinition { | |||
/** | |||
* @throws IllegalArgumentException if there's not at least one output metrics | |||
* @throws NullPointerException if the metrics contains a {@code null} | |||
* Return the metric keys that can be read using {@link MeasureComputerContext}. | |||
* Can be empty for instance when the computer only need to access to issues. | |||
*/ | |||
MeasureComputerBuilder setOutputMetrics(String... outMetrics); | |||
Set<String> getInputMetrics(); | |||
/** | |||
* @throws NullPointerException if there's no implementation | |||
* Return the metric keys that can be create using {@link MeasureComputerContext}. | |||
* Can never ne empty. | |||
*/ | |||
MeasureComputerBuilder setImplementation(Implementation impl); | |||
Set<String> getOutputMetrics(); | |||
/** | |||
* @throws NullPointerException if inputMetrics is null | |||
* @throws NullPointerException if inputs metrics contains a {@code null} | |||
* @throws IllegalArgumentException if there's not at least one output metrics | |||
* @throws NullPointerException if outputs metrics contains a {@code null} | |||
* @throws NullPointerException if there's no implementation | |||
*/ | |||
MeasureComputer build(); | |||
interface Builder { | |||
/** | |||
* Input metrics can be empty (for instance when only issues are needed) | |||
* @throws NullPointerException if inputMetrics is null | |||
* @throws NullPointerException if the metrics contains a {@code null} | |||
* */ | |||
Builder setInputMetrics(String... inputMetrics); | |||
/** | |||
* @throws NullPointerException if outputMetrics is null | |||
* @throws IllegalArgumentException if there's not at least one output metrics | |||
* @throws NullPointerException if the metrics contains a {@code null} | |||
*/ | |||
Builder setOutputMetrics(String... outputMetrics); | |||
/** | |||
* @throws NullPointerException if inputMetrics is null | |||
* @throws NullPointerException if inputs metrics contains a {@code null} | |||
* @throws NullPointerException if outputMetrics is null | |||
* @throws IllegalArgumentException if there's not at least one output metrics | |||
* @throws NullPointerException if outputs metrics contains a {@code null} | |||
*/ | |||
MeasureComputerDefinition build(); | |||
} | |||
} | |||
/** | |||
* This interface must be implemented to define how the measures are computed. | |||
* This method will be called on each component of the projects. | |||
*/ | |||
interface Implementation { | |||
void compute(MeasureComputerContext context); | |||
/** | |||
* Context specific to the computation of the measure(s) of a given component | |||
*/ | |||
interface MeasureComputerContext { | |||
/** | |||
* This method will be called on each component of the projects. | |||
* Returns the current component. | |||
*/ | |||
void compute(Context ctx); | |||
Component getComponent(); | |||
/** | |||
* Context specific to the computation of the measure(s) of a given component | |||
* Returns settings of the current component. | |||
*/ | |||
interface Context { | |||
/** | |||
* Returns the current component. | |||
*/ | |||
Component getComponent(); | |||
Settings getSettings(); | |||
/** | |||
* Returns settings of the current component. | |||
*/ | |||
Settings getSettings(); | |||
/** | |||
* Returns the measure from a given metric on the current component. | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getInputMetrics()} | |||
*/ | |||
@CheckForNull | |||
Measure getMeasure(String metric); | |||
/** | |||
* Returns measures from a given metric on children of the current component. | |||
* It no measure is found for a child, this measure is ignored | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getInputMetrics()} or in {@link MeasureComputer#getOutputMetrics()} | |||
*/ | |||
Iterable<Measure> getChildrenMeasures(String metric); | |||
/** | |||
* Returns the measure from a given metric on the current component. | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getInputMetrics()} | |||
*/ | |||
@CheckForNull | |||
Measure getMeasure(String metric); | |||
/** | |||
* Add a new measure of a given metric which measure type will be int | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getOutputMetrics()} | |||
* @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component | |||
*/ | |||
void addMeasure(String metric, int value); | |||
/** | |||
* Returns measures from a given metric on children of the current component. | |||
* It no measure is found for a child, this measure is ignored | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getInputMetrics()} | |||
* or in {@link MeasureComputerDefinition#getOutputMetrics()} | |||
*/ | |||
Iterable<Measure> getChildrenMeasures(String metric); | |||
/** | |||
* Add a new measure of a given metric which measure type will be double | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getOutputMetrics()} | |||
* @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component | |||
*/ | |||
void addMeasure(String metric, double value); | |||
/** | |||
* Add a new measure of a given metric which measure type will be int | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getOutputMetrics()} | |||
* @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component | |||
*/ | |||
void addMeasure(String metric, int value); | |||
/** | |||
* Add a new measure of a given metric which measure type will be long | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getOutputMetrics()} | |||
* @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component | |||
*/ | |||
void addMeasure(String metric, long value); | |||
/** | |||
* Add a new measure of a given metric which measure type will be double | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getOutputMetrics()} | |||
* @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component | |||
*/ | |||
void addMeasure(String metric, double value); | |||
/** | |||
* Add a new measure of a given metric which measure type will be string | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getOutputMetrics()} | |||
* @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component | |||
*/ | |||
void addMeasure(String metric, String value); | |||
/** | |||
* Add a new measure of a given metric which measure type will be long | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getOutputMetrics()} | |||
* @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component | |||
*/ | |||
void addMeasure(String metric, long value); | |||
/** | |||
* Return list of issues of current component. | |||
*/ | |||
List<? extends Issue> getIssues(); | |||
/** | |||
* Add a new measure of a given metric which measure type will be string | |||
* | |||
* @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getOutputMetrics()} | |||
* @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component | |||
*/ | |||
void addMeasure(String metric, String value); | |||
} | |||
/** | |||
* Return list of all issues (open, closed, etc.) of current component. | |||
*/ | |||
List<? extends Issue> getIssues(); | |||
} | |||
} |
@@ -1,53 +0,0 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.api.ce.measure; | |||
import org.sonar.api.ExtensionPoint; | |||
import org.sonar.api.server.ServerSide; | |||
/** | |||
* This extension point can be used to register {@link MeasureComputer}(s) that will be able to compute measures when a batch report is processed by the Compute Engine | |||
*/ | |||
@ServerSide | |||
@ExtensionPoint | |||
public interface MeasureComputerProvider { | |||
/** | |||
* Use this method to register a new measure computer. | |||
*/ | |||
void register(Context ctx); | |||
interface Context { | |||
/** | |||
* Add a new computer to the context. | |||
* | |||
* @throws UnsupportedOperationException when trying to add a computer providing some measures on metrics already defined by another {@link MeasureComputer} | |||
*/ | |||
Context add(MeasureComputer measureComputer); | |||
/** | |||
* Use this method to build a MeasureComputer to be used in the {@link #add(MeasureComputer)} method | |||
*/ | |||
MeasureComputer.MeasureComputerBuilder newMeasureComputerBuilder(); | |||
} | |||
} |
@@ -37,6 +37,7 @@ import org.sonar.api.utils.KeyValueFormat; | |||
* <p>An example of usage : you wish to record the percentage of lines of code that belong to method | |||
* with pre-defined ranges of complexity.</p> | |||
* | |||
* @since 5.2 | |||
*/ | |||
public class RangeDistributionBuilder { | |||
@@ -23,7 +23,9 @@ package org.sonar.api.ce.measure; | |||
import javax.annotation.CheckForNull; | |||
/** | |||
* Settings of the current component. | |||
* Settings of the current component used in {@link MeasureComputer} | |||
* | |||
* @since 5.2 | |||
*/ | |||
public interface Settings { | |||