]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5931 Cleanup dependency API
authorJulien HENRY <julien.henry@sonarsource.com>
Tue, 17 Feb 2015 17:47:59 +0000 (18:47 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Tue, 17 Feb 2015 17:56:29 +0000 (18:56 +0100)
19 files changed:
sonar-batch/src/main/java/org/sonar/batch/dependency/DefaultDependencyValueCoder.java
sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java
sonar-batch/src/main/java/org/sonar/batch/deprecated/DeprecatedSensorContext.java
sonar-batch/src/main/java/org/sonar/batch/index/BatchResource.java
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
sonar-batch/src/main/java/org/sonar/batch/index/DependencyPersister.java
sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorContext.java
sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
sonar-batch/src/test/java/org/sonar/batch/mediumtest/dependency/DependencyMediumTest.java
sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorContextTest.java
sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.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/dependency/Dependency.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/NewDependency.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/internal/DefaultDependency.java
sonar-plugin-api/src/main/java/org/sonar/api/design/Dependency.java

index 8f01f2c233b0d21d91362c0888e268fd19702bc7..6dd1202dc42a29e93ba4e3d78633a44336b0f8a6 100644 (file)
@@ -22,47 +22,26 @@ package org.sonar.batch.dependency;
 import com.persistit.Value;
 import com.persistit.encoding.CoderContext;
 import com.persistit.encoding.ValueCoder;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
-import org.sonar.batch.scan.filesystem.InputPathCache;
 
 class DefaultDependencyValueCoder implements ValueCoder {
 
-  private InputPathCache inputPathCache;
-
-  public DefaultDependencyValueCoder(InputPathCache inputPathCache) {
-    this.inputPathCache = inputPathCache;
-  }
-
   @Override
   public void put(Value value, Object object, CoderContext context) {
     DefaultDependency dep = (DefaultDependency) object;
-    value.putUTF(((DefaultInputFile) dep.from()).moduleKey());
-    value.putUTF(((DefaultInputFile) dep.from()).relativePath());
-    value.putUTF(((DefaultInputFile) dep.to()).moduleKey());
-    value.putUTF(((DefaultInputFile) dep.to()).relativePath());
+    value.putUTF(dep.fromKey());
+    value.putUTF(dep.toKey());
     value.put(dep.weight());
   }
 
   @Override
   public Object get(Value value, Class clazz, CoderContext context) {
-    String fromModuleKey = value.getString();
-    String fromRelativePath = value.getString();
-    InputFile from = inputPathCache.getFile(fromModuleKey, fromRelativePath);
-    if (from == null) {
-      throw new IllegalStateException("Unable to load InputFile " + fromModuleKey + ":" + fromRelativePath);
-    }
-    String toModuleKey = value.getString();
-    String toRelativePath = value.getString();
-    InputFile to = inputPathCache.getFile(toModuleKey, toRelativePath);
-    if (to == null) {
-      throw new IllegalStateException("Unable to load InputFile " + toModuleKey + ":" + toRelativePath);
-    }
+    String fromKey = value.getString();
+    String toKey = value.getString();
     int weight = value.getInt();
     return new DefaultDependency()
-      .from(from)
-      .to(to)
-      .weight(weight);
+      .setFromKey(fromKey)
+      .setToKey(toKey)
+      .setWeight(weight);
   }
 }
index 9e3709a55325860c0a02777834f0dd9087c7fa77..50ce7577c7b6f3fda981d22e9717dbc541412195 100644 (file)
@@ -21,14 +21,10 @@ package org.sonar.batch.dependency;
 
 import com.google.common.base.Preconditions;
 import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.sensor.dependency.Dependency;
 import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
 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;
 
 import javax.annotation.CheckForNull;
 
@@ -38,29 +34,29 @@ import javax.annotation.CheckForNull;
  */
 public class DependencyCache implements BatchComponent {
 
-  private final Cache<Dependency> cache;
+  private final Cache<DefaultDependency> cache;
 
-  public DependencyCache(Caches caches, InputPathCache inputPathCache) {
-    caches.registerValueCoder(DefaultDependency.class, new DefaultDependencyValueCoder(inputPathCache));
+  public DependencyCache(Caches caches) {
+    caches.registerValueCoder(DefaultDependency.class, new DefaultDependencyValueCoder());
     cache = caches.createCache("dependencies");
   }
 
-  public Iterable<Entry<Dependency>> entries() {
+  public Iterable<Entry<DefaultDependency>> entries() {
     return cache.entries();
   }
 
   @CheckForNull
-  public Dependency get(String moduleKey, InputFile from, InputFile to) {
+  public DefaultDependency get(String moduleKey, String fromKey, String toKey) {
     Preconditions.checkNotNull(moduleKey);
-    Preconditions.checkNotNull(from);
-    Preconditions.checkNotNull(to);
-    return cache.get(moduleKey, ((DefaultInputFile) from).key(), ((DefaultInputFile) to).key());
+    Preconditions.checkNotNull(fromKey);
+    Preconditions.checkNotNull(toKey);
+    return cache.get(moduleKey, fromKey, toKey);
   }
 
-  public DependencyCache put(String moduleKey, Dependency dependency) {
+  public DependencyCache put(String moduleKey, DefaultDependency dependency) {
     Preconditions.checkNotNull(moduleKey);
     Preconditions.checkNotNull(dependency);
-    cache.put(moduleKey, ((DefaultInputFile) dependency.from()).key(), ((DefaultInputFile) dependency.to()).key(), dependency);
+    cache.put(moduleKey, dependency.fromKey(), dependency.toKey(), dependency);
     return this;
   }
 
index 6c7146c6e61eb16e95279bae63305cfc27b27ad6..a8d96036863aabf5a2d29495d04a207393bf2ee0 100644 (file)
@@ -40,7 +40,6 @@ import org.sonar.api.measures.Metric;
 import org.sonar.api.resources.*;
 import org.sonar.api.rules.Violation;
 import org.sonar.api.utils.SonarException;
-import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.batch.sensor.DefaultSensorContext;
 import org.sonar.batch.sensor.coverage.CoverageExclusions;
@@ -63,8 +62,8 @@ public class DeprecatedSensorContext extends DefaultSensorContext implements Sen
 
   public DeprecatedSensorContext(SonarIndex index, Project project, Settings settings, FileSystem fs, ActiveRules activeRules,
     AnalysisMode analysisMode, ComponentDataCache componentDataCache, CoverageExclusions coverageFilter,
-    DuplicationCache duplicationCache, SensorStorage sensorStorage) {
-    super(settings, fs, activeRules, analysisMode, componentDataCache, duplicationCache, sensorStorage);
+    SensorStorage sensorStorage) {
+    super(settings, fs, activeRules, analysisMode, componentDataCache, sensorStorage);
     this.index = index;
     this.project = project;
     this.coverageFilter = coverageFilter;
index 10d4b9d543e7ee3ff85a8d51bb26953d4dd7bf4c..a07eded789c9bb694c1460faf49ebcf84a0e2272 100644 (file)
@@ -46,6 +46,10 @@ public class BatchResource {
     }
   }
 
+  public String key() {
+    return r.getEffectiveKey();
+  }
+
   public int batchId() {
     return batchId;
   }
index e551d46250796f005accd18c9d19b3ee918883cc..0e2c128b1857f0092a2676581060913f14bfe311 100644 (file)
@@ -114,9 +114,9 @@ public class DefaultIndex extends SonarIndex {
     this.measureCache = measureCache;
   }
 
-  public DefaultIndex(ResourceCache resourceCache, ProjectTree projectTree, MetricFinder metricFinder, MeasureCache measureCache) {
+  public DefaultIndex(ResourceCache resourceCache, DependencyPersister dependencyPersister, ProjectTree projectTree, MetricFinder metricFinder, MeasureCache measureCache) {
     this.resourceCache = resourceCache;
-    this.dependencyPersister = null;
+    this.dependencyPersister = dependencyPersister;
     this.linkPersister = null;
     this.eventPersister = null;
     this.projectTree = projectTree;
@@ -188,6 +188,12 @@ public class DefaultIndex extends SonarIndex {
       }
     }
 
+    // store dependencies
+    for (Dependency dep : dependencies) {
+      dependencyPersister.saveDependency(currentProject, dep);
+    }
+
+    // Keep only inter module dependencies
     Set<Dependency> projectDependencies = getDependenciesBetweenProjects();
     dependencies.clear();
     incomingDependenciesByResource.clear();
@@ -268,8 +274,10 @@ public class DefaultIndex extends SonarIndex {
     // Reload resources
     Resource from = getResource(dependency.getFrom());
     Preconditions.checkArgument(from != null, dependency.getFrom() + " is not indexed");
+    dependency.setFrom(from);
     Resource to = getResource(dependency.getTo());
     Preconditions.checkArgument(to != null, dependency.getTo() + " is not indexed");
+    dependency.setTo(to);
 
     Dependency existingDep = getEdge(from, to);
     if (existingDep != null) {
@@ -280,10 +288,7 @@ public class DefaultIndex extends SonarIndex {
     if (parentDependency != null) {
       addDependency(parentDependency);
     }
-
-    if (registerDependency(dependency) && dependencyPersister != null) {
-      dependencyPersister.saveDependency(currentProject, from, to, dependency, parentDependency);
-    }
+    registerDependency(dependency);
     return dependency;
   }
 
index 15886b6b4ac17209aa4516bcb552a71932fa6c20..13c73e278f5b39cee451862f1160352ff051f644 100644 (file)
  */
 package org.sonar.batch.index;
 
+import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
 import org.sonar.api.database.DatabaseSession;
 import org.sonar.api.design.Dependency;
 import org.sonar.api.design.DependencyDto;
 import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
+import org.sonar.batch.dependency.DependencyCache;
+
+import javax.annotation.Nullable;
 
 public final class DependencyPersister {
 
-  private ResourceCache resourceCache;
-  private DatabaseSession session;
+  private final ResourceCache resourceCache;
+  private final DatabaseSession session;
+  private final DependencyCache dependencyCache;
 
-  public DependencyPersister(ResourceCache resourceCache, DatabaseSession session) {
+  public DependencyPersister(ResourceCache resourceCache, DependencyCache dependencyCache, @Nullable DatabaseSession session) {
     this.resourceCache = resourceCache;
+    this.dependencyCache = dependencyCache;
     this.session = session;
   }
 
-  public void saveDependency(Project project, Resource from, Resource to, Dependency dependency, Dependency parentDependency) {
-    BatchResource fromResource = resourceCache.get(from);
-    BatchResource toResource = resourceCache.get(to);
+  public DependencyPersister(ResourceCache resourceCache, DependencyCache dependencyCache) {
+    this(resourceCache, dependencyCache, null);
+  }
+
+  public void saveDependency(Project project, Dependency dependency) {
+    BatchResource fromResource = resourceCache.get(dependency.getFrom());
+    BatchResource toResource = resourceCache.get(dependency.getTo());
     BatchResource projectResource = resourceCache.get(project);
 
+    if (fromResource.isFile() && toResource.isFile()) {
+      dependencyCache.put(project.getEffectiveKey(), new DefaultDependency().setFromKey(fromResource.key()).setToKey(toResource.key()).setWeight(dependency.getWeight()));
+    }
+
+    if (session != null) {
+      saveInDB(project, dependency, fromResource, toResource, projectResource);
+    }
+  }
+
+  private void saveInDB(Project project, Dependency dependency, BatchResource fromResource, BatchResource toResource, BatchResource projectResource) {
     DependencyDto model = new DependencyDto();
     model.setProjectSnapshotId(projectResource.snapshotId());
     model.setUsage(dependency.getUsage());
@@ -53,8 +72,11 @@ public final class DependencyPersister {
     model.setToScope(toResource.resource().getScope());
     model.setToSnapshotId(toResource.snapshotId());
 
+    Dependency parentDependency = dependency.getParent();
     if (parentDependency != null) {
-      // assume that it has been previously saved
+      if (parentDependency.getId() == null) {
+        saveDependency(project, parentDependency);
+      }
       model.setParentDependencyId(parentDependency.getId());
     }
     session.save(model);
index 8013dd54d9d7b6fd44fd5112a1e74da1a7a7e31c..245f85bd38d7cd261d6aa5e12bd5602abd3dcf7a 100644 (file)
@@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory;
 import org.sonar.api.batch.fs.InputDir;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.sensor.dependency.Dependency;
+import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
 import org.sonar.api.batch.sensor.duplication.Duplication;
 import org.sonar.api.batch.sensor.highlighting.TypeOfText;
 import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
@@ -92,7 +92,7 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
     storeDuplication(container);
     // storeTestCases(container);
     // storeCoveragePerTest(container);
-    // storeDependencies(container);
+    storeDependencies(container);
 
   }
 
@@ -174,7 +174,7 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
 
   private void storeDependencies(ProjectScanContainer container) {
     DependencyCache dependencyCache = container.getComponentByType(DependencyCache.class);
-    for (Entry<Dependency> entry : dependencyCache.entries()) {
+    for (Entry<DefaultDependency> entry : dependencyCache.entries()) {
       String fromKey = entry.key()[1].toString();
       String toKey = entry.key()[2].toString();
       if (!dependencies.containsKey(fromKey)) {
index 850b6e984bfa5bbb9337d10eebc606d4b632ec20..a2f46a03fe42dc1265a7f786cec30758c7b65e10 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.batch.bootstrap.ExtensionUtils;
 import org.sonar.batch.bootstrap.MetricProvider;
 import org.sonar.batch.debt.DebtModelProvider;
 import org.sonar.batch.debt.IssueChangelogDebtCalculator;
+import org.sonar.batch.dependency.DependencyCache;
 import org.sonar.batch.deprecated.components.DefaultResourceCreationLock;
 import org.sonar.batch.deprecated.components.PeriodsDefinition;
 import org.sonar.batch.duplication.DuplicationCache;
@@ -189,6 +190,10 @@ public class ProjectScanContainer extends ComponentContainer {
       // Duplications
       DuplicationCache.class,
 
+      // Dependencies
+      DependencyPersister.class,
+      DependencyCache.class,
+
       ProjectSettings.class,
 
       ScanTaskObservers.class);
@@ -196,7 +201,6 @@ public class ProjectScanContainer extends ComponentContainer {
 
   private void addDataBaseComponents() {
     add(
-      DependencyPersister.class,
       EventPersister.class,
       LinkPersister.class,
       MeasurePersister.class,
index 654134b051961aafbc2005ce9d973399046f0d7d..7dd0c1eab1c25147df2164fb4fca5a636432a5c0 100644 (file)
@@ -26,7 +26,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.rule.ActiveRules;
 import org.sonar.api.batch.sensor.SensorContext;
 import org.sonar.api.batch.sensor.SensorStorage;
-import org.sonar.api.batch.sensor.dependency.Dependency;
+import org.sonar.api.batch.sensor.dependency.NewDependency;
 import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
 import org.sonar.api.batch.sensor.duplication.NewDuplication;
 import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
@@ -43,7 +43,6 @@ import org.sonar.api.batch.sensor.test.internal.DefaultCoverage;
 import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseCoverage;
 import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution;
 import org.sonar.api.config.Settings;
-import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.highlighting.DefaultHighlightingBuilder;
 import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.batch.symbol.DefaultSymbolTableBuilder;
@@ -56,18 +55,16 @@ public class DefaultSensorContext implements SensorContext {
   private final FileSystem fs;
   private final ActiveRules activeRules;
   private final ComponentDataCache componentDataCache;
-  private final DuplicationCache duplicationCache;
   private final SensorStorage sensorStorage;
   private final AnalysisMode analysisMode;
 
   public DefaultSensorContext(Settings settings, FileSystem fs, ActiveRules activeRules, AnalysisMode analysisMode, ComponentDataCache componentDataCache,
-    DuplicationCache duplicationCache, SensorStorage sensorStorage) {
+    SensorStorage sensorStorage) {
     this.settings = settings;
     this.fs = fs;
     this.activeRules = activeRules;
     this.analysisMode = analysisMode;
     this.componentDataCache = componentDataCache;
-    this.duplicationCache = duplicationCache;
     this.sensorStorage = sensorStorage;
   }
 
@@ -132,7 +129,7 @@ public class DefaultSensorContext implements SensorContext {
   }
 
   @Override
-  public Dependency newDependency() {
+  public NewDependency newDependency() {
     return new DefaultDependency(sensorStorage);
   }
 
index 300fe651380c2b98f1e78f6ae9ff81a811da7387..d512c02ca9642f8295108f1d1856a647de70c12c 100644 (file)
@@ -58,6 +58,7 @@ import org.sonar.api.test.Testable;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.batch.index.DefaultIndex;
+import org.sonar.batch.index.ResourceCache;
 import org.sonar.batch.sensor.coverage.CoverageExclusions;
 import org.sonar.core.component.ComponentKeys;
 
@@ -70,17 +71,20 @@ public class DefaultSensorStorage implements SensorStorage {
   private final DefaultIndex sonarIndex;
   private final CoverageExclusions coverageExclusions;
   private final DuplicationCache duplicationCache;
+  private final ResourceCache resourceCache;
 
   public DefaultSensorStorage(MetricFinder metricFinder, Project project,
     ResourcePerspectives perspectives,
     Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache,
-    DuplicationCache duplicationCache, DefaultIndex sonarIndex, CoverageExclusions coverageExclusions) {
+    DuplicationCache duplicationCache, DefaultIndex sonarIndex, CoverageExclusions coverageExclusions,
+    ResourceCache resourceCache) {
     this.metricFinder = metricFinder;
     this.project = project;
     this.perspectives = perspectives;
     this.sonarIndex = sonarIndex;
     this.coverageExclusions = coverageExclusions;
     this.duplicationCache = duplicationCache;
+    this.resourceCache = resourceCache;
   }
 
   private Metric findMetricOrFail(String metricKey) {
@@ -241,10 +245,10 @@ public class DefaultSensorStorage implements SensorStorage {
 
   @Override
   public void store(org.sonar.api.batch.sensor.dependency.Dependency dep) {
-    File fromResource = getFile(dep.from());
-    File toResource = getFile(dep.to());
+    File fromResource = (File) resourceCache.get(dep.fromKey()).resource();
+    File toResource = (File) resourceCache.get(dep.toKey()).resource();
     if (sonarIndex.getEdge(fromResource, toResource) != null) {
-      throw new IllegalStateException("Dependency between " + dep.from() + " and " + dep.to() + " was already saved.");
+      throw new IllegalStateException("Dependency between " + dep.fromKey() + " and " + dep.toKey() + " was already saved.");
     }
     Directory fromParent = fromResource.getParent();
     Directory toParent = toResource.getParent();
index 4d562d4de879b5c7aaffb6c338b209f04bf61641..e7a08a4a37cb30b9e5a081ce478aa797dcda5f0c 100644 (file)
@@ -34,6 +34,8 @@ import org.sonar.xoo.XooPlugin;
 import java.io.File;
 import java.io.IOException;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 public class DependencyMediumTest {
 
   @Rule
@@ -85,8 +87,8 @@ public class DependencyMediumTest {
         .build())
       .start();
 
-    // assertThat(result.dependencyWeight(result.inputFile("src/sample.xoo"), result.inputFile("src/sample2.xoo"))).isEqualTo(3);
-    // assertThat(result.dependencyWeight(result.inputFile("src/sample.xoo"), result.inputFile("src/foo/sample3.xoo"))).isEqualTo(6);
+    assertThat(result.dependencyWeight(result.inputFile("src/sample.xoo"), result.inputFile("src/sample2.xoo"))).isEqualTo(3);
+    assertThat(result.dependencyWeight(result.inputFile("src/sample.xoo"), result.inputFile("src/foo/sample3.xoo"))).isEqualTo(6);
   }
 
 }
index 4f7fa7507ac45318876dc5ac8c1827f6deb431ed..19b12f7b972130d7728a51ca7b8a97f2a44575b6 100644 (file)
@@ -32,7 +32,6 @@ import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
 import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.config.Settings;
 import org.sonar.api.measures.CoreMetrics;
-import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.ComponentDataCache;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -65,7 +64,7 @@ public class DefaultSensorContextTest {
     ComponentDataCache componentDataCache = mock(ComponentDataCache.class);
     sensorStorage = mock(SensorStorage.class);
     analysisMode = mock(AnalysisMode.class);
-    adaptor = new DefaultSensorContext(settings, fs, activeRules, analysisMode, componentDataCache, mock(DuplicationCache.class), sensorStorage);
+    adaptor = new DefaultSensorContext(settings, fs, activeRules, analysisMode, componentDataCache, sensorStorage);
   }
 
   @Test
index a4ed0b085716c4e30c35111d84741d669c213873..02b526f0375d75e667d138e7fa8cdcf8108fdab1 100644 (file)
@@ -54,6 +54,7 @@ import org.sonar.api.rule.RuleKey;
 import org.sonar.batch.duplication.DuplicationCache;
 import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.batch.index.DefaultIndex;
+import org.sonar.batch.index.ResourceCache;
 import org.sonar.batch.sensor.coverage.CoverageExclusions;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -80,6 +81,8 @@ public class DefaultSensorStorageTest {
   private Project project;
   private DefaultIndex sonarIndex;
 
+  private ResourceCache resourceCache;
+
   @Before
   public void prepare() throws Exception {
     activeRules = new ActiveRulesBuilder().build();
@@ -94,8 +97,9 @@ public class DefaultSensorStorageTest {
     sonarIndex = mock(DefaultIndex.class);
     CoverageExclusions coverageExclusions = mock(CoverageExclusions.class);
     when(coverageExclusions.accept(any(Resource.class), any(Measure.class))).thenReturn(true);
+    resourceCache = new ResourceCache();
     sensorStorage = new DefaultSensorStorage(metricFinder, project,
-      resourcePerspectives, settings, fs, activeRules, componentDataCache, mock(DuplicationCache.class), sonarIndex, coverageExclusions);
+      resourcePerspectives, settings, fs, activeRules, componentDataCache, mock(DuplicationCache.class), sonarIndex, coverageExclusions, resourceCache);
   }
 
   @Test
@@ -248,10 +252,10 @@ public class DefaultSensorStorageTest {
   @Test
   public void shouldStoreDependencyInSameFolder() {
 
-    File foo = File.create("src/Foo.java");
-    File bar = File.create("src/Bar.java");
-    when(sonarIndex.getResource(foo)).thenReturn(foo);
-    when(sonarIndex.getResource(bar)).thenReturn(bar);
+    Resource foo = File.create("src/Foo.java").setEffectiveKey("foo:src/Foo.java");
+    Resource bar = File.create("src/Bar.java").setEffectiveKey("foo:src/Bar.java");
+    resourceCache.add(foo, null);
+    resourceCache.add(bar, null);
 
     sensorStorage.store(new DefaultDependency()
       .from(new DefaultInputFile("foo", "src/Foo.java").setType(Type.MAIN))
@@ -270,14 +274,15 @@ public class DefaultSensorStorageTest {
   @Test
   public void throw_if_attempt_to_save_same_dep_twice() {
 
-    File foo = File.create("src/Foo.java");
-    File bar = File.create("src/Bar.java");
-    when(sonarIndex.getResource(foo)).thenReturn(foo);
-    when(sonarIndex.getResource(bar)).thenReturn(bar);
+    Resource foo = File.create("src/Foo.java").setEffectiveKey("foo:src/Foo.java");
+    Resource bar = File.create("src/Bar.java").setEffectiveKey("foo:src/Bar.java");
+    resourceCache.add(foo, null);
+    resourceCache.add(bar, null);
+
     when(sonarIndex.getEdge(foo, bar)).thenReturn(new Dependency(foo, bar));
 
     thrown.expect(IllegalStateException.class);
-    thrown.expectMessage("Dependency between [moduleKey=foo, relative=src/Foo.java, basedir=null] and [moduleKey=foo, relative=src/Bar.java, basedir=null] was already saved.");
+    thrown.expectMessage("Dependency between foo:src/Foo.java and foo:src/Bar.java was already saved.");
 
     sensorStorage.store(new DefaultDependency()
       .from(new DefaultInputFile("foo", "src/Foo.java").setType(Type.MAIN))
@@ -288,10 +293,10 @@ public class DefaultSensorStorageTest {
   @Test
   public void shouldStoreDependencyInDifferentFolder() {
 
-    File foo = File.create("src1/Foo.java");
-    File bar = File.create("src2/Bar.java");
-    when(sonarIndex.getResource(foo)).thenReturn(foo);
-    when(sonarIndex.getResource(bar)).thenReturn(bar);
+    Resource foo = File.create("src1/Foo.java").setEffectiveKey("foo:src1/Foo.java");
+    Resource bar = File.create("src2/Bar.java").setEffectiveKey("foo:src2/Bar.java");
+    resourceCache.add(foo, null);
+    resourceCache.add(bar, null);
 
     sensorStorage.store(new DefaultDependency()
       .from(new DefaultInputFile("foo", "src1/Foo.java").setType(Type.MAIN))
@@ -318,12 +323,14 @@ public class DefaultSensorStorageTest {
   @Test
   public void shouldIncrementParentWeight() {
 
-    File foo = File.create("src1/Foo.java");
-    File bar = File.create("src2/Bar.java");
-    Directory src1 = Directory.create("src1");
-    Directory src2 = Directory.create("src2");
-    when(sonarIndex.getResource(foo)).thenReturn(foo);
-    when(sonarIndex.getResource(bar)).thenReturn(bar);
+    Resource src1 = Directory.create("src1").setEffectiveKey("foo:src1");
+    Resource src2 = Directory.create("src2").setEffectiveKey("foo:src2");
+    Resource foo = File.create("src1/Foo.java").setEffectiveKey("foo:src1/Foo.java");
+    Resource bar = File.create("src2/Bar.java").setEffectiveKey("foo:src2/Bar.java");
+    resourceCache.add(src1, null);
+    resourceCache.add(src2, null);
+    resourceCache.add(foo, src1);
+    resourceCache.add(bar, src2);
     Dependency parentDep = new Dependency(src1, src2).setWeight(4);
     when(sonarIndex.getEdge(src1, src2)).thenReturn(parentDep);
 
index 00fd00d8314730f38f8b29da9bf4362f4a8ecca8..6a5463e67f985f203983a16d8c11fbce077d2725 100644 (file)
@@ -192,14 +192,23 @@ public interface SensorContext extends org.sonar.api.batch.sensor.SensorContext
   // ----------- DEPENDENCIES BETWEEN RESOURCES --------------
 
   /**
-   * Build a new dependency : from depends upon to. The dependency is NOT saved. The method saveDependency() must still be executed.
+   * @deprecated since 5.1 use {@link #newDependency()}
    */
   Dependency saveDependency(Dependency dependency);
 
+  /**
+   * @deprecated since 5.1 Sensors should not read but only save data
+   */
   Set<Dependency> getDependencies();
 
+  /**
+   * @deprecated since 5.1 Sensors should not read but only save data
+   */
   Collection<Dependency> getIncomingDependencies(Resource to);
 
+  /**
+   * @deprecated since 5.1 Sensors should not read but only save data
+   */
   Collection<Dependency> getOutgoingDependencies(Resource from);
 
   // ----------- FILE SOURCES --------------
index b36786c2333fb52bd65b17173ba028bd41add509..a1de94d8b3fb788df65444065d8d844a6f64b46b 100644 (file)
@@ -24,7 +24,7 @@ import org.sonar.api.batch.CpdMapping;
 import org.sonar.api.batch.fs.FileSystem;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.batch.sensor.dependency.Dependency;
+import org.sonar.api.batch.sensor.dependency.NewDependency;
 import org.sonar.api.batch.sensor.duplication.NewDuplication;
 import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder;
 import org.sonar.api.batch.sensor.issue.Issue;
@@ -82,7 +82,6 @@ public interface SensorContext {
 
   /**
    * Builder to define highlighting of a file.
-   * @since 4.5
    */
   HighlightingBuilder highlightingBuilder(InputFile inputFile);
 
@@ -90,7 +89,6 @@ public interface SensorContext {
 
   /**
    * Builder to define symbol references in a file.
-   * @since 4.5
    */
   SymbolTableBuilder symbolTableBuilder(InputFile inputFile);
 
@@ -99,7 +97,6 @@ public interface SensorContext {
   /**
    * Builder to manually register duplication in a file. This can be used in addition to {@link CpdMapping} extension point.
    * Don't forget to call {@link NewDuplication#save()}.
-   * @since 5.1
    */
   NewDuplication newDuplication();
 
@@ -108,21 +105,18 @@ public interface SensorContext {
   /**
    * Create a new coverage report.
    * Don't forget to call {@link Coverage#save()} once all parameters are provided.
-   * @since 5.0
    */
   Coverage newCoverage();
 
   /**
    * Create a new test case execution report.
    * Don't forget to call {@link TestCaseExecution#save()} once all parameters are provided.
-   * @since 5.0
    */
   TestCaseExecution newTestCaseExecution();
 
   /**
    * Create a new test case coverage report.
    * Don't forget to call {@link TestCaseCoverage#save()} once all parameters are provided.
-   * @since 5.0
    */
   TestCaseCoverage newTestCaseCoverage();
 
@@ -130,9 +124,8 @@ public interface SensorContext {
 
   /**
    * Create a new dependency.
-   * Don't forget to call {@link Dependency#save()} once all parameters are provided.
-   * @since 5.0
+   * Don't forget to call {@link NewDependency#save()} once all parameters are provided.
    */
-  Dependency newDependency();
+  NewDependency newDependency();
 
 }
index 87bd3029fbd356f8a694885c259b6464cdbffd79..56185acaf3aefca4c642e45167ac395ff98230b3 100644 (file)
  */
 package org.sonar.api.batch.sensor.dependency;
 
-import com.google.common.annotations.Beta;
-import org.sonar.api.batch.fs.InputFile;
 
 /**
- * @since 5.0
+ * @since 5.1
  */
-@Beta
 public interface Dependency {
 
-  InputFile from();
+  String fromKey();
 
-  Dependency from(InputFile from);
-
-  InputFile to();
-
-  Dependency to(InputFile to);
+  String toKey();
 
   /**
    * Default weight value is 1.
    */
   int weight();
 
-  /**
-   * Set the weight of the dependency.
-   */
-  Dependency weight(int weight);
-
-  /**
-   * Save the dependency.
-   */
-  void save();
-
 }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/NewDependency.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/NewDependency.java
new file mode 100644 (file)
index 0000000..8d62a2f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.dependency;
+
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * Builder to create new Dependency.
+ * Should not be implemented by client.
+ * @since 5.1
+ */
+public interface NewDependency {
+
+  NewDependency from(InputFile from);
+
+  NewDependency to(InputFile to);
+
+  /**
+   * Set the weight of the dependency. If not set default weight is 1.
+   */
+  NewDependency weight(int weight);
+
+  /**
+   * Save the dependency. It is not permitted so save several time a dependency between two same files.
+   */
+  void save();
+
+}
index c7ab2fcc9979e796fd986aecd96f630a8e5acd4b..9dcb3d34ece175104479d201d70bc20eff56d712 100644 (file)
@@ -23,16 +23,18 @@ import com.google.common.base.Preconditions;
 import org.apache.commons.lang.builder.EqualsBuilder;
 import org.apache.commons.lang.builder.HashCodeBuilder;
 import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.dependency.Dependency;
+import org.sonar.api.batch.sensor.dependency.NewDependency;
 import org.sonar.api.batch.sensor.internal.DefaultStorable;
 
 import javax.annotation.Nullable;
 
-public class DefaultDependency extends DefaultStorable implements Dependency {
+public class DefaultDependency extends DefaultStorable implements Dependency, NewDependency {
 
-  private InputFile from;
-  private InputFile to;
+  private String fromKey;
+  private String toKey;
   private int weight = 1;
 
   public DefaultDependency() {
@@ -44,21 +46,21 @@ public class DefaultDependency extends DefaultStorable implements Dependency {
   }
 
   @Override
-  public Dependency from(InputFile from) {
+  public DefaultDependency from(InputFile from) {
     Preconditions.checkNotNull(from, "InputFile should be non null");
-    this.from = from;
+    this.fromKey = ((DefaultInputFile) from).key();
     return this;
   }
 
   @Override
-  public Dependency to(InputFile to) {
+  public DefaultDependency to(InputFile to) {
     Preconditions.checkNotNull(to, "InputFile should be non null");
-    this.to = to;
+    this.toKey = ((DefaultInputFile) to).key();
     return this;
   }
 
   @Override
-  public Dependency weight(int weight) {
+  public DefaultDependency weight(int weight) {
     Preconditions.checkArgument(weight > 1, "weight should be greater than 1");
     this.weight = weight;
     return this;
@@ -66,20 +68,30 @@ public class DefaultDependency extends DefaultStorable implements Dependency {
 
   @Override
   public void doSave() {
-    Preconditions.checkState(!this.from.equals(this.to), "From and To can't be the same inputFile");
-    Preconditions.checkNotNull(this.from, "From inputFile can't be null");
-    Preconditions.checkNotNull(this.to, "To inputFile can't be null");
+    Preconditions.checkState(!this.fromKey.equals(this.toKey), "From and To can't be the same inputFile");
+    Preconditions.checkNotNull(this.fromKey, "From inputFile can't be null");
+    Preconditions.checkNotNull(this.toKey, "To inputFile can't be null");
     storage.store((Dependency) this);
   }
 
   @Override
-  public InputFile from() {
-    return this.from;
+  public String fromKey() {
+    return this.fromKey;
+  }
+
+  public DefaultDependency setFromKey(String fromKey) {
+    this.fromKey = fromKey;
+    return this;
   }
 
   @Override
-  public InputFile to() {
-    return this.to;
+  public String toKey() {
+    return this.toKey;
+  }
+
+  public DefaultDependency setToKey(String toKey) {
+    this.toKey = toKey;
+    return this;
   }
 
   @Override
@@ -87,6 +99,11 @@ public class DefaultDependency extends DefaultStorable implements Dependency {
     return this.weight;
   }
 
+  public DefaultDependency setWeight(int weight) {
+    this.weight = weight;
+    return this;
+  }
+
   // For testing purpose
 
   @Override
@@ -102,8 +119,8 @@ public class DefaultDependency extends DefaultStorable implements Dependency {
     }
     DefaultDependency rhs = (DefaultDependency) obj;
     return new EqualsBuilder()
-      .append(from, rhs.from)
-      .append(to, rhs.to)
+      .append(fromKey, rhs.fromKey)
+      .append(toKey, rhs.toKey)
       .append(weight, rhs.weight)
       .isEquals();
   }
@@ -111,8 +128,8 @@ public class DefaultDependency extends DefaultStorable implements Dependency {
   @Override
   public int hashCode() {
     return new HashCodeBuilder(27, 45).
-      append(from).
-      append(to).
+      append(fromKey).
+      append(toKey).
       append(weight).
       toHashCode();
   }
index 5b7537f20dad8325d7f2a3684d8f98b533d4f10a..bc9655838819fe14bb952002fa921f300980c4a3 100644 (file)
@@ -50,11 +50,25 @@ public class Dependency implements Edge<Resource> {
     return from;
   }
 
+  /**
+   * For internal use only
+   */
+  public void setFrom(Resource from) {
+    this.from = from;
+  }
+
   @Override
   public Resource getTo() {
     return to;
   }
 
+  /**
+   * For internal use only
+   */
+  public void setTo(Resource to) {
+    this.to = to;
+  }
+
   public String getUsage() {
     return usage;
   }
@@ -105,26 +119,26 @@ public class Dependency implements Edge<Resource> {
     }
     Dependency other = (Dependency) obj;
     return new EqualsBuilder()
-        .append(from, other.from)
-        .append(to, other.to)
-        .isEquals();
+      .append(from, other.from)
+      .append(to, other.to)
+      .isEquals();
   }
 
   @Override
   public int hashCode() {
     return new HashCodeBuilder(17, 37)
-        .append(from)
-        .append(to)
-        .toHashCode();
+      .append(from)
+      .append(to)
+      .toHashCode();
   }
 
   @Override
   public String toString() {
     return new ToStringBuilder(this)
-        .append("from", from)
-        .append("to", to)
-        .append("weight", weight)
-        .append("usage", usage)
-        .toString();
+      .append("from", from)
+      .append("to", to)
+      .append("weight", weight)
+      .append("usage", usage)
+      .toString();
   }
 }