]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5389 Refactor new issue API
authorJulien HENRY <julien.henry@sonarsource.com>
Fri, 19 Sep 2014 16:08:26 +0000 (18:08 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Mon, 22 Sep 2014 08:49:34 +0000 (10:49 +0200)
34 files changed:
plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/JavaCpdEngineTest.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssueOnDirPerFileSensor.java
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java
plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/MeasureSensorTest.java
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java
sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java
sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java
sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContext.java
sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultFileLinesContextFactory.java
sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultIssueValueCoder.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultMeasureValueCoder.java
sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java
sonar-batch/src/main/java/org/sonar/batch/scan2/IssueCache.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan2/MeasureCache.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/scan2/NewMeasureCache.java [deleted file]
sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/Sensor.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorDescriptor.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorStorage.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/Issue.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueBuilder.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueBuilder.java [deleted file]
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/Measure.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java
sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueTest.java
sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasureTest.java

index d2dd4d2d32cd340edf34326f9eff83f816eb4dc4..1b565ff56b39538e7d7cc882532b63fdea356779 100644 (file)
@@ -29,8 +29,8 @@ import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
-import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
 import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder;
 import org.sonar.api.batch.sensor.measure.Measure;
@@ -63,14 +63,14 @@ public class JavaCpdEngineTest {
   private DefaultDuplicationBuilder duplicationBuilder;
   private FileLinesContextFactory contextFactory;
   private FileLinesContext linesContext;
-  private SensorStorage<Measure> persister = mock(SensorStorage.class);
+  private SensorStorage storage = mock(SensorStorage.class);
 
   @Before
   public void before() throws IOException {
     when(context.newMeasure()).then(new Answer<Measure>() {
       @Override
       public Measure answer(InvocationOnMock invocation) throws Throwable {
-        return new DefaultMeasure(persister);
+        return new DefaultMeasure(storage);
       }
     });
     inputFile = new DeprecatedDefaultInputFile("foo", "src/main/java/Foo.java");
@@ -97,9 +97,9 @@ public class JavaCpdEngineTest {
     List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key2", 0, 15, 214)));
     JavaCpdEngine.save(context, inputFile, groups, contextFactory);
 
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(1));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(200));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(1));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(200));
 
     InOrder inOrder = Mockito.inOrder(duplicationBuilder);
     inOrder.verify(duplicationBuilder).originBlock(5, 204);
@@ -118,9 +118,9 @@ public class JavaCpdEngineTest {
     List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key1", 0, 215, 414)));
     JavaCpdEngine.save(context, inputFile, groups, contextFactory);
 
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(2));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(400));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(2));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(400));
 
     InOrder inOrder = Mockito.inOrder(duplicationBuilder);
     inOrder.verify(duplicationBuilder).originBlock(5, 204);
@@ -133,9 +133,9 @@ public class JavaCpdEngineTest {
     List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key2", 0, 15, 214), new ClonePart("key3", 0, 25, 224)));
     JavaCpdEngine.save(context, inputFile, groups, contextFactory);
 
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(1));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(200));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(1));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(200));
 
     InOrder inOrder = Mockito.inOrder(duplicationBuilder);
     inOrder.verify(duplicationBuilder).originBlock(5, 204);
@@ -157,9 +157,9 @@ public class JavaCpdEngineTest {
       newCloneGroup(new ClonePart("key1", 0, 15, 214), new ClonePart("key3", 0, 15, 214)));
     JavaCpdEngine.save(context, inputFile, groups, contextFactory);
 
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(2));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(210));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(2));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(210));
 
     InOrder inOrder = Mockito.inOrder(duplicationBuilder);
     inOrder.verify(duplicationBuilder).originBlock(5, 204);
index 041bdd94efd6795027263d8db024c12db11b7fa7..01b2f8168bd3d2ccb17f0a669bc5f19f0cd164b4 100644 (file)
@@ -50,11 +50,11 @@ public class CreateIssueByInternalKeySensor implements Sensor {
     ActiveRule rule = context.activeRules().findByInternalKey(XooRulesDefinition.XOO_REPOSITORY,
       context.settings().getString(INTERNAL_KEY_PROPERTY));
     if (rule != null) {
-      context.addIssue(context.issueBuilder()
+      context.newIssue()
         .ruleKey(rule.ruleKey())
         .onFile(file)
         .message("This issue is generated on each file")
-        .build());
+        .save();
     }
   }
 }
index 6763d0308c8ba462cd03955a0a96ef5904ea69aa..7a2161b10493de0694526c42a2fd307049f5f6c6 100644 (file)
@@ -51,11 +51,11 @@ public class OneIssueOnDirPerFileSensor implements Sensor {
     RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY);
     InputDir inputDir = context.fileSystem().inputDir(file.file().getParentFile());
     if (inputDir != null) {
-      context.addIssue(context.issueBuilder()
+      context.newIssue()
         .ruleKey(ruleKey)
         .onDir(inputDir)
         .message("This issue is generated for file " + file.relativePath())
-        .build());
+        .save();
     }
   }
 }
index e9fab499c18e6b7cac93f9ed21dd9560d02e7967..7a11c639e38d96b0fdea33135ebee38db61fbb04 100644 (file)
@@ -23,7 +23,7 @@ import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.api.batch.sensor.issue.IssueBuilder;
+import org.sonar.api.batch.sensor.issue.Issue.Severity;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.xoo.Xoo;
@@ -53,16 +53,16 @@ public class OneIssuePerLineSensor implements Sensor {
 
   private void createIssues(InputFile file, SensorContext context) {
     RuleKey ruleKey = RuleKey.of(XooRulesDefinition.XOO_REPOSITORY, RULE_KEY);
-    IssueBuilder issueBuilder = context.issueBuilder();
+    String severity = context.settings().getString(FORCE_SEVERITY_PROPERTY);
     for (int line = 1; line <= file.lines(); line++) {
-      context.addIssue(issueBuilder
+      context.newIssue()
         .ruleKey(ruleKey)
         .onFile(file)
         .atLine(line)
         .effortToFix(context.settings().getDouble(EFFORT_TO_FIX_PROPERTY))
-        .severity(context.settings().getString(FORCE_SEVERITY_PROPERTY))
+        .overrideSeverity(severity != null ? Severity.valueOf(severity) : null)
         .message("This issue is generated on each line")
-        .build());
+        .save();
     }
   }
 }
index 11be6dfcccc50a95253ee9142b6fb7f0fe292201..2e04e8184dbff3ff776aabd1efa658a69eedb057 100644 (file)
@@ -30,8 +30,8 @@ import org.mockito.stubbing.Answer;
 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.measure.MetricFinder;
