diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2015-03-20 16:12:20 +0100 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2015-03-23 10:55:44 +0100 |
commit | 7b2066e95e177700b41f86b30468cbca12cb5f5a (patch) | |
tree | 0bd38a280402b9483b5e5d552fbe6f8d2e870f37 /sonar-batch/src/main | |
parent | 99c983079b5cd16c34f6407fcfac9cb5b7e821d9 (diff) | |
download | sonarqube-7b2066e95e177700b41f86b30468cbca12cb5f5a.tar.gz sonarqube-7b2066e95e177700b41f86b30468cbca12cb5f5a.zip |
SONAR-6275 Feed measures in compute report
Diffstat (limited to 'sonar-batch/src/main')
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, |