aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch/src/main
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2015-03-20 16:12:20 +0100
committerJulien HENRY <julien.henry@sonarsource.com>2015-03-23 10:55:44 +0100
commit7b2066e95e177700b41f86b30468cbca12cb5f5a (patch)
tree0bd38a280402b9483b5e5d552fbe6f8d2e870f37 /sonar-batch/src/main
parent99c983079b5cd16c34f6407fcfac9cb5b7e821d9 (diff)
downloadsonarqube-7b2066e95e177700b41f86b30468cbca12cb5f5a.tar.gz
sonarqube-7b2066e95e177700b41f86b30468cbca12cb5f5a.zip
SONAR-6275 Feed measures in compute report
Diffstat (limited to 'sonar-batch/src/main')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java74
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java134
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/DatabaseModePhaseExecutor.java23
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java13
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java203
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java2
7 files changed, 216 insertions, 235 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java
deleted file mode 100644
index cf5e56ea5a3..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java
+++ /dev/null
@@ -1,74 +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.batch.index;
-
-import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
-import org.sonar.api.database.model.MeasureMapper;
-import org.sonar.api.database.model.MeasureModel;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.measures.PersistenceMode;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.duplication.DuplicationUtils;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-
-public final class DuplicationPersister implements ScanPersister {
- private final MyBatis mybatis;
- private final RuleFinder ruleFinder;
- private final ResourceCache resourceCache;
- private final DuplicationCache duplicationCache;
- private final MetricFinder metricFinder;
-
- public DuplicationPersister(MyBatis mybatis, RuleFinder ruleFinder, ResourceCache resourceCache,
- DuplicationCache duplicationCache, MetricFinder metricFinder) {
- this.mybatis = mybatis;
- this.ruleFinder = ruleFinder;
- this.resourceCache = resourceCache;
- this.duplicationCache = duplicationCache;
- this.metricFinder = metricFinder;
- }
-
- @Override
- public void persist() {
- // Don't use batch insert for duplications since keeping all data in memory can produce OOM
- try (DbSession session = mybatis.openSession(false)) {
- MeasureMapper mapper = session.getMapper(MeasureMapper.class);
- Metric duplicationMetricWithId = metricFinder.findByKey(CoreMetrics.DUPLICATIONS_DATA_KEY);
- for (String effectiveKey : duplicationCache.componentKeys()) {
- Iterable<DefaultDuplication> dups = duplicationCache.byComponent(effectiveKey);
- Measure measure = new Measure(duplicationMetricWithId, DuplicationUtils.toXml(dups)).setPersistenceMode(PersistenceMode.DATABASE);
- BatchResource batchResource = resourceCache.get(effectiveKey);
-
- if (MeasurePersister.shouldPersistMeasure(batchResource.resource(), measure)) {
- MeasureModel measureModel = MeasurePersister.model(measure, ruleFinder).setSnapshotId(batchResource.snapshotId());
- mapper.insert(measureModel);
- session.commit();
- }
- }
- } catch (Exception e) {
- throw new IllegalStateException("Unable to save some measures", e);
- }
- }
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
deleted file mode 100644
index 6559b0a7f7f..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
+++ /dev/null
@@ -1,134 +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.batch.index;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.sonar.api.database.model.MeasureMapper;
-import org.sonar.api.database.model.MeasureModel;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.measures.RuleMeasure;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.technicaldebt.batch.Characteristic;
-import org.sonar.batch.index.Cache.Entry;
-import org.sonar.batch.scan.measure.MeasureCache;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-
-import javax.annotation.Nullable;
-
-public class MeasurePersister implements ScanPersister {
- private final MyBatis mybatis;
- private final RuleFinder ruleFinder;
- private final MeasureCache measureCache;
- private final ResourceCache resourceCache;
- private final MetricFinder metricFinder;
-
- public MeasurePersister(MyBatis mybatis, RuleFinder ruleFinder, MetricFinder metricFinder,
- MeasureCache measureCache, ResourceCache resourceCache) {
- this.mybatis = mybatis;
- this.ruleFinder = ruleFinder;
- this.metricFinder = metricFinder;
- this.measureCache = measureCache;
- this.resourceCache = resourceCache;
- }
-
- @Override
- public void persist() {
- try (DbSession session = mybatis.openSession(true)) {
- MeasureMapper mapper = session.getMapper(MeasureMapper.class);
-
- for (Entry<Measure> entry : measureCache.entries()) {
- String effectiveKey = entry.key()[0].toString();
- Measure measure = entry.value();
- BatchResource batchResource = resourceCache.get(effectiveKey);
-
- // Reload Metric to have all Hibernate fields populated
- measure.setMetric(metricFinder.findByKey(measure.getMetricKey()));
-
- if (shouldPersistMeasure(batchResource.resource(), measure)) {
- MeasureModel measureModel = model(measure, ruleFinder).setSnapshotId(batchResource.snapshotId());
- mapper.insert(measureModel);
- }
- }
-
- session.commit();
- } catch (Exception e) {
- throw new IllegalStateException("Unable to save some measures", e);
- }
- }
-
- @VisibleForTesting
- static boolean shouldPersistMeasure(@Nullable Resource resource, @Nullable Measure measure) {
- if (resource == null || measure == null) {
- return false;
- }
- return measure.getPersistenceMode().useDatabase() &&
- !(ResourceUtils.isEntity(resource) && measure.isBestValue()) && isMeasureNotEmpty(measure);
- }
-
- private static boolean isMeasureNotEmpty(Measure measure) {
- boolean isNotEmpty = false;
- for (int i = 1; i <= 5; i++) {
- isNotEmpty = isNotEmpty || measure.getVariation(i) != null;
- }
- return measure.getValue() != null || measure.getData() != null
- || isNotEmpty;
- }
-
- static MeasureModel model(Measure measure, RuleFinder ruleFinder) {
- MeasureModel model = new MeasureModel();
- // Assume Metric was reloaded
- model.setMetricId(measure.getMetric().getId());
- model.setDescription(measure.getDescription());
- model.setData(measure.getData());
- model.setAlertStatus(measure.getAlertStatus());
- model.setAlertText(measure.getAlertText());
- model.setTendency(measure.getTendency());
- model.setVariationValue1(measure.getVariation1());
- model.setVariationValue2(measure.getVariation2());
- model.setVariationValue3(measure.getVariation3());
- model.setVariationValue4(measure.getVariation4());
- model.setVariationValue5(measure.getVariation5());
- Characteristic characteristic = measure.getCharacteristic();
- if (characteristic != null) {
- model.setCharacteristicId(characteristic.id());
- }
- model.setPersonId(measure.getPersonId());
- model.setValue(measure.getValue());
- if (measure instanceof RuleMeasure) {
- RuleMeasure ruleMeasure = (RuleMeasure) measure;
- model.setRulePriority(ruleMeasure.getSeverity());
- RuleKey ruleKey = ruleMeasure.ruleKey();
- if (ruleKey != null) {
- Rule ruleWithId = ruleFinder.findByKey(ruleKey);
- if (ruleWithId == null) {
- throw new IllegalStateException("Can not save a measure with unknown rule " + ruleMeasure);
- }
- model.setRuleId(ruleWithId.getId());
- }
- }
- return model;
- }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/DatabaseModePhaseExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/phases/DatabaseModePhaseExecutor.java
index cf54bb43943..13ec298b8d4 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/DatabaseModePhaseExecutor.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/DatabaseModePhaseExecutor.java
@@ -37,11 +37,7 @@ import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.batch.scan.filesystem.FileSystemLogger;
import org.sonar.batch.scan.report.IssuesReports;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
public final class DatabaseModePhaseExecutor implements PhaseExecutor {
@@ -157,31 +153,18 @@ public final class DatabaseModePhaseExecutor implements PhaseExecutor {
private void executePersisters() {
if (!analysisMode.isPreview()) {
LOGGER.info("Store results in database");
- List<ScanPersister> sortedPersisters = sortedPersisters();
- eventBus.fireEvent(new PersistersPhaseEvent(sortedPersisters, true));
- for (ScanPersister persister : sortedPersisters) {
+ eventBus.fireEvent(new PersistersPhaseEvent(Arrays.asList(persisters), true));
+ for (ScanPersister persister : persisters) {
LOGGER.debug("Execute {}", persister.getClass().getName());
eventBus.fireEvent(new PersisterExecutionEvent(persister, true));
persister.persist();
eventBus.fireEvent(new PersisterExecutionEvent(persister, false));
}
- eventBus.fireEvent(new PersistersPhaseEvent(sortedPersisters, false));
+ eventBus.fireEvent(new PersistersPhaseEvent(Arrays.asList(persisters), false));
}
}
- List<ScanPersister> sortedPersisters() {
- // Sort by reverse name so that ResourcePersister is executed before MeasurePersister
- List<ScanPersister> sortedPersisters = new ArrayList<>(Arrays.asList(persisters));
- Collections.sort(sortedPersisters, new Comparator<ScanPersister>() {
- @Override
- public int compare(ScanPersister o1, ScanPersister o2) {
- return o2.getClass().getName().compareTo(o1.getClass().getName());
- }
- });
- return sortedPersisters;
- }
-
private void publishReportJob() {
String stepName = "Publish report";
eventBus.fireEvent(new BatchStepEvent(stepName, true));
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
index 540c3fb723f..640552eccfe 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java
@@ -58,9 +58,11 @@ public class IssuesPublisher implements ReportPublisher {
String componentKey = resource.resource().getEffectiveKey();
Iterable<DefaultIssue> issues = issueCache.byComponent(componentKey);
writer.writeComponentIssues(resource.batchId(), Iterables.transform(issues, new Function<DefaultIssue, BatchReport.Issue>() {
+ private BatchReport.Issue.Builder builder = BatchReport.Issue.newBuilder();
+
@Override
public BatchReport.Issue apply(DefaultIssue input) {
- return toReportIssue(input);
+ return toReportIssue(builder, input);
}
}));
deletedComponentKeys.remove(componentKey);
@@ -94,9 +96,11 @@ public class IssuesPublisher implements ReportPublisher {
if (iterator.hasNext()) {
String componentUuid = iterator.next().componentUuid();
writer.writeDeletedComponentIssues(deletedComponentCount, componentUuid, Iterables.transform(issues, new Function<DefaultIssue, BatchReport.Issue>() {
+ private BatchReport.Issue.Builder builder = BatchReport.Issue.newBuilder();
+
@Override
public BatchReport.Issue apply(DefaultIssue input) {
- return toReportIssue(input);
+ return toReportIssue(builder, input);
}
}));
}
@@ -104,9 +108,8 @@ public class IssuesPublisher implements ReportPublisher {
return deletedComponentCount;
}
- private BatchReport.Issue toReportIssue(DefaultIssue issue) {
- BatchReport.Issue.Builder builder = BatchReport.Issue.newBuilder();
-
+ private BatchReport.Issue toReportIssue(BatchReport.Issue.Builder builder, DefaultIssue issue) {
+ builder.clear();
// non-null fields
builder.setUuid(issue.key());
builder.setIsNew(issue.isNew());
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java
new file mode 100644
index 00000000000..ed0b342dba0
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java
@@ -0,0 +1,203 @@
+/*
+ * 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.batch.report;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
+import org.sonar.api.measures.*;
+import org.sonar.api.measures.Metric.Level;
+import org.sonar.api.measures.Metric.ValueType;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.technicaldebt.batch.Characteristic;
+import org.sonar.batch.duplication.DuplicationCache;
+import org.sonar.batch.duplication.DuplicationUtils;
+import org.sonar.batch.index.BatchResource;
+import org.sonar.batch.index.ResourceCache;
+import org.sonar.batch.protocol.Constants;
+import org.sonar.batch.protocol.Constants.MeasureValueType;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.batch.protocol.output.BatchReportWriter;
+import org.sonar.batch.scan.measure.MeasureCache;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+public class MeasuresPublisher implements ReportPublisher {
+
+ private final ResourceCache resourceCache;
+ private final MeasureCache measureCache;
+ private final DuplicationCache duplicationCache;
+
+ public MeasuresPublisher(ResourceCache resourceCache, MeasureCache measureCache, DuplicationCache duplicationCache) {
+ this.resourceCache = resourceCache;
+ this.measureCache = measureCache;
+ this.duplicationCache = duplicationCache;
+ }
+
+ @Override
+ public void publish(BatchReportWriter writer) {
+ for (BatchResource resource : resourceCache.all()) {
+ Iterable<Measure> batchMeasures = measureCache.byResource(resource.resource());
+ Iterable<org.sonar.batch.protocol.output.BatchReport.Measure> reportMeasures = Iterables.transform(batchMeasures, new Function<Measure, BatchReport.Measure>() {
+ private BatchReport.Measure.Builder builder = BatchReport.Measure.newBuilder();
+
+ @Override
+ public BatchReport.Measure apply(Measure input) {
+ return toReportMeasure(builder, input);
+ }
+ });
+ Iterable<DefaultDuplication> dups = duplicationCache.byComponent(resource.resource().getEffectiveKey());
+ if (dups.iterator().hasNext()) {
+ org.sonar.batch.protocol.output.BatchReport.Measure dupMeasure = toReportMeasure(BatchReport.Measure.newBuilder(), dups);
+ writer.writeComponentMeasures(resource.batchId(), Iterables.concat(Arrays.asList(dupMeasure), reportMeasures));
+ } else {
+ writer.writeComponentMeasures(resource.batchId(), reportMeasures);
+ }
+ }
+ }
+
+ private BatchReport.Measure toReportMeasure(BatchReport.Measure.Builder builder, Iterable<DefaultDuplication> dups) {
+ builder.clear();
+
+ builder.setValueType(MeasureValueType.STRING);
+ builder.setStringValue(DuplicationUtils.toXml(dups));
+ builder.setMetricKey(CoreMetrics.DUPLICATIONS_DATA_KEY);
+ return builder.build();
+ }
+
+ private BatchReport.Measure toReportMeasure(BatchReport.Measure.Builder builder, Measure measure) {
+ builder.clear();
+
+ builder.setValueType(getMeasureValueType(measure.getMetric().getType()));
+ setValueAccordingToType(builder, measure);
+ // Because some numeric measures also have a data (like Sqale rating)
+ String data = measure.getData();
+ if (data != null) {
+ builder.setStringValue(data);
+ }
+ builder.setMetricKey(measure.getMetricKey());
+
+ // temporary fields during development of computation stack
+ String description = measure.getDescription();
+ if (description != null) {
+ builder.setDescription(description);
+ }
+ if (measure instanceof RuleMeasure) {
+ RuleMeasure ruleMeasure = (RuleMeasure) measure;
+ RuleKey ruleKey = ruleMeasure.ruleKey();
+ if (ruleKey != null) {
+ builder.setRuleKey(ruleKey.toString());
+ }
+ RulePriority severity = ruleMeasure.getSeverity();
+ if (severity != null) {
+ builder.setSeverity(Constants.Severity.valueOf(severity.toString()));
+ }
+ }
+ Level alertStatus = measure.getAlertStatus();
+ if (alertStatus != null) {
+ builder.setAlertStatus(alertStatus.toString());
+ }
+ String alertText = measure.getAlertText();
+ if (alertText != null) {
+ builder.setAlertText(alertText);
+ }
+ Double variation1 = measure.getVariation1();
+ if (variation1 != null) {
+ builder.setVariationValue1(variation1);
+ }
+ Double variation2 = measure.getVariation2();
+ if (variation2 != null) {
+ builder.setVariationValue1(variation2);
+ }
+ Double variation3 = measure.getVariation3();
+ if (variation3 != null) {
+ builder.setVariationValue1(variation3);
+ }
+ Double variation4 = measure.getVariation4();
+ if (variation4 != null) {
+ builder.setVariationValue1(variation4);
+ }
+ Double variation5 = measure.getVariation5();
+ if (variation5 != null) {
+ builder.setVariationValue1(variation5);
+ }
+ Integer tendency = measure.getTendency();
+ if (tendency != null) {
+ builder.setTendency(tendency);
+ }
+ Characteristic charac = measure.getCharacteristic();
+ if (charac != null) {
+ builder.setCharactericId(charac.id());
+ }
+ return builder.build();
+ }
+
+ private void setValueAccordingToType(BatchReport.Measure.Builder builder, Measure measure) {
+ Serializable value = measure.value();
+ // Value is null for new_xxx measures where only variations are populated
+ if (value != null) {
+ switch (builder.getValueType()) {
+ case BOOLEAN:
+ builder.setBooleanValue((Boolean) value);
+ break;
+ case DOUBLE:
+ builder.setDoubleValue((Double) value);
+ break;
+ case INT:
+ builder.setIntValue((Integer) value);
+ break;
+ case LONG:
+ builder.setLongValue((Long) value);
+ break;
+ case STRING:
+ builder.setStringValue((String) value);
+ break;
+ default:
+ throw new IllegalStateException("Unknown value type: " + builder.getValueType());
+ }
+ }
+ }
+
+ private MeasureValueType getMeasureValueType(ValueType type) {
+ switch (type) {
+ case INT:
+ case MILLISEC:
+ case RATING:
+ return MeasureValueType.INT;
+ case FLOAT:
+ case PERCENT:
+ return MeasureValueType.DOUBLE;
+ case BOOL:
+ return MeasureValueType.BOOLEAN;
+ case STRING:
+ case DATA:
+ case LEVEL:
+ case DISTRIB:
+ return MeasureValueType.STRING;
+ case WORK_DUR:
+ return MeasureValueType.LONG;
+ default:
+ throw new IllegalStateException("Unknown value type: " + type);
+ }
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
index a092c3a9f36..aa35effd389 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
@@ -57,6 +57,7 @@ import org.sonar.batch.qualitygate.GenerateQualityGateEvents;
import org.sonar.batch.qualitygate.QualityGateVerifier;
import org.sonar.batch.report.ComponentsPublisher;
import org.sonar.batch.report.IssuesPublisher;
+import org.sonar.batch.report.MeasuresPublisher;
import org.sonar.batch.report.PublishReportJob;
import org.sonar.batch.rule.*;
import org.sonar.batch.scan.filesystem.*;
@@ -116,6 +117,7 @@ public class ModuleScanContainer extends ComponentContainer {
PublishReportJob.class,
ComponentsPublisher.class,
IssuesPublisher.class,
+ MeasuresPublisher.class,
moduleDefinition.getContainerExtensions(),
// file system
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index 8c4f5e6272d..ffa93f69285 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -192,8 +192,6 @@ public class ProjectScanContainer extends ComponentContainer {
private void addDataBaseComponents() {
add(
- MeasurePersister.class,
- DuplicationPersister.class,
ResourcePersister.class,
SourcePersister.class,
ResourceKeyMigration.class,