-import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.measures.CoreMetrics;
@@ -58,7 +58,7 @@ public class MeasureSensorTest {
 
   private File baseDir;
   private MetricFinder metricFinder;
-  private SensorStorage<DefaultMeasure> persister;
+  private SensorStorage storage;
 
   @Before
   public void prepare() throws IOException {
@@ -67,11 +67,11 @@ public class MeasureSensorTest {
     sensor = new MeasureSensor(metricFinder);
     fileSystem = new DefaultFileSystem();
     when(context.fileSystem()).thenReturn(fileSystem);
-    persister = mock(SensorStorage.class);
+    storage = mock(SensorStorage.class);
     when(context.newMeasure()).then(new Answer<DefaultMeasure>() {
       @Override
       public DefaultMeasure answer(InvocationOnMock invocation) throws Throwable {
-        return new DefaultMeasure(persister);
+        return new DefaultMeasure(storage);
       }
     });
   }
@@ -106,11 +106,11 @@ public class MeasureSensorTest {
 
     sensor.execute(context);
 
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.NCLOC).onFile(inputFile).withValue(12));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.BRANCH_COVERAGE).onFile(inputFile).withValue(5.3));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.TECHNICAL_DEBT).onFile(inputFile).withValue(300L));
-    verify(persister).store(new DefaultMeasure().forMetric(booleanMetric).onFile(inputFile).withValue(true));
-    verify(persister).store(new DefaultMeasure().forMetric(CoreMetrics.COMMENT_LINES_DATA).onFile(inputFile).withValue("1=1,2=1"));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.NCLOC).onFile(inputFile).withValue(12));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.BRANCH_COVERAGE).onFile(inputFile).withValue(5.3));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.TECHNICAL_DEBT).onFile(inputFile).withValue(300L));
+    verify(storage).store(new DefaultMeasure().forMetric(booleanMetric).onFile(inputFile).withValue(true));
+    verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.COMMENT_LINES_DATA).onFile(inputFile).withValue("1=1,2=1"));
 
   }
 
index d73f1fcab1a728b3381383d6b1db0cc1b603952d..703935806384fc936c1518ab5fe61ca0569b0c80 100644 (file)
@@ -216,7 +216,7 @@ public class DefaultIndex extends SonarIndex {
         throw new SonarException("Unknown metric: " + measure.getMetricKey());
       }
       if (DefaultSensorContext.INTERNAL_METRICS.contains(metric)) {
-        LOG.warn("Metric " + metric + " is an internal metric computed by SonarQube. Please update your plugin.");
+        LOG.warn("Metric " + metric.key() + " is an internal metric computed by SonarQube. Please update your plugin.");
         return measure;
       }
       measure.setMetric(metric);
index 69b1dad23859a6078634d6a4e57adaf7bb715d98..437d778b7fdcbc3934f1b19bc8086bbb312599da 100644 (file)
@@ -56,8 +56,8 @@ import org.sonar.batch.protocol.input.ProjectReferentials;
 import org.sonar.batch.referential.GlobalReferentialsLoader;
 import org.sonar.batch.referential.ProjectReferentialsLoader;
 import org.sonar.batch.scan.filesystem.InputPathCache;
-import org.sonar.batch.scan2.AnalyzerIssueCache;
-import org.sonar.batch.scan2.NewMeasureCache;
+import org.sonar.batch.scan2.IssueCache;
+import org.sonar.batch.scan2.MeasureCache;
 import org.sonar.batch.scan2.ProjectScanContainer;
 import org.sonar.batch.scan2.ScanTaskObserver;
 import org.sonar.batch.symbol.SymbolData;
