From b707f2c2b6a5820496d5ba83ad6e69432512f908 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 1 Sep 2015 10:58:54 +0200 Subject: [PATCH] SONAR-6730 Simplify API --- .../issue/ComponentIssuesRepository.java | 2 +- .../measure/MeasureComputersHolder.java | 4 +- .../measure/MeasureComputersHolderImpl.java | 8 +- .../measure/MeasureComputersVisitor.java | 14 +- .../MutableMeasureComputersHolder.java | 4 +- ...t.java => MeasureComputerContextImpl.java} | 37 ++- ...ava => MeasureComputerDefinitionImpl.java} | 46 +--- .../api/MeasureComputerProviderContext.java | 89 ------ .../measure/api/MeasureComputerWrapper.java | 52 ++++ .../step/FeedMeasureComputers.java | 166 ++++++++---- .../MeasureComputersHolderImplTest.java | 8 +- .../measure/MeasureComputersVisitorTest.java | 46 ++-- ...va => MeasureComputerContextImplTest.java} | 76 +++--- ...=> MeasureComputerDefinitionImplTest.java} | 107 ++------ .../MeasureComputerProviderContextTest.java | 153 ----------- .../step/FeedMeasureComputersTest.java | 216 ++++++++------- .../java/org/sonar/api/batch/Decorator.java | 3 +- .../org/sonar/api/ce/measure/Component.java | 5 + .../java/org/sonar/api/ce/measure/Issue.java | 5 + .../org/sonar/api/ce/measure/Measure.java | 5 + .../sonar/api/ce/measure/MeasureComputer.java | 256 +++++++++++------- .../ce/measure/MeasureComputerProvider.java | 53 ---- .../ce/measure/RangeDistributionBuilder.java | 1 + .../org/sonar/api/ce/measure/Settings.java | 4 +- 24 files changed, 614 insertions(+), 746 deletions(-) rename server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/{MeasureComputerImplementationContext.java => MeasureComputerContextImpl.java} (81%) rename server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/{MeasureComputerImpl.java => MeasureComputerDefinitionImpl.java} (68%) delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerProviderContext.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerWrapper.java rename server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/{MeasureComputerImplementationContextTest.java => MeasureComputerContextImplTest.java} (76%) rename server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/{MeasureComputerImplTest.java => MeasureComputerDefinitionImplTest.java} (55%) delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerProviderContextTest.java delete mode 100644 sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/MeasureComputerProvider.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepository.java index fd8900ce56a..7691503f611 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepository.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepository.java @@ -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. diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersHolder.java index 61a1ac39f33..1abd4233ebe 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersHolder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersHolder.java @@ -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 getMeasureComputers(); + Iterable getMeasureComputers(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersHolderImpl.java index de32f552072..dc58e306860 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersHolderImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersHolderImpl.java @@ -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 measureComputers; + private Iterable measureComputers; @Override - public Iterable getMeasureComputers() { + public Iterable getMeasureComputers() { checkState(this.measureComputers != null, "Measure computers have not been initialized yet"); return measureComputers; } @Override - public void setMeasureComputers(Iterable measureComputers) { + public void setMeasureComputers(Iterable 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(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersVisitor.java index 8998020f111..2424ae21c6f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersVisitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureComputersVisitor.java @@ -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); } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MutableMeasureComputersHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MutableMeasureComputersHolder.java index 1d297ec0f99..0e68d3818b4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MutableMeasureComputersHolder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MutableMeasureComputersHolder.java @@ -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 measureComputers); + void setMeasureComputers(Iterable measureComputers); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerImplementationContext.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerContextImpl.java similarity index 81% rename from server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerImplementationContext.java rename to server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerContextImpl.java index 237846ed193..434e18d1185 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerImplementationContext.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerContextImpl.java @@ -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 componentIssues; - private final Set allowedMetrics; + private MeasureComputerDefinition definition; + private Set 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 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 allowedMetric(MeasureComputerDefinition definition) { Set 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())); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerDefinitionImpl.java similarity index 68% rename from server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerImpl.java rename to server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerDefinitionImpl.java index 1712950e7a0..e4532c49b84 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerDefinitionImpl.java @@ -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 inputMetricKeys; private final Set 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"); } } - } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerProviderContext.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerProviderContext.java deleted file mode 100644 index 27be1a2338d..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerProviderContext.java +++ /dev/null @@ -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 measureComputers = new ArrayList<>(); - private final Map 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 inputMetrics = measureComputer.getInputMetrics(); - Set 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 getMeasureComputers() { - return measureComputers; - } - - private void checkOutputMetricsNotAlreadyDefinedByAnotherComputer(MeasureComputer measureComputer) { - Set duplicated = ImmutableSet.copyOf(Sets.intersection(computerByOutputMetrics.keySet(), measureComputer.getOutputMetrics())); - if (!duplicated.isEmpty()) { - throw new UnsupportedOperationException(generateErrorMsg(duplicated)); - } - } - - private String generateErrorMsg(Set 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(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerWrapper.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerWrapper.java new file mode 100644 index 00000000000..6da2da7d8bb --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/api/MeasureComputerWrapper.java @@ -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(); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedMeasureComputers.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedMeasureComputers.java index 48dc14cbf1e..eff2e6626ab 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedMeasureComputers.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedMeasureComputers.java @@ -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 CORE_METRIC_KEYS = FluentIterable.from(CoreMetrics.getMetrics()).transform(MetricToKey.INSTANCE).toSet(); + private static final Set CORE_METRIC_KEYS = from(CoreMetrics.getMetrics()).transform(MetricToKey.INSTANCE).toSet(); + private Set 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 wrappers = from(Arrays.asList(measureComputers)).transform(ToMeasureWrapper.INSTANCE).toList(); + validateMetrics(wrappers); + measureComputersHolder.setMeasureComputers(sortComputers(wrappers)); } - private static Iterable sortComputers(List computers) { - Map computersByOutputMetric = new HashMap<>(); - Map computersByInputMetric = new HashMap<>(); - feedComputersByMetric(computers, computersByOutputMetric, computersByInputMetric); + private static Iterable sortComputers(List wrappers) { + Map computersByOutputMetric = new HashMap<>(); + Map 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 computers, Map computersByOutputMetric, - Map computersByInputMetric) { - for (MeasureComputer computer : computers) { - for (String outputMetric : computer.getOutputMetrics()) { + private static void feedComputersByMetric(List wrappers, Map computersByOutputMetric, + Map 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 computers) { - Set 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 wrappers) { + from(wrappers).transformAndConcat(ToInputMetrics.INSTANCE).filter(new ValidateInputMetric()).size(); + from(wrappers).transformAndConcat(ToOutputMetrics.INSTANCE).filter(new ValidateOutputMetric()).size(); } - private static Iterable getDependencies(MeasureComputer measureComputer, ToComputerByKey toComputerByOutputMetricKey) { + private static Iterable 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 getDependents(MeasureComputer measureComputer, ToComputerByKey toComputerByInputMetricKey) { - return FluentIterable.from(measureComputer.getInputMetrics()).transform(toComputerByInputMetricKey); + private static Iterable getDependents(MeasureComputerWrapper measureComputer, ToComputerByKey toComputerByInputMetricKey) { + return from(measureComputer.getDefinition().getInputMetrics()).transform(toComputerByInputMetricKey); } - private static class ToComputerByKey implements Function { - private final Map computersByMetric; + private static class ToComputerByKey implements Function { + private final Map computersByMetric; - private ToComputerByKey(Map computersByMetric) { + private ToComputerByKey(Map 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 { + 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 inputMetrics = def.getInputMetrics(); + Set 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> { + INSTANCE; + + @Override + public Collection apply(@Nonnull MeasureComputerWrapper input) { + return input.getDefinition().getInputMetrics(); + } + } + + private class ValidateInputMetric implements Predicate { + @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> { + INSTANCE; + + @Override + public Collection apply(@Nonnull MeasureComputerWrapper input) { + return input.getDefinition().getOutputMetrics(); + } + } + + private class ValidateOutputMetric implements Predicate { + @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"; diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureComputersHolderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureComputersHolderImplTest.java index a42ce3ed72c..83529efa4b0 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureComputersHolderImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureComputersHolderImplTest.java @@ -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.of()); + underTest.setMeasureComputers(ImmutableList.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)); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureComputersVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureComputersVisitorTest.java index 9aa1cac9d2e..da699436f8d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureComputersVisitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureComputersVisitorTest.java @@ -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.asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, measureComputersHolder, componentIssuesRepository))); + VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.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.emptyList()); - VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, measureComputersHolder, componentIssuesRepository))); + measureComputersHolder.setMeasureComputers(Collections.emptyList()); + VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, + measureComputersHolder, componentIssuesRepository))); visitorsCrawler.visit(ROOT); assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).isEmpty(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerImplementationContextTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerContextImplTest.java similarity index 76% rename from server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerImplementationContextTest.java rename to server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerContextImplTest.java index cf4d8b06097..74c2cd64b3a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerImplementationContextTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerContextImplTest.java @@ -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 = 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 = 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 = 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 = 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.emptySet(), Collections.emptySet()); + private MeasureComputerContextImpl newContext(int componentRef) { + return newContext(componentRef, NCLOC_KEY, COMMENT_LINES_KEY, Collections.emptyList()); } - private MeasureComputer.Implementation.Context newContext(int componentRef, List issues) { - return newContext(componentRef, Collections.emptySet(), Collections.emptySet(), issues); + private MeasureComputerContextImpl newContext(int componentRef, List issues) { + return newContext(componentRef, NCLOC_KEY, COMMENT_LINES_KEY, issues); } - private MeasureComputer.Implementation.Context newContext(int componentRef, final Set inputMetrics, final Set outputMetrics) { - return newContext(componentRef, inputMetrics, outputMetrics, Collections.emptyList()); + private MeasureComputerContextImpl newContext(int componentRef, String inputMetric, String outputMetric) { + return newContext(componentRef, inputMetric, outputMetric, Collections.emptyList()); } - private MeasureComputer.Implementation.Context newContext(int componentRef, final Set inputMetrics, final Set outputMetrics, List issues) { + private MeasureComputerContextImpl newContext(int componentRef, String inputMetric, String outputMetric, List issues) { componentIssuesRepository.setIssues(componentRef, issues); - MeasureComputer measureComputer = new MeasureComputer() { - @Override - public Set getInputMetrics() { - return inputMetrics; - } - - @Override - public Set 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; } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerDefinitionImplTest.java similarity index 55% rename from server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerImplTest.java rename to server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerDefinitionImplTest.java index 98eb6b04987..5e9b6c02fac 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerDefinitionImplTest.java @@ -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]}"); } + } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerProviderContextTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerProviderContextTest.java deleted file mode 100644 index d68eacdee10..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/api/MeasureComputerProviderContextTest.java +++ /dev/null @@ -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 getInputMetrics() { - return ImmutableSet.of("ncloc", "debt"); - } - - @Override - public Set 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 getInputMetrics() { - return ImmutableSet.of("ncloc", "debt"); - } - - @Override - public Set 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(); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedMeasureComputersTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedMeasureComputersTest.java index aab334c6818..2b3d0163ced 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedMeasureComputersTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedMeasureComputersTest.java @@ -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 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 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 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 getInputMetrics() { + return ImmutableSet.of(NCLOC_KEY); + } + + @Override + public Set 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 { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/Decorator.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/Decorator.java index 9565c9417c3..66bc873a3ee 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/Decorator.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/Decorator.java @@ -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 diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Component.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Component.java index ede0cce0b21..f94098414e9 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Component.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Component.java @@ -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 { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Issue.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Issue.java index e4233c2a6a5..7b68843bf94 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Issue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Issue.java @@ -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(); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Measure.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Measure.java index fea604b8ff3..948f33eee6c 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Measure.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Measure.java @@ -20,6 +20,11 @@ package org.sonar.api.ce.measure; +/** + * Measure used in {@link MeasureComputer} + * + * @since 5.2 + */ public interface Measure { /** diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/MeasureComputer.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/MeasureComputer.java index d62851006a6..76a8dfa5c96 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/MeasureComputer.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/MeasureComputer.java @@ -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}. + *

+ * This interface replaces the deprecated class org.sonar.api.batch.Decorator. + *

+ *

How to use

+ *
+ * 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);
+ *     }
+ *   }
+ * }
+ * 
+ *

+ *

How to test

+ *
+ * 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);
+ *   }
+ * 
+ * + * @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 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 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 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 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 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 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 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 getIssues(); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/MeasureComputerProvider.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/MeasureComputerProvider.java deleted file mode 100644 index 6eb62df1141..00000000000 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/MeasureComputerProvider.java +++ /dev/null @@ -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(); - - } -} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/RangeDistributionBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/RangeDistributionBuilder.java index 06408466db6..3910d777acf 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/RangeDistributionBuilder.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/RangeDistributionBuilder.java @@ -37,6 +37,7 @@ import org.sonar.api.utils.KeyValueFormat; *

An example of usage : you wish to record the percentage of lines of code that belong to method * with pre-defined ranges of complexity.

* + * @since 5.2 */ public class RangeDistributionBuilder { diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Settings.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Settings.java index b704d6cd8e3..8403c254fbf 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Settings.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/Settings.java @@ -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 { -- 2.39.5