@@ -240,11 +240,11 @@ public class BatchMediumTester {
     @Override
     public void scanTaskCompleted(ProjectScanContainer container) {
       LOG.info("Store analysis results in memory for later assertions in medium test");
-      for (Issue issue : container.getComponentByType(AnalyzerIssueCache.class).all()) {
+      for (Issue issue : container.getComponentByType(IssueCache.class).all()) {
         issues.add(issue);
       }
 
-      for (DefaultMeasure<?> measure : container.getComponentByType(NewMeasureCache.class).all()) {
+      for (DefaultMeasure<?> measure : container.getComponentByType(MeasureCache.class).all()) {
         measures.add(measure);
       }
 
index 8a225c94dc0978bebdc47f964b5ddfd36138fe9e..f11c6b82f880f709bea360a8d133e01e3ca4d964 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.api.batch.measure.Metric;
 import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.Issue.Severity;
 import org.sonar.api.batch.sensor.measure.Measure;
 import org.sonar.api.batch.sensor.test.TestCase;
 import org.sonar.api.batch.sensor.test.internal.DefaultTestCase;
@@ -62,7 +63,6 @@ import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.batch.scan2.BaseSensorContext;
 import org.sonar.core.component.ComponentKeys;
 
-import java.io.Serializable;
 import java.util.List;
 
 /**
@@ -100,7 +100,7 @@ public class SensorContextAdapter extends BaseSensorContext {
   }
 
   @Override
-  public void store(Measure<Serializable> measure) {
+  public void store(Measure measure) {
     org.sonar.api.measures.Metric<?> m = metricFinder.findByKey(measure.metric().key());
     if (m == null) {
       throw new IllegalStateException("Unknow metric with key: " + measure.metric().key());
@@ -155,7 +155,7 @@ public class SensorContextAdapter extends BaseSensorContext {
   }
 
   @Override
-  public boolean addIssue(Issue issue) {
+  public void store(Issue issue) {
     Resource r;
     InputPath inputPath = issue.inputPath();
     if (inputPath != null) {
@@ -169,12 +169,13 @@ public class SensorContextAdapter extends BaseSensorContext {
     }
     Issuable issuable = perspectives.as(Issuable.class, r);
     if (issuable == null) {
-      return false;
+      return;
     }
-    return issuable.addIssue(toDefaultIssue(project.getKey(), ComponentKeys.createEffectiveKey(project, r), issue));
+    issuable.addIssue(toDefaultIssue(project.getKey(), ComponentKeys.createEffectiveKey(project, r), issue));
   }
 
   public static DefaultIssue toDefaultIssue(String projectKey, String componentKey, Issue issue) {
+    Severity overridenSeverity = issue.overridenSeverity();
     return new org.sonar.core.issue.DefaultIssueBuilder()
       .componentKey(componentKey)
       .projectKey(projectKey)
@@ -182,7 +183,7 @@ public class SensorContextAdapter extends BaseSensorContext {
       .effortToFix(issue.effortToFix())
       .line(issue.line())
       .message(issue.message())
-      .severity(issue.severity())
+      .severity(overridenSeverity != null ? overridenSeverity.name() : null)
       .build();
   }
 
index 824b229897ad1438b4131a2b9ac4e151a7fd01df..1dad931f8b577e303d897ea0661b8ae76c5b5d31 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.Issue.Severity;
 import org.sonar.api.batch.sensor.measure.Measure;
 import org.sonar.api.config.Settings;
 import org.sonar.api.utils.ZipUtils;
@@ -42,13 +43,13 @@ public final class AnalysisPublisher {
   private static final Logger LOG = LoggerFactory.getLogger(AnalysisPublisher.class);
   private final Settings settings;
   private final FileSystem fs;
-  private final NewMeasureCache measureCache;
+  private final MeasureCache measureCache;
   private final ProjectDefinition def;
-  private final AnalyzerIssueCache issueCache;
+  private final IssueCache issueCache;
 
   public AnalysisPublisher(ProjectDefinition def, Settings settings, FileSystem fs,
-    NewMeasureCache measureCache,
-    AnalyzerIssueCache analyzerIssueCache) {
+    MeasureCache measureCache,
+    IssueCache analyzerIssueCache) {
     this.def = def;
     this.settings = settings;
     this.fs = fs;
@@ -108,9 +109,12 @@ public final class AnalysisPublisher {
         }
         jsonWriter.prop("message", issue.message())
           .prop("effortToFix", issue.effortToFix())
-          .prop("line", issue.line())
-          .prop("severity", issue.severity())
-          .endObject();
+          .prop("line", issue.line());
+        Severity overridenSeverity = issue.overridenSeverity();
+        if (overridenSeverity != null) {
+          jsonWriter.prop("severity", overridenSeverity.name());
+        }
+        jsonWriter.endObject();
       }
       jsonWriter.endArray()
         .endObject()
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java
deleted file mode 100644 (file)
index 9b0fd3f..0000000
+++ /dev/null
@@ -1,57 +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.scan2;
-
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
-
-import org.sonar.api.BatchComponent;
-import org.sonar.batch.index.Cache;
-import org.sonar.batch.index.Caches;
-
-/**
- * Shared issues among all project modules
- */
-public class AnalyzerIssueCache implements BatchComponent {
-
-  // project key -> resource key -> issue key -> issue
-  private final Cache<DefaultIssue> cache;
-
-  public AnalyzerIssueCache(Caches caches) {
-    cache = caches.createCache("issues");
-  }
-
-  public Iterable<DefaultIssue> byComponent(String projectKey, String resourceKey) {
-    return cache.values(projectKey, resourceKey);
-  }
-
-  public Iterable<DefaultIssue> all() {
-    return cache.values();
-  }
-
-  public AnalyzerIssueCache put(String projectKey, String resourceKey, DefaultIssue issue) {
-    cache.put(projectKey, resourceKey, issue.key(), issue);
-    return this;
-  }
-
-  public Iterable<DefaultIssue> byModule(String projectKey) {
-    return cache.values(projectKey);
-  }
-
-}
index 63135f0dc0385a4bb0312f4c5051e8fcd859a069..09ed5a9f133b4500e03d0ed8bce7952e5974b2be 100644 (file)
@@ -24,15 +24,15 @@ import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.duplication.DuplicationBuilder;
 import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
 import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
 import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder;
 import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder;
-import org.sonar.api.batch.sensor.issue.IssueBuilder;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueBuilder;
+import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
 import org.sonar.api.batch.sensor.measure.Measure;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder;
@@ -56,7 +56,7 @@ import java.util.List;
  * @author julien
  *
  */
-public abstract class BaseSensorContext implements SensorContext, SensorStorage<Measure<Serializable>> {
+public abstract class BaseSensorContext implements SensorContext, SensorStorage {
 
   private final Settings settings;
   private final FileSystem fs;
@@ -96,8 +96,8 @@ public abstract class BaseSensorContext implements SensorContext, SensorStorage<
   }
 
   @Override
-  public IssueBuilder issueBuilder() {
-    return new DefaultIssueBuilder();
+  public Issue newIssue() {
+    return new DefaultIssue(this);
   }
 
   @Override
index 5c9559a90eb43bd88790ecb131f0cb1516f93667..545a8d176268d8b9883f0de52a3bd5208e7d0d8b 100644 (file)
@@ -36,7 +36,7 @@ import java.util.Map;
 
 public class DefaultFileLinesContext implements FileLinesContext {
 
-  private final NewMeasureCache measureCache;
+  private final MeasureCache measureCache;
   private final InputFile inputFile;
 
   /**
@@ -46,7 +46,7 @@ public class DefaultFileLinesContext implements FileLinesContext {
   private String projectKey;
   private MetricFinder metricFinder;
 
-  public DefaultFileLinesContext(MetricFinder metricFinder, NewMeasureCache measureCache, String projectKey, InputFile inputFile) {
+  public DefaultFileLinesContext(MetricFinder metricFinder, MeasureCache measureCache, String projectKey, InputFile inputFile) {
     this.metricFinder = metricFinder;
     this.projectKey = projectKey;
     Preconditions.checkNotNull(measureCache);
index 78086efdd8ef323f71615e4e9c77458a5c606d15..c93fb84312f74e594697a5465ecd90a8462ccf77 100644 (file)
@@ -30,12 +30,12 @@ import org.sonar.batch.scan.filesystem.InputPathCache;
 
 public class DefaultFileLinesContextFactory implements FileLinesContextFactory {
 
-  private final NewMeasureCache measureCache;
+  private final MeasureCache measureCache;
   private final MetricFinder metricFinder;
   private final ProjectDefinition def;
   private InputPathCache fileCache;
 
-  public DefaultFileLinesContextFactory(InputPathCache fileCache, FileSystem fs, MetricFinder metricFinder, NewMeasureCache measureCache,
+  public DefaultFileLinesContextFactory(InputPathCache fileCache, FileSystem fs, MetricFinder metricFinder, MeasureCache measureCache,
     ProjectDefinition def) {
     this.fileCache = fileCache;
     this.metricFinder = metricFinder;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultIssueValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultIssueValueCoder.java
new file mode 100644 (file)
index 0000000..61ce8f9
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.scan2;
+
+import com.persistit.Value;
+import com.persistit.encoding.CoderContext;
+import com.persistit.encoding.ValueCoder;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputPath;
+import org.sonar.api.batch.fs.internal.DefaultInputDir;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.issue.Issue.Severity;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.batch.scan.filesystem.InputPathCache;
+
+class DefaultIssueValueCoder implements ValueCoder {
+
+  private final InputPathCache inputPathCache;
+
+  public DefaultIssueValueCoder(InputPathCache inputPathCache) {
+    this.inputPathCache = inputPathCache;
+  }
+
+  @Override
+  public void put(Value value, Object object, CoderContext context) {
+    DefaultIssue issue = (DefaultIssue) object;
+    value.putString(issue.key());
+    InputPath inputPath = issue.inputPath();
+    if (inputPath != null) {
+      if (inputPath instanceof InputDir) {
+        value.put(0);
+        value.putString(((DefaultInputDir) inputPath).moduleKey());
+        value.putString(inputPath.relativePath());
+      } else {
+        value.put(1);
+        value.putString(((DefaultInputFile) inputPath).moduleKey());
+        value.putString(inputPath.relativePath());
+        value.put(issue.line());
+      }
+    } else {
+      value.putNull();
+    }
+    value.put(issue.message());
+    value.put(issue.effortToFix());
+    value.put(issue.ruleKey().repository());
+    value.put(issue.ruleKey().rule());
+    Severity overridenSeverity = issue.overridenSeverity();
+    if (overridenSeverity == null) {
+      value.putNull();
+    } else {
+      value.put(overridenSeverity.ordinal());
+    }
+  }
+
+  @Override
+  public Object get(Value value, Class clazz, CoderContext context) {
+    DefaultIssue newIssue = new DefaultIssue(null);
+    newIssue.withKey(value.getString());
+    if (value.isNull(true)) {
+      newIssue.onProject();
+    } else {
+      int type = value.getInt();
+      String moduleKey = value.getString();
+      String relativePath = value.getString();
+      if (type == 0) {
+        InputDir dir = inputPathCache.getDir(moduleKey, relativePath);
+        newIssue.onDir(dir);
+      } else {
+        InputFile f = inputPathCache.getFile(moduleKey, relativePath);
+        newIssue.onFile(f);
+        if (!value.isNull(true)) {
+          newIssue.atLine(value.getInt());
+        }
+      }
+    }
+    newIssue.message(value.getString());
+    newIssue.effortToFix(value.isNull(true) ? null : value.getDouble());
+    String repo = value.getString();
+    String rule = value.getString();
+    newIssue.ruleKey(RuleKey.of(repo, rule));
+    newIssue.overrideSeverity(value.isNull(true) ? null : Severity.values()[value.getInt()]);
+    return newIssue;
+  }
+
+}
index 53ab539df7b0ab31ea6b270b48584f861364c460..e0beb814130625b675cd9487a19b177edaf5d133 100644 (file)
@@ -51,7 +51,7 @@ class DefaultMeasureValueCoder implements ValueCoder {
     } else {
       value.putNull();
     }
-    value.putUTF(m.metric().key());
+    value.putString(m.metric().key());
     value.put(m.value());
   }
 
index 51c13e2bf937dee23c5aad6a83b8379bd85b417a..e02999d23754f83d4db9368cc09cdd96cf426f83 100644 (file)
@@ -71,8 +71,8 @@ public class DefaultSensorContext extends BaseSensorContext {
     CoreMetrics.FILE_TANGLE_INDEX,
     CoreMetrics.FILE_TANGLES
     );
-  private final NewMeasureCache measureCache;
-  private final AnalyzerIssueCache issueCache;
+  private final MeasureCache measureCache;
+  private final IssueCache issueCache;
   private final ProjectDefinition def;
   private final ActiveRules activeRules;
   private final IssueFilters issueFilters;
@@ -80,7 +80,7 @@ public class DefaultSensorContext extends BaseSensorContext {
   private final CoveragePerTestCache coveragePerTestCache;
   private final DependencyCache dependencyCache;
 
-  public DefaultSensorContext(ProjectDefinition def, NewMeasureCache measureCache, AnalyzerIssueCache issueCache,
+  public DefaultSensorContext(ProjectDefinition def, MeasureCache measureCache, IssueCache issueCache,
     Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters, ComponentDataCache componentDataCache,
     BlockCache blockCache, DuplicationCache duplicationCache, TestCaseCache testCaseCache, CoveragePerTestCache coveragePerTestCache, DependencyCache dependencyCache) {
     super(settings, fs, activeRules, componentDataCache, blockCache, duplicationCache);
@@ -95,10 +95,10 @@ public class DefaultSensorContext extends BaseSensorContext {
   }
 
   @Override
-  public void store(Measure<Serializable> newMeasure) {
+  public void store(Measure newMeasure) {
     DefaultMeasure<Serializable> measure = (DefaultMeasure<Serializable>) newMeasure;
     if (INTERNAL_METRICS.contains(measure.metric())) {
-      LOG.warn("Metric " + measure.metric() + " is an internal metric computed by SonarQube. Please update your plugin.");
+      LOG.warn("Metric " + measure.metric().key() + " is an internal metric computed by SonarQube. Please update your plugin.");
       return;
     }
     InputFile inputFile = measure.inputFile();
@@ -110,7 +110,7 @@ public class DefaultSensorContext extends BaseSensorContext {
   }
 
   @Override
-  public boolean addIssue(Issue issue) {
+  public void store(Issue issue) {
     String resourceKey;
     if (issue.inputPath() != null) {
       resourceKey = ComponentKeys.createEffectiveKey(def.getKey(), issue.inputPath());
@@ -121,7 +121,8 @@ public class DefaultSensorContext extends BaseSensorContext {
     DefaultActiveRule activeRule = (DefaultActiveRule) activeRules.find(ruleKey);
     if (activeRule == null) {
       // rule does not exist or is not enabled -> ignore the issue
-      return false;
+      LOG.debug("Rule {} does not exists or is not enabled. Issue {} is ignored.", issue.ruleKey(), issue);
+      return;
     }
     if (Strings.isNullOrEmpty(activeRule.name()) && Strings.isNullOrEmpty(issue.message())) {
       throw MessageException.of(String.format("The rule '%s' has no name and the related issue has no message.", ruleKey));
@@ -129,21 +130,16 @@ public class DefaultSensorContext extends BaseSensorContext {
 
     updateIssue((DefaultIssue) issue, activeRule);
 
-    if (issueFilters.accept(SensorContextAdapter.toDefaultIssue(def.getKey(), resourceKey, issue), null)) {
-      issueCache.put(def.getKey(), resourceKey, (DefaultIssue) issue);
-      return true;
+    if (!issueFilters.accept(SensorContextAdapter.toDefaultIssue(def.getKey(), resourceKey, issue), null)) {
+      LOG.debug("Issue {} was excluded by some filters.", issue);
+      return;
     }
-
-    return false;
+    issueCache.put(def.getKey(), resourceKey, (DefaultIssue) issue);
   }
 
   private void updateIssue(DefaultIssue issue, DefaultActiveRule activeRule) {
     if (Strings.isNullOrEmpty(issue.message())) {
-      issue.setMessage(activeRule.name());
-    }
-
-    if (issue.severity() == null) {
-      issue.setSeverity(activeRule.severity());
+      issue.message(activeRule.name());
     }
   }
 
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/IssueCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/IssueCache.java
new file mode 100644 (file)
index 0000000..5de18c1
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.scan2;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
+import org.sonar.batch.index.Cache;
+import org.sonar.batch.index.Caches;
+import org.sonar.batch.scan.filesystem.InputPathCache;
+
+/**
+ * Shared issues among all project modules
+ */
+public class IssueCache implements BatchComponent {
+
+  // project key -> resource key -> issue key -> issue
+  private final Cache<DefaultIssue> cache;
+
+  public IssueCache(Caches caches, InputPathCache inputPathCache) {
+    caches.registerValueCoder(DefaultIssue.class, new DefaultIssueValueCoder(inputPathCache));
+    cache = caches.createCache("issues");
+  }
+
+  public Iterable<DefaultIssue> byComponent(String projectKey, String resourceKey) {
+    return cache.values(projectKey, resourceKey);
+  }
+
+  public Iterable<DefaultIssue> all() {
+    return cache.values();
+  }
+
+  public IssueCache put(String projectKey, String resourceKey, DefaultIssue issue) {
+    cache.put(projectKey, resourceKey, issue.key(), issue);
+    return this;
+  }
+
+  public Iterable<DefaultIssue> byModule(String projectKey) {
+    return cache.values(projectKey);
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/MeasureCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/MeasureCache.java
new file mode 100644 (file)
index 0000000..57fe7dd
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.scan2;
+
+import com.google.common.base.Preconditions;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.batch.measure.MetricFinder;
+import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
+import org.sonar.batch.index.Cache;
+import org.sonar.batch.index.Cache.Entry;
+import org.sonar.batch.index.Caches;
+import org.sonar.batch.scan.filesystem.InputPathCache;
+
+/**
+ * Cache of all measures. This cache is shared amongst all project modules.
+ */
+public class MeasureCache implements BatchComponent {
+
+  // project key -> component key -> metric key -> measure
+  private final Cache<DefaultMeasure> cache;
+
+  public MeasureCache(Caches caches, MetricFinder metricFinder, InputPathCache inputPathCache) {
+    caches.registerValueCoder(DefaultMeasure.class, new DefaultMeasureValueCoder(metricFinder, inputPathCache));
+    cache = caches.createCache("measures");
+  }
+
+  public Iterable<Entry<DefaultMeasure>> entries() {
+    return cache.entries();
+  }
+
+  public Iterable<DefaultMeasure> byModule(String projectKey) {
+    return cache.values(projectKey);
+  }
+
+  public DefaultMeasure<?> byMetric(String projectKey, String resourceKey, String metricKey) {
+    return cache.get(projectKey, resourceKey, metricKey);
+  }
+
+  public MeasureCache put(String projectKey, String resourceKey, DefaultMeasure<?> measure) {
+    Preconditions.checkNotNull(projectKey);
+    Preconditions.checkNotNull(resourceKey);
+    Preconditions.checkNotNull(measure);
+    cache.put(projectKey, resourceKey, measure.metric().key(), measure);
+    return this;
+  }
+
+  public boolean contains(String projectKey, String resourceKey, DefaultMeasure<?> measure) {
+    Preconditions.checkNotNull(projectKey);
+    Preconditions.checkNotNull(resourceKey);
+    Preconditions.checkNotNull(measure);
+    return cache.containsKey(projectKey, resourceKey, measure.metric().key());
+  }
+
+  public Iterable<DefaultMeasure> all() {
+    return cache.values();
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/NewMeasureCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/NewMeasureCache.java
deleted file mode 100644 (file)
index 361ed8c..0000000
+++ /dev/null
@@ -1,75 +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.scan2;
-
-import com.google.common.base.Preconditions;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.measure.MetricFinder;
-import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
-import org.sonar.batch.index.Cache;
-import org.sonar.batch.index.Cache.Entry;
-import org.sonar.batch.index.Caches;
-import org.sonar.batch.scan.filesystem.InputPathCache;
-
-/**
- * Cache of all measures. This cache is shared amongst all project modules.
- */
-public class NewMeasureCache implements BatchComponent {
-
-  // project key -> component key -> metric key -> measure
-  private final Cache<DefaultMeasure> cache;
-
-  public NewMeasureCache(Caches caches, MetricFinder metricFinder, InputPathCache inputPathCache) {
-    caches.registerValueCoder(DefaultMeasure.class, new DefaultMeasureValueCoder(metricFinder, inputPathCache));
-    cache = caches.createCache("measures");
-  }
-
-  public Iterable<Entry<DefaultMeasure>> entries() {
-    return cache.entries();
-  }
-
-  public Iterable<DefaultMeasure> byModule(String projectKey) {
-    return cache.values(projectKey);
-  }
-
-  public DefaultMeasure<?> byMetric(String projectKey, String resourceKey, String metricKey) {
-    return cache.get(projectKey, resourceKey, metricKey);
-  }
-
-  public NewMeasureCache put(String projectKey, String resourceKey, DefaultMeasure<?> measure) {
-    Preconditions.checkNotNull(projectKey);
-    Preconditions.checkNotNull(resourceKey);
-    Preconditions.checkNotNull(measure);
-    cache.put(projectKey, resourceKey, measure.metric().key(), measure);
-    return this;
-  }
-
-  public boolean contains(String projectKey, String resourceKey, DefaultMeasure<?> measure) {
-    Preconditions.checkNotNull(projectKey);
-    Preconditions.checkNotNull(resourceKey);
-    Preconditions.checkNotNull(measure);
-    return cache.containsKey(projectKey, resourceKey, measure.metric().key());
-  }
-
-  public Iterable<DefaultMeasure> all() {
-    return cache.values();
-  }
-
-}
index 09b5bdf8db8a59a5fc81a29d9f014c0e72a89d3d..8eeb6c5b113d69dc7271a396f2f1a3b47e0e4bb6 100644 (file)
@@ -101,14 +101,14 @@ public class ProjectScanContainer extends ComponentContainer {
       DefaultLanguagesReferential.class,
 
       // Measures
-      NewMeasureCache.class,
+      MeasureCache.class,
 
       // file system
       InputPathCache.class,
       PathResolver.class,
 
       // issues
-      AnalyzerIssueCache.class,
+      IssueCache.class,
 
       // Syntax highlighting and symbols
       ComponentDataCache.class,
index 0cbe96dd48f23eba1844f1f90789e71fcde56ba4..146761ad94f06e4602947881d7b102cbc452e6d6 100644 (file)
@@ -27,6 +27,7 @@ import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.Issue.Severity;
 import org.sonar.batch.mediumtest.BatchMediumTester;
 import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult;
 import org.sonar.batch.protocol.input.ActiveRule;
@@ -91,7 +92,7 @@ public class IssuesMediumTest {
       .property("sonar.oneIssuePerLine.forceSeverity", "CRITICAL")
       .start();
 
-    assertThat(result.issues().iterator().next().severity()).isEqualTo("CRITICAL");
+    assertThat(result.issues().iterator().next().overridenSeverity()).isEqualTo(Severity.CRITICAL);
   }
 
   @Test
index a93e87dfe2a1676ecb1508887d82f340f4161170..865e3b50f6bf472d6e5cd49fcb469ff4f2ce9f51 100644 (file)
@@ -31,7 +31,7 @@ import org.sonar.api.batch.fs.internal.DefaultFileSystem;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueBuilder;
+import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
 import org.sonar.api.component.ResourcePerspectives;
 import org.sonar.api.config.Settings;
@@ -84,7 +84,7 @@ public class SensorContextAdapterTest {
     assertThat(adaptor.fileSystem()).isEqualTo(fs);
     assertThat(adaptor.settings()).isEqualTo(settings);
 
-    assertThat(adaptor.issueBuilder()).isNotNull();
+    assertThat(adaptor.newIssue()).isNotNull();
     assertThat(adaptor.newMeasure()).isNotNull();
   }
 
@@ -116,13 +116,12 @@ public class SensorContextAdapterTest {
 
     when(issuable.addIssue(argumentCaptor.capture())).thenReturn(true);
 
-    adaptor.addIssue(new DefaultIssueBuilder()
+    adaptor.store(new DefaultIssue()
       .onFile(file)
       .ruleKey(RuleKey.of("foo", "bar"))
       .message("Foo")
       .atLine(3)
-      .effortToFix(10.0)
-      .build());
+      .effortToFix(10.0));
 
     Issue issue = argumentCaptor.getValue();
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar"));
index f01ab0fa900d05443fecb33f0251c14d4c70b2b4..a0be6e447ab49ece9cccb8f16612deb0b7edc502 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.api.batch.sensor;
 
-import com.google.common.annotations.Beta;
 import org.sonar.api.BatchExtension;
 
 /**
@@ -32,9 +31,8 @@ import org.sonar.api.BatchExtension;
  * For example the Cobertura Sensor parses Cobertura report and saves the first-level of measures on files.
  * </p>
  *
- * @since 4.4
+ * @since 5.0
  */
-@Beta
 public interface Sensor extends BatchExtension {
 
   /**
index 016bda15f9412eabb90aee250651b7eeac27ad20..b79471f7975904a9babc8c62211bd0fe3fb7cca5 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.api.batch.sensor;
 
-import com.google.common.annotations.Beta;
 import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.rule.ActiveRules;
@@ -28,7 +27,6 @@ import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
 import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
 import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder;
 import org.sonar.api.batch.sensor.issue.Issue;
-import org.sonar.api.batch.sensor.issue.IssueBuilder;
 import org.sonar.api.batch.sensor.measure.Measure;
 import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder;
 import org.sonar.api.batch.sensor.test.TestCase;
@@ -41,9 +39,9 @@ import java.io.Serializable;
 import java.util.List;
 
 /**
- * @since 4.4
+ * See {@link Sensor#execute(SensorContext)}
+ * @since 5.0
  */
-@Beta
 public interface SensorContext {
 
   /**
@@ -64,26 +62,16 @@ public interface SensorContext {
   // ----------- MEASURES --------------
 
   /**
-   * Builder to create a new {@link Measure}.
+   * Fluent builder to create a new {@link Measure}. Don't forget to call {@link Measure#save()} once all parameters are provided.
    */
   <G extends Serializable> Measure<G> newMeasure();
 
   // ----------- ISSUES --------------
 
   /**
-   * Builder to create a new {@link Issue}.
+   * Fluent builder to create a new {@link Issue}. Don't forget to call {@link Issue#save()} once all parameters are provided.
    */
-  IssueBuilder issueBuilder();
-
-  /**
-   * Add an issue. Use {@link #issueBuilder()} to create the new issue.
-   * @return <code>true</code> if the new issue is registered, <code>false</code> if:
-   * <ul>
-   * <li>the rule does not exist</li>
-   * <li>the rule is disabled in the Quality profile</li>
-   * </ul>
-   */
-  boolean addIssue(Issue issue);
+  Issue newIssue();
 
   // ------------ HIGHLIGHTING ------------
 
index 9fcd030e553f496d29d48215cae640138006b947..a2187c13c4952817de34208d20326fe97058be95 100644 (file)
  */
 package org.sonar.api.batch.sensor;
 
-import com.google.common.annotations.Beta;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.measure.Metric;
 
 /**
  * Describe what an {@link Sensor} is doing. Information may be used by the platform
  * to log interesting information or perform some optimization.
- * @since 4.4
+ * See {@link Sensor#describe(SensorDescriptor)}
+ * @since 5.0
  */
-@Beta
 public interface SensorDescriptor {
 
   /**
index c48035c810150236775ad09c3a516dcc9a824519..ce2bbc1dbd3da000cc53fa014aee8dd1b6c21ce9 100644 (file)
  */
 package org.sonar.api.batch.sensor;
 
+import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.measure.Measure;
+
 /**
  * Interface for storing data computed by sensors.
+ * @since 5.0
  */
-public interface SensorStorage<G> {
+public interface SensorStorage {
+
+  void store(Measure measure);
 
-  void store(G data);
+  void store(Issue issue);
 
 }
index a8d2512542af2ccccb30734bc5e669bc3f87ab18..e126ddef95b669249a7f73eeda9f143222a3e0f6 100644 (file)
 package org.sonar.api.batch.sensor.issue;
 
 import com.google.common.annotations.Beta;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputPath;
 import org.sonar.api.batch.sensor.Sensor;
 import org.sonar.api.rule.RuleKey;
 
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 
 /**
- * Issue reported by an {@link Sensor}
+ * Represents an issue detected by a {@link Sensor}.
  *
- * @since 4.4
+ * @since 5.0
  */
 @Beta
 public interface Issue {
 
+  public enum Severity {
+    INFO,
+    MINOR,
+    MAJOR,
+    CRITICAL,
+    BLOCKER;
+  }
+
   /**
-   * The {@link InputPath} this issue belongs to. Returns null if issue is global to the project.
+   * The {@link RuleKey} of the issue.
    */
-  @CheckForNull
-  InputPath inputPath();
+  Issue ruleKey(RuleKey ruleKey);
 
   /**
    * The {@link RuleKey} of this issue.
@@ -46,10 +56,31 @@ public interface Issue {
   RuleKey ruleKey();
 
   /**
-   * Message of the issue.
+   * The {@link InputFile} the issue belongs to. For global issues call {@link #onProject()}.
+   */
+  Issue onFile(InputFile file);
+
+  /**
+   * The {@link InputDir} the issue belongs to. For global issues call {@link #onProject()}.
+   */
+  Issue onDir(InputDir inputDir);
+
+  /**
+   * Tell that the issue is global to the project.
+   */
+  Issue onProject();
+
+  /**
+   * The {@link InputPath} this issue belongs to. Returns null if issue is global to the project.
    */
   @CheckForNull
-  String message();
+  InputPath inputPath();
+
+  /**
+   * Line of the issue. Only available for {@link #onFile(InputFile)} issues. 
+   * If no line is specified it means that issue is global to the file.
+   */
+  Issue atLine(int line);
 
   /**
    * Line of the issue. Null for global issues and issues on directories. Can also be null
@@ -58,6 +89,11 @@ public interface Issue {
   @CheckForNull
   Integer line();
 
+  /**
+   * Effort to fix the issue.
+   */
+  Issue effortToFix(@Nullable Double effortToFix);
+
   /**
    * Effort to fix the issue. Used by technical debt model.
    */
@@ -65,10 +101,32 @@ public interface Issue {
   Double effortToFix();
 
   /**
-   * See constants in {@link org.sonar.api.rule.Severity}.
-   * Can be null before issue is saved. Means to use severity configured in quality profile.
+   * Message of the issue.
+   */
+  Issue message(String message);
+
+  /**
+   * Message of the issue.
    */
   @CheckForNull
-  String severity();
+  String message();
+
+  /**
+   * Override severity of the issue.
+   * Setting a null value or not calling this method means to use severity configured in quality profile.
+   */
+  Issue overrideSeverity(@Nullable Severity severity);
+
+  /**
+   * Overriden severity.
+   */
+  @CheckForNull
+  Severity overridenSeverity();
+
+  /**
+   * Save the issue. If rule key is unknow or rule not enabled in the current quality profile then a warning is logged but no exception
+   * is thrown.
+   */
+  void save();
 
 }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/IssueBuilder.java
deleted file mode 100644 (file)
index f6b4fa8..0000000
+++ /dev/null
@@ -1,85 +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.batch.sensor.issue;
-
-import com.google.common.annotations.Beta;
-import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-
-import javax.annotation.Nullable;
-
-/**
- * Builder for {@link Issue}.
- *
- * @since 4.4
- */
-@Beta
-public interface IssueBuilder {
-
-  /**
-   * The {@link RuleKey} of the issue.
-   */
-  IssueBuilder ruleKey(RuleKey ruleKey);
-
-  /**
-   * The {@link InputFile} the issue belongs to. For global issues call {@link #onProject()}.
-   */
-  IssueBuilder onFile(InputFile file);
-
-  /**
-   * The {@link InputDir} the issue belongs to. For global issues call {@link #onProject()}.
-   */
-  IssueBuilder onDir(InputDir inputDir);
-
-  /**
-   * Tell that the issue is global to the project.
-   */
-  IssueBuilder onProject();
-
-  /**
-   * Line of the issue. Only available for {@link #onFile(InputFile)} issues. 
-   * If no line is specified it means that issue is global to the file.
-   */
-  IssueBuilder atLine(int line);
-
-  /**
-   * Effort to fix the issue.
-   */
-  IssueBuilder effortToFix(@Nullable Double effortToFix);
-
-  /**
-   * Message of the issue.
-   */
-  IssueBuilder message(String message);
-
-  /**
-   * Severity of the issue. See {@link Severity}.
-   * Setting a null value means to use severity configured in quality profile.
-   */
-  IssueBuilder severity(@Nullable String severity);
-
-  /**
-   * Build the issue. After call of this method the builder is cleaned and can be used to build another issue.
-   */
-  Issue build();
-
-}
index f3b56f73b6c77cab8fa1a308431a3113bff8c11c..23148378f35abfe3e29dfa98896ee917a57ec73f 100644 (file)
@@ -23,82 +23,152 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import org.apache.commons.lang.builder.ToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputPath;
+import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.issue.Issue;
 import org.sonar.api.rule.RuleKey;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
-import java.io.Serializable;
 import java.util.UUID;
 
-public class DefaultIssue implements Issue, Serializable {
+public class DefaultIssue implements Issue {
 
-  private final String key;
-  private final InputPath inputPath;
-  private final RuleKey ruleKey;
+  private static final String INPUT_DIR_SHOULD_BE_NON_NULL = "InputDir should be non null";
+  private static final String INPUT_FILE_SHOULD_BE_NON_NULL = "InputFile should be non null";
+  private static final String ON_FILE_OR_ON_DIR_ALREADY_CALLED = "onFile or onDir already called";
+  private static final String ON_PROJECT_ALREADY_CALLED = "onProject already called";
+  private String key;
+  private boolean onProject = false;
+  private InputPath path;
+  private RuleKey ruleKey;
   private String message;
-  private final Integer line;
-  private final Double effortToFix;
-  private String severity;
-
-  DefaultIssue(DefaultIssueBuilder builder) {
-    Preconditions.checkNotNull(builder.ruleKey, "ruleKey is mandatory on issue");
-    this.inputPath = builder.path;
-    this.ruleKey = builder.ruleKey;
-    this.message = builder.message;
-    this.line = builder.line;
-    this.effortToFix = builder.effortToFix;
-    this.severity = builder.severity;
-    this.key = builder.key == null ? UUID.randomUUID().toString() : builder.key;
-    Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key");
+  private Integer line;
+  private Double effortToFix;
+  private Severity overridenSeverity;
+  private final SensorStorage storage;
+
+  public DefaultIssue() {
+    this.storage = null;
   }
 
-  public String key() {
-    return key;
+  public DefaultIssue(SensorStorage storage) {
+    this.storage = storage;
   }
 
   @Override
-  @Nullable
-  public InputPath inputPath() {
-    return inputPath;
+  public DefaultIssue ruleKey(RuleKey ruleKey) {
+    this.ruleKey = ruleKey;
+    return this;
   }
 
   @Override
-  public RuleKey ruleKey() {
-    return ruleKey;
+  public DefaultIssue onFile(InputFile file) {
+    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
+    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
+    Preconditions.checkNotNull(file, INPUT_FILE_SHOULD_BE_NON_NULL);
+    this.path = file;
+    return this;
   }
 
-  @CheckForNull
   @Override
-  public String message() {
-    return message;
+  public DefaultIssue onDir(InputDir dir) {
+    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
+    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
+    Preconditions.checkNotNull(dir, INPUT_DIR_SHOULD_BE_NON_NULL);
+    this.path = dir;
+    return this;
+  }
+
+  @Override
+  public DefaultIssue onProject() {
+    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
+    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
+    this.onProject = true;
+    return this;
+  }
+
+  @Override
+  public DefaultIssue atLine(int line) {
+    Preconditions.checkState(this.path != null && this.path instanceof InputFile, "atLine should be called after onFile");
+    this.line = line;
+    return this;
+  }
+
+  @Override
+  public DefaultIssue effortToFix(@Nullable Double effortToFix) {
+    this.effortToFix = effortToFix;
+    return this;
   }
 
-  public void setMessage(String message) {
+  @Override
+  public DefaultIssue message(String message) {
     this.message = message;
+    return this;
+  }
+
+  @Override
+  public Issue overrideSeverity(@Nullable Severity severity) {
+    this.overridenSeverity = severity;
+    return this;
+  }
+
+  @Override
+  public RuleKey ruleKey() {
+    return this.ruleKey;
+  }
+
+  @CheckForNull
+  @Override
+  public InputPath inputPath() {
+    return this.path;
   }
 
   @Override
   public Integer line() {
-    return line;
+    return this.line;
+  }
+
+  @Override
+  public String message() {
+    return this.message;
+  }
+
+  @Override
+  public Severity overridenSeverity() {
+    return this.overridenSeverity;
   }
 
   @Override
-  @Nullable
   public Double effortToFix() {
-    return effortToFix;
+    return this.effortToFix;
+  }
+
+  public String key() {
+    return this.key;
   }
 
   @Override
-  @CheckForNull
-  public String severity() {
-    return severity;
+  public void save() {
+    Preconditions.checkNotNull(this.storage, "No persister on this object");
+    Preconditions.checkNotNull(this.ruleKey, "ruleKey is mandatory on issue");
+    if (this.key == null) {
+      this.key = UUID.randomUUID().toString();
+    }
+    Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key");
+
+    storage.store(this);
   }
 
-  public void setSeverity(String severity) {
-    this.severity = severity;
+  /**
+   * For testing only.
+   */
+  public DefaultIssue withKey(String key) {
+    this.key = key;
+    return this;
   }
 
   @Override
@@ -122,5 +192,4 @@ public class DefaultIssue implements Issue, Serializable {
   public String toString() {
     return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
   }
-
 }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueBuilder.java
deleted file mode 100644 (file)
index 10c0c71..0000000
+++ /dev/null
@@ -1,131 +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.batch.sensor.issue.internal;
-
-import com.google.common.base.Preconditions;
-import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputPath;
-import org.sonar.api.batch.sensor.issue.IssueBuilder;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-
-import javax.annotation.Nullable;
-
-public class DefaultIssueBuilder implements IssueBuilder {
-
-  private static final String INPUT_DIR_SHOULD_BE_NON_NULL = "InputDir should be non null";
-  private static final String INPUT_FILE_SHOULD_BE_NON_NULL = "InputFile should be non null";
-  private static final String ON_FILE_OR_ON_DIR_ALREADY_CALLED = "onFile or onDir already called";
-  private static final String ON_PROJECT_ALREADY_CALLED = "onProject already called";
-  String key;
-  boolean onProject = false;
-  InputPath path;
-  RuleKey ruleKey;
-  String message;
-  Integer line;
-  Double effortToFix;
-  String severity;
-
-  @Override
-  public DefaultIssueBuilder ruleKey(RuleKey ruleKey) {
-    this.ruleKey = ruleKey;
-    return this;
-  }
-
-  @Override
-  public DefaultIssueBuilder onFile(InputFile file) {
-    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
-    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
-    Preconditions.checkNotNull(file, INPUT_FILE_SHOULD_BE_NON_NULL);
-    this.path = file;
-    return this;
-  }
-
-  @Override
-  public DefaultIssueBuilder onDir(InputDir dir) {
-    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
-    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
-    Preconditions.checkNotNull(dir, INPUT_DIR_SHOULD_BE_NON_NULL);
-    this.path = dir;
-    return this;
-  }
-
-  @Override
-  public DefaultIssueBuilder onProject() {
-    Preconditions.checkState(!this.onProject, ON_PROJECT_ALREADY_CALLED);
-    Preconditions.checkState(this.path == null, ON_FILE_OR_ON_DIR_ALREADY_CALLED);
-    this.onProject = true;
-    return this;
-  }
-
-  @Override
-  public DefaultIssueBuilder atLine(int line) {
-    Preconditions.checkState(this.path != null && this.path instanceof InputFile, "atLine should be called after onFile");
-    this.line = line;
-    return this;
-  }
-
-  @Override
-  public DefaultIssueBuilder effortToFix(@Nullable Double effortToFix) {
-    this.effortToFix = effortToFix;
-    return this;
-  }
-
-  @Override
-  public DefaultIssueBuilder message(String message) {
-    this.message = message;
-    return this;
-  }
-
-  @Override
-  public IssueBuilder severity(@Nullable String severity) {
-    Preconditions.checkState(severity == null || Severity.ALL.contains(severity), "Invalid severity: " + severity);
-    this.severity = severity;
-    return this;
-  }
-
-  /**
-   * For testing only.
-   */
-  public DefaultIssueBuilder withKey(String key) {
-    this.key = key;
-    return this;
-  }
-
-  @Override
-  public DefaultIssue build() {
-    DefaultIssue result = new DefaultIssue(this);
-    reset();
-    return result;
-  }
-
-  private void reset() {
-    key = null;
-    onProject = false;
-    path = null;
-    ruleKey = null;
-    message = null;
-    line = null;
-    effortToFix = null;
-    severity = null;
-  }
-
-}
index 2ce2cf983611e1054340dd86ecb020f7c62bb795..86a0abdffadb2729a4490750db8371240993c65b 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.api.batch.sensor.measure;
 
-import com.google.common.annotations.Beta;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.measure.Metric;
 
@@ -29,9 +28,8 @@ import java.io.Serializable;
 
 /**
  * Builder to create new Measure.
- * @since 4.4
+ * @since 5.0
  */
-@Beta
 public interface Measure<G extends Serializable> {
 
   /**
index f6b191355c70234a6456d0635ca34750c3e69abe..fee7172f9eaa7a030c10dbe32858b6b303c8dd9b 100644 (file)
@@ -36,7 +36,7 @@ import java.io.Serializable;
 
 public class DefaultMeasure<G extends Serializable> implements Measure<G> {
 
-  private final SensorStorage<DefaultMeasure<G>> measureStorage;
+  private final SensorStorage storage;
   private boolean onProject = false;
   private InputFile file;
   private Metric<G> metric;
@@ -44,11 +44,11 @@ public class DefaultMeasure<G extends Serializable> implements Measure<G> {
   private boolean saved = false;
 
   public DefaultMeasure() {
-    this.measureStorage = null;
+    this.storage = null;
   }
 
-  public DefaultMeasure(@Nullable SensorStorage<DefaultMeasure<G>> measureStorage) {
-    this.measureStorage = measureStorage;
+  public DefaultMeasure(@Nullable SensorStorage storage) {
+    this.storage = storage;
   }
 
   @Override
@@ -86,14 +86,12 @@ public class DefaultMeasure<G extends Serializable> implements Measure<G> {
 
   @Override
   public void save() {
-    Preconditions.checkNotNull(this.measureStorage, "No persister on this object");
+    Preconditions.checkNotNull(this.storage, "No persister on this object");
     Preconditions.checkState(!saved, "This measure was already saved");
     Preconditions.checkNotNull(this.value, "Measure value can't be null");
     Preconditions.checkNotNull(this.metric, "Measure metric can't be null");
     Preconditions.checkState(this.metric.valueType().equals(this.value.getClass()), "Measure value should be of type " + this.metric.valueType());
-    if (measureStorage != null) {
-      measureStorage.store(this);
-    }
+    storage.store((Measure<Serializable>) this);
     this.saved = true;
   }
 
index 6c0d12da82c17d4ec5b296c3d57ad738d14f5d57..722f09481208fb798d406b12b73ace3ccabc3419 100644 (file)
@@ -23,10 +23,12 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.rule.RuleKey;
 
 import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 public class DefaultIssueTest {
 
@@ -35,58 +37,56 @@ public class DefaultIssueTest {
 
   @Test
   public void build_file_issue() {
-    Issue issue = new DefaultIssueBuilder()
+    SensorStorage storage = mock(SensorStorage.class);
+    DefaultIssue issue = new DefaultIssue(storage)
       .onFile(new DefaultInputFile("foo", "src/Foo.php"))
       .ruleKey(RuleKey.of("repo", "rule"))
       .atLine(1)
       .effortToFix(10.0)
-      .message("Wrong way!")
-      .build();
+      .message("Wrong way!");
 
     assertThat(issue.inputPath()).isEqualTo(new DefaultInputFile("foo", "src/Foo.php"));
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
     assertThat(issue.line()).isEqualTo(1);
     assertThat(issue.effortToFix()).isEqualTo(10.0);
     assertThat(issue.message()).isEqualTo("Wrong way!");
+
+    issue.save();
+
+    verify(storage).store(issue);
   }
 
   @Test
   public void build_project_issue() {
-    Issue issue = new DefaultIssueBuilder()
+    SensorStorage storage = mock(SensorStorage.class);
+    DefaultIssue issue = new DefaultIssue(storage)
       .onProject()
       .ruleKey(RuleKey.of("repo", "rule"))
       .effortToFix(10.0)
-      .message("Wrong way!")
-      .build();
+      .message("Wrong way!");
 
     assertThat(issue.inputPath()).isNull();
     assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
     assertThat(issue.line()).isNull();
     assertThat(issue.effortToFix()).isEqualTo(10.0);
     assertThat(issue.message()).isEqualTo("Wrong way!");
+
+    issue.save();
+
+    verify(storage).store(issue);
   }
 
   @Test
   public void not_allowed_to_call_onFile_and_onProject() {
     thrown.expect(IllegalStateException.class);
     thrown.expectMessage("onProject already called");
-    new DefaultIssueBuilder()
+    new DefaultIssue()
       .onProject()
       .onFile(new DefaultInputFile("foo", "src/Foo.php"))
       .ruleKey(RuleKey.of("repo", "rule"))
       .atLine(1)
       .effortToFix(10.0)
-      .message("Wrong way!")
-      .build();
-  }
-
-  @Test
-  public void validate_severity() {
-    thrown.expect(IllegalStateException.class);
-    thrown.expectMessage("Invalid severity: FOO");
-    new DefaultIssueBuilder()
-      .severity("FOO")
-      .build();
+      .message("Wrong way!");
   }
 
 }
index 7085ca901695a7ecab759aff1510c8f33917811a..7fa5fbfc593e0c0434057b86aaa832c4d985aa8c 100644 (file)
@@ -37,8 +37,8 @@ public class DefaultMeasureTest {
 
   @Test
   public void build_file_measure() {
-    SensorStorage<DefaultMeasure<Integer>> persister = mock(SensorStorage.class);
-    DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(persister)
+    SensorStorage storage = mock(SensorStorage.class);
+    DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(storage)
       .forMetric(CoreMetrics.LINES)
       .onFile(new DefaultInputFile("foo", "src/Foo.php"))
       .withValue(3);
@@ -49,13 +49,13 @@ public class DefaultMeasureTest {
 
     newMeasure.save();
 
-    verify(persister).store(newMeasure);
+    verify(storage).store(newMeasure);
   }
 
   @Test
   public void build_project_measure() {
-    SensorStorage<DefaultMeasure<Integer>> persister = mock(SensorStorage.class);
-    DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(persister)
+    SensorStorage storage = mock(SensorStorage.class);
+    DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(storage)
       .forMetric(CoreMetrics.LINES)
       .onProject()
       .withValue(3);
@@ -66,7 +66,7 @@ public class DefaultMeasureTest {
 
     newMeasure.save();
 
-    verify(persister).store(newMeasure);
+    verify(storage).store(newMeasure);
   }
 
   @Test