aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsimonbrandhof <simon.brandhof@gmail.com>2011-01-21 14:32:24 +0100
committersimonbrandhof <simon.brandhof@gmail.com>2011-01-21 14:32:24 +0100
commit08cb4444e0341652a4bf34133485ac405fb1ec50 (patch)
treebfefc7453a2ad73be491cdeaa10c3b1bd45bd060
parent1ab2475003835b71ff44b3652691c538059db699 (diff)
downloadsonarqube-08cb4444e0341652a4bf34133485ac405fb1ec50.tar.gz
sonarqube-08cb4444e0341652a4bf34133485ac405fb1ec50.zip
SONAR-2127 API: do not automatically create hierarchy of resource tree
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java6
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java4
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java5
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java3
-rw-r--r--sonar-batch/pom.xml6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java46
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java11
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java257
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java45
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java88
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java19
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java25
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java8
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java11
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/ResourceNotPersistedException.java34
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java21
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java28
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java113
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DefaultPersistenceManagerTest.java46
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java22
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java12
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java12
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/AbstractSourceImporter.java11
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java84
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java83
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Directory.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/DuplicatedSourceException.java14
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/File.java6
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Library.java6
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Qualifiers.java24
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/resources/Scopes.java21
-rw-r--r--sonar-server/pom.xml5
-rw-r--r--tests/integration/tests/pom.xml4
35 files changed, 789 insertions, 303 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java
index 1f7d5e5982f..da1415f6fde 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java
@@ -20,6 +20,7 @@
package org.sonar.plugins.core.timemachine;
import com.google.common.collect.*;
+import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.batch.DependedUpon;
@@ -28,6 +29,7 @@ import org.sonar.api.measures.*;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
+import org.sonar.api.resources.Scopes;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.Violation;
@@ -72,7 +74,9 @@ public class NewViolationsDecorator implements Decorator {
}
private boolean shouldDecorateResource(Resource resource, DecoratorContext context) {
- return !ResourceUtils.isUnitTestClass(resource) && context.getMeasure(CoreMetrics.NEW_VIOLATIONS) == null;
+ return
+ (StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope()) || StringUtils.equals(Scopes.FILE, resource.getScope()))
+ && !ResourceUtils.isUnitTestClass(resource) && context.getMeasure(CoreMetrics.NEW_VIOLATIONS) == null;
}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java
index 836d23613e8..310b19f04ef 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/TendencyDecorator.java
@@ -22,6 +22,7 @@ package org.sonar.plugins.core.timemachine;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.sonar.api.batch.*;
import org.sonar.api.measures.Measure;
@@ -30,6 +31,7 @@ import org.sonar.api.measures.MetricFinder;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
+import org.sonar.api.resources.Scopes;
import org.sonar.batch.components.TimeMachineConfiguration;
import java.util.List;
@@ -114,6 +116,6 @@ public class TendencyDecorator implements Decorator {
}
private boolean shouldDecorateResource(Resource resource) {
- return ResourceUtils.isSet(resource) || ResourceUtils.isSpace(resource);
+ return StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope());
}
}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java
index 4e6ddddf74e..68e686f61c8 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/VariationDecorator.java
@@ -20,13 +20,14 @@
package org.sonar.plugins.core.timemachine;
import com.google.common.collect.Maps;
+import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.*;
import org.sonar.api.database.model.MeasureModel;
import org.sonar.api.measures.*;
import org.sonar.api.qualitymodel.Characteristic;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
+import org.sonar.api.resources.Scopes;
import org.sonar.api.rules.RulePriority;
import org.sonar.batch.components.PastMeasuresLoader;
import org.sonar.batch.components.PastSnapshot;
@@ -73,7 +74,7 @@ public class VariationDecorator implements Decorator {
static boolean shouldCalculateVariations(Resource resource) {
// measures on files are currently purged, so past measures are not available on files
- return !ResourceUtils.isEntity(resource);
+ return StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope());
}
private void calculateVariation(Resource resource, DecoratorContext context, PastSnapshot pastSnapshot) {
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java
index 8170bb55dfe..22574d4a1b7 100644
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java
+++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java
@@ -31,6 +31,7 @@ import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.RuleMeasure;
+import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Rule;
@@ -79,7 +80,7 @@ public class NewViolationsDecoratorTest {
when(timeMachineConfiguration.getProjectPastSnapshots()).thenReturn(Arrays.asList(pastSnapshot, pastSnapshot2));
context = mock(DecoratorContext.class);
- resource = mock(Resource.class);
+ resource = new File("com/foo/bar");
when(context.getResource()).thenReturn(resource);
decorator = new NewViolationsDecorator(timeMachineConfiguration);
diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml
index b39f5e60004..fd1ae8dffb2 100644
--- a/sonar-batch/pom.xml
+++ b/sonar-batch/pom.xml
@@ -23,6 +23,10 @@
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-java-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-plugin-api</artifactId>
</dependency>
<dependency>
@@ -52,6 +56,8 @@
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
+
+ <!-- unit tests -->
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-testing-harness</artifactId>
diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java
index 24c70220e9d..a924fba8ac1 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultSensorContext.java
@@ -19,23 +19,21 @@
*/
package org.sonar.batch;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-
import org.sonar.api.batch.Event;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilter;
import org.sonar.api.measures.Metric;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.ProjectLink;
-import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.*;
import org.sonar.api.rules.Violation;
import org.sonar.batch.index.DefaultIndex;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
public class DefaultSensorContext implements SensorContext {
private DefaultIndex index;
@@ -50,6 +48,30 @@ public class DefaultSensorContext implements SensorContext {
return project;
}
+ public boolean index(Resource resource) {
+ return index.index(resource);
+ }
+
+ public boolean index(Resource resource, Resource parentReference) {
+ return index.index(resource, parentReference);
+ }
+
+ public boolean isExcluded(Resource reference) {
+ return index.isExcluded(reference);
+ }
+
+ public boolean isIndexed(Resource reference) {
+ return index.isIndexed(reference);
+ }
+
+ public Resource getParent(Resource reference) {
+ return index.getParent(reference);
+ }
+
+ public Collection<Resource> getChildren(Resource reference) {
+ return index.getChildren(reference);
+ }
+
public Measure getMeasure(Metric metric) {
return index.getMeasure(project, metric);
}
@@ -78,6 +100,10 @@ public class DefaultSensorContext implements SensorContext {
return null;
}
+ public boolean saveResource(Resource resource, Resource parentReference) {
+ return index.index(resource, parentReference);
+ }
+
public Resource getResource(Resource resource) {
return index.getResource(resource);
}
@@ -129,8 +155,8 @@ public class DefaultSensorContext implements SensorContext {
return index.getOutgoingEdges(resourceOrProject(from));
}
- public void saveSource(Resource resource, String source) {
- index.setSource(resource, source);
+ public boolean saveSource(Resource reference, String source) throws DuplicatedSourceException {
+ return index.setSource(reference, source);
}
public void saveLink(ProjectLink link) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java b/sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java
index ee3ad649957..eb374de1094 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/components/PastMeasuresLoader.java
@@ -30,6 +30,7 @@ import org.sonar.api.measures.MetricFinder;
import org.sonar.api.resources.Resource;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -61,8 +62,10 @@ public class PastMeasuresLoader implements BatchExtension {
}
public List<MeasureModel> getPastMeasures(Resource resource, Snapshot projectSnapshot) {
- // assume that the resource has already been saved
- return getPastMeasures(resource.getId(), projectSnapshot);
+ if (isPersisted(resource)) {
+ return getPastMeasures(resource.getId(), projectSnapshot);
+ }
+ return Collections.emptyList();
}
public List<MeasureModel> getPastMeasures(int resourceId, Snapshot projectSnapshot) {
@@ -78,4 +81,8 @@ public class PastMeasuresLoader implements BatchExtension {
.setParameter("status", Snapshot.STATUS_PROCESSED)
.getResultList();
}
+
+ private boolean isPersisted(Resource resource) {
+ return resource.getId()!=null;
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java b/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java
index 0969f089333..5a19f6ba97d 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java
@@ -50,18 +50,20 @@ public final class Bucket {
return resource;
}
- public void setParent(Bucket parent) {
+ public Bucket setParent(Bucket parent) {
this.parent = parent;
if (parent != null) {
parent.addChild(this);
}
+ return this;
}
- private void addChild(Bucket child) {
+ private Bucket addChild(Bucket child) {
if (children == null) {
children = Lists.newArrayList();
}
children.add(child);
+ return this;
}
private void removeChild(Bucket child) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
index 8f7a9f1e872..b63bef696fd 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java
@@ -22,6 +22,7 @@ package org.sonar.batch.index;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -75,9 +76,13 @@ public final class DefaultIndex extends SonarIndex {
public void start() {
Project rootProject = projectTree.getRootProject();
+ doStart(rootProject);
+ }
+
+ void doStart(Project rootProject) {
Bucket bucket = new Bucket(rootProject);
buckets.put(rootProject, bucket);
- persistence.saveProject(rootProject);
+ persistence.saveProject(rootProject, null);
currentProject = rootProject;
for (Project project : rootProject.getModules()) {
@@ -131,93 +136,6 @@ public final class DefaultIndex extends SonarIndex {
lock.unlock();
}
- /**
- * Does nothing if the resource is already registered.
- */
- public Resource addResource(Resource resource) {
- Bucket bucket = getOrAddBucket(resource);
- return bucket != null ? bucket.getResource() : null;
- }
-
- public Resource getResource(Resource resource) {
- Bucket bucket = buckets.get(resource);
- if (bucket != null) {
- return bucket.getResource();
- }
- return null;
- }
-
- private Bucket getOrAddBucket(Resource resource) {
- Bucket bucket = buckets.get(resource);
- if (bucket != null) {
- return bucket;
- }
-
- if (lock.isLocked() && !ResourceUtils.isLibrary(resource)) {
- LOG.warn("The following resource has not been registered before saving data: " + resource);
- }
-
- resource.setEffectiveKey(calculateResourceEffectiveKey(currentProject, resource));
- bucket = new Bucket(resource);
- Bucket parentBucket = null;
- Resource parent = resource.getParent();
- if (parent != null) {
- parentBucket = getOrAddBucket(parent);
- } else if (!ResourceUtils.isLibrary(resource)) {
- parentBucket = buckets.get(currentProject);
- }
- bucket.setParent(parentBucket);
- buckets.put(resource, bucket);
-
- boolean excluded = checkExclusion(resource, parentBucket);
- if (!excluded) {
- persistence.saveResource(currentProject, resource);
- }
- return bucket;
- }
-
- static String calculateResourceEffectiveKey(Project project, Resource resource) {
- String effectiveKey = resource.getKey();
- if (!StringUtils.equals(Resource.SCOPE_SET, resource.getScope())) {
- // not a project nor a library
- effectiveKey = new StringBuilder(ResourceModel.KEY_SIZE)
- .append(project.getKey())
- .append(':')
- .append(resource.getKey())
- .toString();
- }
- return effectiveKey;
- }
-
- private boolean checkExclusion(Resource resource, Bucket parent) {
- boolean excluded = (parent != null && parent.isExcluded()) || (resourceFilters != null && resourceFilters.isExcluded(resource));
- resource.setExcluded(excluded);
- return excluded;
- }
-
- public List<Resource> getChildren(Resource resource) {
- return getChildren(resource, false);
- }
-
- public List<Resource> getChildren(Resource resource, boolean includeExcludedResources) {
- List<Resource> children = Lists.newArrayList();
- Bucket bucket = buckets.get(resource);
- if (bucket != null) {
- for (Bucket childBucket : bucket.getChildren()) {
- if (includeExcludedResources || !childBucket.isExcluded())
- children.add(childBucket.getResource());
- }
- }
- return children;
- }
-
- public Resource getParent(Resource resource) {
- Bucket bucket = buckets.get(resource);
- if (bucket != null && bucket.getParent() != null) {
- return bucket.getParent().getResource();
- }
- return null;
- }
public Measure getMeasure(Resource resource, Metric metric) {
Bucket bucket = buckets.get(resource);
@@ -239,8 +157,8 @@ public final class DefaultIndex extends SonarIndex {
* the measure is updated if it's already registered.
*/
public Measure addMeasure(Resource resource, Measure measure) {
- Bucket bucket = getOrAddBucket(resource);
- if (!bucket.isExcluded()) {
+ Bucket bucket = doIndex(resource);
+ if (bucket != null && !bucket.isExcluded()) {
Metric metric = metricFinder.findByKey(measure.getMetricKey());
if (metric == null) {
throw new SonarException("Unknown metric: " + measure.getMetricKey());
@@ -250,7 +168,7 @@ public final class DefaultIndex extends SonarIndex {
bucket.addMeasure(measure);
}
if (measure.getPersistenceMode().useDatabase()) {
- persistence.saveMeasure(currentProject, resource, measure);
+ persistence.saveMeasure(resource, measure);
}
// TODO keep database measures in cache but remove data
@@ -258,13 +176,6 @@ public final class DefaultIndex extends SonarIndex {
return measure;
}
- public void setSource(Resource resource, String source) {
- Bucket bucket = getOrAddBucket(resource);
- if (!bucket.isExcluded()) {
- persistence.setSource(currentProject, resource, source);
- }
- }
-
//
//
//
@@ -291,8 +202,8 @@ public final class DefaultIndex extends SonarIndex {
}
boolean registerDependency(Dependency dependency) {
- Bucket fromBucket = getOrAddBucket(dependency.getFrom());
- Bucket toBucket = getOrAddBucket(dependency.getTo());
+ Bucket fromBucket = doIndex(dependency.getFrom());
+ Bucket toBucket = doIndex(dependency.getTo());
if (fromBucket != null && !fromBucket.isExcluded() && toBucket != null && !toBucket.isExcluded()) {
dependencies.add(dependency);
@@ -389,7 +300,7 @@ public final class DefaultIndex extends SonarIndex {
if (resource == null) {
violation.setResource(currentProject);
}
- bucket = getOrAddBucket(violation.getResource());
+ bucket = doIndex(violation.getResource());
if (!bucket.isExcluded()) {
boolean isIgnored = !force && violationFilters != null && violationFilters.isIgnored(violation);
if (!isIgnored) {
@@ -451,7 +362,149 @@ public final class DefaultIndex extends SonarIndex {
public Event addEvent(Resource resource, String name, String description, String category, Date date) {
Event event = new Event(name, description, category);
event.setDate(date);
- persistence.saveEvent(currentProject, resource, event);
+ persistence.saveEvent(resource, event);
return null;
}
+
+ public boolean setSource(Resource reference, String source) {
+ boolean result = false;
+ if (isIndexed(reference)) {
+ persistence.setSource(reference, source);
+ result = true;
+ }
+ return result;
+ }
+
+
+ /**
+ * Does nothing if the resource is already registered.
+ */
+ public Resource addResource(Resource resource) {
+ Bucket bucket = doIndex(resource);
+ return bucket != null ? bucket.getResource() : null;
+ }
+
+ public <R extends Resource> R getResource(R reference) {
+ Bucket bucket = buckets.get(reference);
+ if (bucket != null) {
+ return (R)bucket.getResource();
+ }
+ return null;
+ }
+
+ static String createUID(Project project, Resource resource) {
+ String uid = resource.getKey();
+ if (!StringUtils.equals(Resource.SCOPE_SET, resource.getScope())) {
+ // not a project nor a library
+ uid = new StringBuilder(ResourceModel.KEY_SIZE)
+ .append(project.getKey())
+ .append(':')
+ .append(resource.getKey())
+ .toString();
+ }
+ return uid;
+ }
+
+ private boolean checkExclusion(Resource resource, Bucket parent) {
+ boolean excluded = (parent != null && parent.isExcluded()) || (resourceFilters != null && resourceFilters.isExcluded(resource));
+ resource.setExcluded(excluded);
+ return excluded;
+ }
+
+ public List<Resource> getChildren(Resource resource) {
+ return getChildren(resource, false);
+ }
+
+
+ public List<Resource> getChildren(Resource resource, boolean acceptExcluded) {
+ List<Resource> children = Lists.newLinkedList();
+ Bucket bucket = getBucket(resource, acceptExcluded);
+ if (bucket != null) {
+ for (Bucket childBucket : bucket.getChildren()) {
+ if (acceptExcluded || !childBucket.isExcluded())
+ children.add(childBucket.getResource());
+ }
+ }
+ return children;
+ }
+
+ public Resource getParent(Resource resource) {
+ Bucket bucket = getBucket(resource, false);
+ if (bucket != null && bucket.getParent() != null) {
+ return bucket.getParent().getResource();
+ }
+ return null;
+ }
+
+ public boolean index(Resource resource) {
+ Bucket bucket = doIndex(resource);
+ return bucket != null && !bucket.isExcluded();
+ }
+
+ private Bucket doIndex(Resource resource) {
+ if (resource.getParent() != null) {
+ // SONAR-2127 backward-compatibility - create automatically parent of files
+ doIndex(resource.getParent(), currentProject);
+ }
+ return doIndex(resource, resource.getParent());
+ }
+
+ public boolean index(Resource resource, Resource parentReference) {
+ Bucket bucket = doIndex(resource, parentReference);
+ return bucket != null && !bucket.isExcluded();
+ }
+
+ private Bucket doIndex(Resource resource, Resource parentReference) {
+ Bucket bucket = buckets.get(resource);
+ if (bucket != null) {
+ return bucket;
+ }
+
+ if (lock.isLocked() && !ResourceUtils.isLibrary(resource)) {
+ LOG.warn("Resource will be ignored in next Sonar versions, index is locked: " + resource);
+ }
+
+ Resource parent = null;
+ if (!ResourceUtils.isLibrary(resource)) {
+ // a library has no parent
+ parent = (Resource) ObjectUtils.defaultIfNull(parentReference, currentProject);
+ }
+
+ Bucket parentBucket = getBucket(parent, true);
+ if (parentBucket==null && parent!=null) {
+ LOG.warn("Resource ignored, parent is not indexed: " + resource);
+ return null;
+ }
+
+ resource.setEffectiveKey(createUID(currentProject, resource));
+ bucket = new Bucket(resource).setParent(parentBucket);
+ buckets.put(resource, bucket);
+
+ boolean excluded = checkExclusion(resource, parentBucket);
+ if (!excluded) {
+ persistence.saveResource(currentProject, resource, (parentBucket!=null ? parentBucket.getResource() : null));
+ }
+ return bucket;
+ }
+
+
+ public boolean isExcluded(Resource reference) {
+ Bucket bucket = getBucket(reference, true);
+ return bucket != null && bucket.isExcluded();
+ }
+
+ public boolean isIndexed(Resource reference) {
+ return getBucket(reference, false) != null;
+ }
+
+ private Bucket getBucket(Resource resource, boolean acceptExcluded) {
+ Bucket bucket = null;
+ if (resource != null) {
+ bucket = buckets.get(resource);
+ if (!acceptExcluded && bucket != null && bucket.isExcluded()) {
+ bucket = null;
+ }
+ }
+ return bucket;
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
index 942dd3aa127..ea019c5ee4c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultPersistenceManager.java
@@ -19,13 +19,12 @@
*/
package org.sonar.batch.index;
+import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.Event;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.ProjectLink;
-import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.*;
import java.util.List;
@@ -62,24 +61,31 @@ public final class DefaultPersistenceManager implements PersistenceManager {
measurePersister.dump();
}
- public void saveProject(Project project) {
- resourcePersister.saveProject(project);
+ public void saveProject(Project project, Project parent) {
+ resourcePersister.saveProject(project, parent);
}
- public Snapshot saveResource(Project project, Resource resource) {
- return resourcePersister.saveResource(project, resource);
+ public Snapshot saveResource(Project project, Resource resource, Resource parent) {
+ if (isPersistable(resource)) {
+ return resourcePersister.saveResource(project, resource, parent);
+ }
+ return null;
}
- public void setSource(Project project, Resource resource, String source) {
- sourcePersister.saveSource(project, resource, source);
+ public void setSource(Resource file, String source) {
+ sourcePersister.saveSource(file, source);
}
- public void saveMeasure(Project project, Resource resource, Measure measure) {
- measurePersister.saveMeasure(project, resource, measure);
+ public void saveMeasure(Resource resource, Measure measure) {
+ if (isPersistable(resource)) {
+ measurePersister.saveMeasure(resource, measure);
+ }
}
public void saveDependency(Project project, Dependency dependency, Dependency parentDependency) {
- dependencyPersister.saveDependency(project, dependency, parentDependency);
+ if (isPersistable(dependency.getFrom()) && isPersistable(dependency.getTo())) {
+ dependencyPersister.saveDependency(project, dependency, parentDependency);
+ }
}
public void saveLink(Project project, ProjectLink link) {
@@ -98,7 +104,18 @@ public final class DefaultPersistenceManager implements PersistenceManager {
eventPersister.deleteEvent(event);
}
- public void saveEvent(Project project, Resource resource, Event event) {
- eventPersister.saveEvent(project, resource, event);
+ public void saveEvent(Resource resource, Event event) {
+ if (isPersistable(resource)) {
+ eventPersister.saveEvent(resource, event);
+ }
+ }
+
+ static boolean isPersistable(Resource resource) {
+ if (resource != null) {
+ return resource instanceof File || resource instanceof Directory || resource instanceof Library || resource instanceof Project ||
+ // for deprecated resources
+ StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope()) || StringUtils.equals(Scopes.FILE, resource.getScope());
+ }
+ return false;
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
index 3634307178f..640503ecdd8 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
@@ -33,7 +33,6 @@ import org.sonar.api.utils.SonarException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
-
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -48,29 +47,22 @@ public final class DefaultResourcePersister implements ResourcePersister {
this.session = session;
}
- public Snapshot saveProject(Project project) {
+ public Snapshot saveProject(Project project, Project parent) {
Snapshot snapshot = snapshotsByResource.get(project);
if (snapshot == null) {
- snapshot = doSaveProject(project);
+ snapshot = persistProject(project, parent);
+ addToCache(project, snapshot);
}
return snapshot;
}
- public Snapshot getSnapshot(Resource resource) {
- if (resource != null) {
- return snapshotsByResource.get(resource);
+ private void addToCache(Resource resource, Snapshot snapshot) {
+ if (snapshot != null) {
+ snapshotsByResource.put(resource, snapshot);
}
- return null;
}
- /**
- * just for unit tests
- */
- Map<Resource, Snapshot> getSnapshotsByResource() {
- return snapshotsByResource;
- }
-
- private Snapshot doSaveProject(Project project) {
+ private Snapshot persistProject(Project project, Project parent) {
// temporary hack
project.setEffectiveKey(project.getKey());
@@ -78,7 +70,7 @@ public final class DefaultResourcePersister implements ResourcePersister {
model.setLanguageKey(project.getLanguageKey());// ugly, only for projects
Snapshot parentSnapshot = null;
- if (project.getParent() != null) {
+ if (parent != null) {
// assume that the parent project has already been saved
parentSnapshot = snapshotsByResource.get(project.getParent());
model.setRootId((Integer) ObjectUtils.defaultIfNull(parentSnapshot.getRootProjectId(), parentSnapshot.getResourceId()));
@@ -91,30 +83,60 @@ public final class DefaultResourcePersister implements ResourcePersister {
snapshot.setCreatedAt(project.getAnalysisDate());
snapshot = session.save(snapshot);
session.commit();
- snapshotsByResource.put(project, snapshot);
return snapshot;
}
- public Snapshot saveResource(Project project, Resource resource) {
- if (resource == null) {
- return null;
+ public Snapshot getSnapshot(Resource reference) {
+ return snapshotsByResource.get(reference);
+ }
+
+ public Snapshot getSnapshotOrFail(Resource resource) throws ResourceNotPersistedException {
+ Snapshot snapshot = getSnapshot(resource);
+ if (snapshot == null) {
+ throw new ResourceNotPersistedException(resource);
}
+ return snapshot;
+ }
+
+ /**
+ * just for unit tests
+ */
+ Map<Resource, Snapshot> getSnapshotsByResource() {
+ return snapshotsByResource;
+ }
+
+
+ public Snapshot saveResource(Project project, Resource resource) {
+ return saveResource(project, resource, null);
+ }
+
+ public Snapshot saveResource(Project project, Resource resource, Resource parent) {
Snapshot snapshot = snapshotsByResource.get(resource);
if (snapshot == null) {
- if (resource instanceof Project) {
- snapshot = doSaveProject((Project) resource);
+ snapshot = persist(project, resource, parent);
+ addToCache(resource, snapshot);
+ }
+ return snapshot;
+ }
- } else if (resource instanceof Library) {
- snapshot = doSaveLibrary(project, (Library) resource);
- } else {
- snapshot = doSaveResource(project, resource);
- }
+ private Snapshot persist(Project project, Resource resource, Resource parent) {
+ Snapshot snapshot;
+ if (resource instanceof Project) {
+ // should not occur, please use the method saveProject()
+ snapshot = persistProject((Project) resource, project);
+
+ } else if (resource instanceof Library) {
+ snapshot = persistLibrary(project, (Library) resource);
+
+ } else {
+ snapshot = persistFileOrDirectory(project, resource, parent);
}
return snapshot;
}
- private Snapshot doSaveLibrary(Project project, Library library) {
+
+ private Snapshot persistLibrary(Project project, Library library) {
ResourceModel model = findOrCreateModel(library);
model = session.save(model);
library.setId(model.getId()); // TODO to be removed
@@ -131,7 +153,6 @@ public final class DefaultResourcePersister implements ResourcePersister {
// The qualifier must be LIB, even if the resource is TRK, because this snapshot has no measures.
snapshot.setQualifier(Resource.QUALIFIER_LIB);
snapshot = session.save(snapshot);
- snapshotsByResource.put(library, snapshot);
}
session.commit();
return snapshot;
@@ -154,18 +175,17 @@ public final class DefaultResourcePersister implements ResourcePersister {
/**
* Everything except project and library
*/
- private Snapshot doSaveResource(Project project, Resource resource) {
+ private Snapshot persistFileOrDirectory(Project project, Resource resource, Resource parentReference) {
ResourceModel model = findOrCreateModel(resource);
Snapshot projectSnapshot = snapshotsByResource.get(project);
model.setRootId(projectSnapshot.getResourceId());
model = session.save(model);
resource.setId(model.getId()); // TODO to be removed
- Snapshot parentSnapshot = (Snapshot) ObjectUtils.defaultIfNull(getSnapshot(resource.getParent()), projectSnapshot);
+ Snapshot parentSnapshot = (Snapshot) ObjectUtils.defaultIfNull(getSnapshot(parentReference), projectSnapshot);
Snapshot snapshot = new Snapshot(model, parentSnapshot);
snapshot = session.save(snapshot);
session.commit();
- snapshotsByResource.put(resource, snapshot);
return snapshot;
}
@@ -186,7 +206,7 @@ public final class DefaultResourcePersister implements ResourcePersister {
// we keep cache of projects
for (Iterator<Map.Entry<Resource, Snapshot>> it = snapshotsByResource.entrySet().iterator(); it.hasNext();) {
Map.Entry<Resource, Snapshot> entry = it.next();
- if ( !ResourceUtils.isSet(entry.getKey())) {
+ if (!ResourceUtils.isSet(entry.getKey())) {
it.remove();
}
}
@@ -239,7 +259,7 @@ public final class DefaultResourcePersister implements ResourcePersister {
if (StringUtils.isNotBlank(resource.getDescription())) {
model.setDescription(resource.getDescription());
}
- if ( !ResourceUtils.isLibrary(resource)) {
+ if (!ResourceUtils.isLibrary(resource)) {
model.setScope(resource.getScope());
model.setQualifier(resource.getQualifier());
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java
index 9b536333674..5cc2b1aa3e5 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java
@@ -50,16 +50,15 @@ public final class EventPersister {
session.commit();
}
- public void saveEvent(Project project, Resource resource, Event event) {
- Snapshot snapshot = resourcePersister.saveResource(project, resource);
- if (snapshot != null) {
- if (event.getDate()==null) {
- event.setSnapshot(snapshot);
- } else {
- event.setResourceId(snapshot.getResourceId());
- }
- session.save(event);
- session.commit();
+ public void saveEvent(Resource resource, Event event) {
+ Snapshot snapshot = resourcePersister.getSnapshotOrFail(resource);
+ if (event.getDate() == null) {
+ event.setSnapshot(snapshot);
+ } else {
+ event.setResourceId(snapshot.getResourceId());
}
+ session.save(event);
+ session.commit();
+
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java
index 123b363658b..66ec62ce999 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/LinkPersister.java
@@ -35,21 +35,20 @@ public final class LinkPersister {
}
public void saveLink(Project project, ProjectLink link) {
- Snapshot snapshot = resourcePersister.getSnapshot(project);
- if (snapshot != null) {
- ResourceModel projectDao = session.reattach(ResourceModel.class, snapshot.getResourceId());
- ProjectLink dbLink = projectDao.getProjectLink(link.getKey());
- if (dbLink == null) {
- link.setResource(projectDao);
- projectDao.getProjectLinks().add(link);
- session.save(link);
+ Snapshot snapshot = resourcePersister.getSnapshotOrFail(project);
+ ResourceModel projectDao = session.reattach(ResourceModel.class, snapshot.getResourceId());
+ ProjectLink dbLink = projectDao.getProjectLink(link.getKey());
+ if (dbLink == null) {
+ link.setResource(projectDao);
+ projectDao.getProjectLinks().add(link);
+ session.save(link);
- } else {
- dbLink.copyFieldsFrom(link);
- session.save(dbLink);
- }
- session.commit();
+ } else {
+ dbLink.copyFieldsFrom(link);
+ session.save(dbLink);
}
+ session.commit();
+
}
public void deleteLink(Project project, String linkKey) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
index 39737571315..ec8ca8c925e 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java
@@ -57,17 +57,13 @@ public final class MeasurePersister {
this.delayedMode = delayedMode;
}
- public void saveMeasure(Project project, Measure measure) {
- saveMeasure(project, project, measure);
- }
-
- public void saveMeasure(Project project, Resource resource, Measure measure) {
+ public void saveMeasure(Resource resource, Measure measure) {
boolean saveLater = (measure.getPersistenceMode().useMemory() && delayedMode);
if (saveLater) {
unsavedMeasuresByResource.put(resource, measure);
} else {
- Snapshot snapshot = resourcePersister.saveResource(project, resource);
+ Snapshot snapshot = resourcePersister.getSnapshotOrFail(resource);
if (measure.getId() != null) {
// update
MeasureModel model = session.reattach(MeasureModel.class, measure.getId());
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java
index f9aebeb5e75..caffd0dac07 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/PersistenceManager.java
@@ -23,6 +23,7 @@ import org.sonar.api.batch.Event;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
+import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.ProjectLink;
import org.sonar.api.resources.Resource;
@@ -36,13 +37,13 @@ public interface PersistenceManager {
void dump();
- void saveProject(Project project);
+ void saveProject(Project project, Project parent);
- Snapshot saveResource(Project project, Resource resource);
+ Snapshot saveResource(Project project, Resource resource, Resource parent);
- void setSource(Project project, Resource resource, String source);
+ void setSource(Resource file, String source);
- void saveMeasure(Project project, Resource resource, Measure measure);
+ void saveMeasure(Resource resource, Measure measure);
void saveDependency(Project project, Dependency dependency, Dependency parentDependency);
@@ -54,5 +55,5 @@ public interface PersistenceManager {
void deleteEvent(Event event);
- void saveEvent(Project project, Resource resource, Event event);
+ void saveEvent(Resource resource, Event event);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceNotPersistedException.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceNotPersistedException.java
new file mode 100644
index 00000000000..c2f30edd2eb
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceNotPersistedException.java
@@ -0,0 +1,34 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.index;
+
+import org.sonar.api.resources.Resource;
+import org.sonar.api.utils.SonarException;
+
+/**
+ * @since 2.6
+ */
+public final class ResourceNotPersistedException extends SonarException {
+
+ public ResourceNotPersistedException(Resource resource) {
+ super(resource.toString());
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
index 644c3261b21..dad3c8f5428 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourcePersister.java
@@ -24,14 +24,29 @@ import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
public interface ResourcePersister {
- Snapshot saveProject(Project project);
+
+ Snapshot saveProject(Project project, Project parent);
- Snapshot getSnapshot(Resource resource);
+ /**
+ * Persist a resource in database. Returns null if the resource must not be persisted (scope lower than file)
+ */
+ Snapshot saveResource(Project project, Resource resource, Resource parent);
+ /**
+ * Persist a resource in database. Returns null if the resource must not be persisted (scope lower than file)
+ */
Snapshot saveResource(Project project, Resource resource);
+ Snapshot getSnapshot(Resource resource);
+
+ /**
+ * @throws ResourceNotPersistedException if the resource is not persisted.
+ */
+ Snapshot getSnapshotOrFail(Resource resource);
+
+
/**
- * The current snapshot which is flagged as "last"
+ * The current snapshot which is flagged as "last", different then the current analysis.
* @param onlyOlder true if the result must be anterior to the snapshot parameter
*/
Snapshot getLastSnapshot(Snapshot snapshot, boolean onlyOlder);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java
index 4480ab4bef5..1b1857c7fc9 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java
@@ -23,9 +23,8 @@ import com.google.common.collect.Sets;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.database.model.SnapshotSource;
-import org.sonar.api.resources.Project;
+import org.sonar.api.resources.DuplicatedSourceException;
import org.sonar.api.resources.Resource;
-import org.sonar.api.utils.SonarException;
import java.util.Set;
@@ -40,17 +39,22 @@ public final class SourcePersister {
this.resourcePersister = resourcePersister;
}
- public void saveSource(Project project, Resource resource, String source) {
- Snapshot snapshot = resourcePersister.saveResource(project, resource);
- if (snapshot != null) {
-
- if (savedSnapshotIds.contains(snapshot.getId())) {
- throw new SonarException("Can not set twice the source of " + resource);
- }
- session.save(new SnapshotSource(snapshot.getId(), source));
- session.commit();
- savedSnapshotIds.add(snapshot.getId());
+ public void saveSource(Resource resource, String source) {
+ Snapshot snapshot = resourcePersister.getSnapshotOrFail(resource);
+ if (isCached(snapshot)) {
+ throw new DuplicatedSourceException(resource);
}
+ session.save(new SnapshotSource(snapshot.getId(), source));
+ session.commit();
+ addToCache(snapshot);
+ }
+
+ private boolean isCached(Snapshot snapshot) {
+ return savedSnapshotIds.contains(snapshot.getId());
+ }
+
+ private void addToCache(Snapshot snapshot) {
+ savedSnapshotIds.add(snapshot.getId());
}
public void clear() {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
index 67a0e4e36d6..25f6bcb6cc1 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java
@@ -19,25 +19,124 @@
*/
package org.sonar.batch.index;
+import org.apache.commons.lang.StringUtils;
+import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
-import org.sonar.api.resources.JavaPackage;
-import org.sonar.api.resources.Library;
-import org.sonar.api.resources.Project;
+import org.sonar.api.batch.ResourceFilter;
+import org.sonar.api.measures.MetricFinder;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.*;
+import org.sonar.batch.DefaultResourceCreationLock;
+import org.sonar.batch.ProjectTree;
+import org.sonar.batch.ResourceFilters;
+import org.sonar.batch.ViolationFilters;
+import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
public class DefaultIndexTest {
+ private DefaultIndex index = null;
+
+ @Before
+ public void createIndex() {
+ index = new DefaultIndex(mock(PersistenceManager.class), new DefaultResourceCreationLock(), mock(ProjectTree.class), mock(MetricFinder.class));
+ Project project = new Project("project");
+
+ ResourceFilter filter = new ResourceFilter() {
+ public boolean isIgnored(Resource resource) {
+ return StringUtils.containsIgnoreCase(resource.getKey(), "excluded");
+ }
+ };
+ index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[]{filter}), new ViolationFilters(), RulesProfile.create());
+ index.doStart(project);
+ }
+
+
@Test
- public void shouldCalculateResourceEffectiveKey() {
+ public void shouldCreateUID() {
Project project = new Project("my_project");
- assertThat(DefaultIndex.calculateResourceEffectiveKey(project, project), is("my_project"));
+ assertThat(DefaultIndex.createUID(project, project), is("my_project"));
JavaPackage javaPackage = new JavaPackage("org.foo");
- assertThat(DefaultIndex.calculateResourceEffectiveKey(project, javaPackage), is("my_project:org.foo"));
+ assertThat(DefaultIndex.createUID(project, javaPackage), is("my_project:org.foo"));
Library library = new Library("junit:junit", "4.7");
- assertThat(DefaultIndex.calculateResourceEffectiveKey(project, library), is("junit:junit"));
+ assertThat(DefaultIndex.createUID(project, library), is("junit:junit"));
+ }
+
+ @Test
+ public void shouldIndexParentOfDeprecatedFiles() {
+ File file = new File("org/foo/Bar.java");
+ assertThat(index.index(file), is(true));
+
+ Directory reference = new Directory("org/foo");
+ assertThat(index.getResource(reference).getName(), is("org/foo"));
+ assertThat(index.isIndexed(reference), is(true));
+ assertThat(index.isExcluded(reference), is(false));
+ assertThat(index.getChildren(reference).size(), is(1));
+ assertThat(index.getParent(reference), is(Project.class));
+ }
+
+ @Test
+ public void shouldIndexTreeOfResources() {
+ Directory directory = new Directory("org/foo");
+ File file = new File("org/foo/Bar.java");
+ file.setLanguage(Java.INSTANCE);
+
+ assertThat(index.index(directory), is(true));
+ assertThat(index.index(file, directory), is(true));
+
+ File fileRef = new File("org/foo/Bar.java");
+ assertThat(index.getResource(fileRef).getKey(), is("org/foo/Bar.java"));
+ assertThat(index.getResource(fileRef).getLanguage(), is((Language) Java.INSTANCE));
+ assertThat(index.isIndexed(fileRef), is(true));
+ assertThat(index.isExcluded(fileRef), is(false));
+ assertThat(index.getChildren(fileRef).size(), is(0));
+ assertThat(index.getParent(fileRef), is(Directory.class));
+ }
+
+ @Test
+ public void shouldIndexLibraryOutsideProjectTree() {
+ Library lib = new Library("junit", "4.8");
+ assertThat(index.index(lib), is(true));
+
+ Library reference = new Library("junit", "4.8");
+ assertThat(index.getResource(reference).getQualifier(), is(Qualifiers.LIBRARY));
+ assertThat(index.isIndexed(reference), is(true));
+ assertThat(index.isExcluded(reference), is(false));
+ }
+
+ @Test
+ public void shouldNotIndexResourceIfParentNotIndexed() {
+ Directory directory = new Directory("org/other");
+ File file = new File("org/foo/Bar.java");
+
+ assertThat(index.index(file, directory), is(false));
+
+ File fileRef = new File("org/foo/Bar.java");
+ assertThat(index.isIndexed(directory), is(false));
+ assertThat(index.isIndexed(fileRef), is(false));
+ assertThat(index.isExcluded(fileRef), is(false));
+ assertThat(index.getChildren(fileRef).size(), is(0));
+ assertThat(index.getParent(fileRef), nullValue());
+ }
+
+
+ @Test
+ @Ignore("TODO: should it be really possible")
+ public void shouldIndexDirectChildOfProject() {
+
+ }
+
+ @Test
+ public void shouldBeExcluded() {
+ File file = new File("org/foo/ExcludedBar.java");
+ assertThat(index.index(file), is(false));
+ assertThat(index.isIndexed(file), is(false));
+ assertThat(index.isExcluded(file), is(true));
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultPersistenceManagerTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultPersistenceManagerTest.java
new file mode 100644
index 00000000000..48458f63a1c
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultPersistenceManagerTest.java
@@ -0,0 +1,46 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2009 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.index;
+
+import org.junit.Test;
+import org.sonar.api.resources.Directory;
+import org.sonar.api.resources.File;
+import org.sonar.api.resources.Library;
+import org.sonar.api.resources.Project;
+import org.sonar.java.api.JavaClass;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class DefaultPersistenceManagerTest {
+
+ @Test
+ public void shouldPersistResoucesWithScopeHigherThanFile() {
+ assertThat(DefaultPersistenceManager.isPersistable(new File("Foo.java")), is(true));
+ assertThat(DefaultPersistenceManager.isPersistable(new Directory("bar/Foo.java")), is(true));
+ assertThat(DefaultPersistenceManager.isPersistable(new Project("foo")), is(true));
+ assertThat(DefaultPersistenceManager.isPersistable(new Library("foo", "1.2")), is(true));
+ }
+
+ @Test
+ public void shouldNotPersistResoucesWithScopeLowerThanFile() {
+ assertThat(DefaultPersistenceManager.isPersistable(JavaClass.createRef("com.foo.Bar")), is(false));
+ }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java
index bfd8a913dc6..ec61785d170 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultResourcePersisterTest.java
@@ -66,7 +66,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
setupData("shared");
ResourcePersister persister = new DefaultResourcePersister(getSession());
- persister.saveProject(singleProject);
+ persister.saveProject(singleProject, null);
checkTables("shouldSaveNewProject", "projects", "snapshots");
}
@@ -76,10 +76,10 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
setupData("shared");
ResourcePersister persister = new DefaultResourcePersister(getSession());
- persister.saveProject(multiModuleProject);
- persister.saveProject(moduleA);
- persister.saveProject(moduleB);
- persister.saveProject(moduleB1);
+ persister.saveProject(multiModuleProject, null);
+ persister.saveProject(moduleA, multiModuleProject);
+ persister.saveProject(moduleB, multiModuleProject);
+ persister.saveProject(moduleB1, moduleB);
checkTables("shouldSaveNewMultiModulesProject", "projects", "snapshots");
}
@@ -89,7 +89,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
setupData("shared");
ResourcePersister persister = new DefaultResourcePersister(getSession());
- persister.saveProject(singleProject);
+ persister.saveProject(singleProject, null);
persister.saveResource(singleProject, new JavaPackage("org.foo").setEffectiveKey("foo:org.foo"));
// check that the directory is attached to the project
@@ -101,7 +101,7 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
setupData("shared");
ResourcePersister persister = new DefaultResourcePersister(getSession());
- persister.saveProject(singleProject);
+ persister.saveProject(singleProject, null);
persister.saveResource(singleProject, new Library("junit:junit", "4.8.2").setEffectiveKey("junit:junit"));
persister.saveResource(singleProject, new Library("junit:junit", "4.8.2").setEffectiveKey("junit:junit"));// do nothing, already saved
persister.saveResource(singleProject, new Library("junit:junit", "3.2").setEffectiveKey("junit:junit"));
@@ -114,8 +114,8 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
setupData("shared");
DefaultResourcePersister persister = new DefaultResourcePersister(getSession());
- persister.saveProject(multiModuleProject);
- persister.saveProject(moduleA);
+ persister.saveProject(multiModuleProject, null);
+ persister.saveProject(moduleA, multiModuleProject);
persister.saveResource(moduleA, new JavaPackage("org.foo").setEffectiveKey("a:org.foo"));
persister.saveResource(moduleA, new JavaFile("org.foo.MyClass").setEffectiveKey("a:org.foo.MyClass"));
persister.clear();
@@ -132,9 +132,9 @@ public class DefaultResourcePersisterTest extends AbstractDbUnitTestCase {
ResourcePersister persister = new DefaultResourcePersister(getSession());
singleProject.setName("new name");
singleProject.setDescription("new description");
- persister.saveProject(singleProject);
+ persister.saveProject(singleProject, null);
checkTables("shouldUpdateExistingResource", "projects", "snapshots");
}
-
+
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
index 90d597908c5..13a299b38b3 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java
@@ -67,9 +67,9 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
fileSnapshot = getSession().getSingleResult(Snapshot.class, "id", FILE_SNAPSHOT_ID);
ncloc = getSession().getSingleResult(Metric.class, "key", "ncloc");
coverage = getSession().getSingleResult(Metric.class, "key", "coverage");
- when(resourcePersister.saveResource((Project) anyObject(), eq(project))).thenReturn(projectSnapshot);
- when(resourcePersister.saveResource((Project) anyObject(), eq(aPackage))).thenReturn(packageSnapshot);
- when(resourcePersister.saveResource((Project) anyObject(), eq(aFile))).thenReturn(fileSnapshot);
+ when(resourcePersister.getSnapshotOrFail(eq(project))).thenReturn(projectSnapshot);
+ when(resourcePersister.getSnapshotOrFail(eq(aPackage))).thenReturn(packageSnapshot);
+ when(resourcePersister.getSnapshotOrFail(eq(aFile))).thenReturn(fileSnapshot);
when(resourcePersister.getSnapshot(project)).thenReturn(projectSnapshot);
when(resourcePersister.getSnapshot(aPackage)).thenReturn(packageSnapshot);
when(resourcePersister.getSnapshot(aFile)).thenReturn(fileSnapshot);
@@ -122,7 +122,7 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
measurePersister.setDelayedMode(true);
measurePersister.saveMeasure(project, new Measure(ncloc).setValue(1234.0));
- measurePersister.saveMeasure(project, aPackage, new Measure(ncloc).setValue(50.0));
+ measurePersister.saveMeasure(aPackage, new Measure(ncloc).setValue(50.0));
assertThat(getSession().getResults(MeasureModel.class, "metricId", 1).size(), is(0));
@@ -135,7 +135,7 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
measurePersister.setDelayedMode(true);
measurePersister.saveMeasure(project, new Measure(ncloc).setValue(1234.0).setPersistenceMode(PersistenceMode.DATABASE)); // database only
- measurePersister.saveMeasure(project, aPackage, new Measure(ncloc).setValue(50.0)); // database + memory
+ measurePersister.saveMeasure(aPackage, new Measure(ncloc).setValue(50.0)); // database + memory
// no dump => the db-only measure is saved
@@ -160,7 +160,7 @@ public class MeasurePersisterTest extends AbstractDbUnitTestCase {
public void shouldNotSaveBestValueMeasuresInDelayedMode() {
measurePersister.setDelayedMode(true);
- measurePersister.saveMeasure(project, aFile, new Measure(coverage).setValue(100.0));
+ measurePersister.saveMeasure(aFile, new Measure(coverage).setValue(100.0));
assertThat(getSession().getResults(MeasureModel.class, "metricId", COVERAGE_METRIC_ID, "snapshotId", FILE_SNAPSHOT_ID).size(), is(0));
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java
index d92fdb8adf7..cc92ff24a4c 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/SourcePersisterTest.java
@@ -22,6 +22,7 @@ package org.sonar.batch.index;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.DuplicatedSourceException;
import org.sonar.api.resources.JavaFile;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
@@ -41,21 +42,20 @@ public class SourcePersisterTest extends AbstractDbUnitTestCase {
setupData("shared");
Snapshot snapshot = getSession().getSingleResult(Snapshot.class, "id", 1000);
ResourcePersister resourcePersister = mock(ResourcePersister.class);
- when(resourcePersister.saveResource((Project) anyObject(), (Resource) anyObject())).thenReturn(snapshot);
+ when(resourcePersister.getSnapshotOrFail((Resource) anyObject())).thenReturn(snapshot);
sourcePersister = new SourcePersister(getSession(), resourcePersister);
}
@Test
public void shouldSaveSource() {
- sourcePersister.saveSource(new Project(""), new JavaFile("org.foo.Bar"), "this is the file content");
+ sourcePersister.saveSource(new JavaFile("org.foo.Bar"), "this is the file content");
checkTables("shouldSaveSource", "snapshot_sources");
}
- @Test(expected = SonarException.class)
+ @Test(expected = DuplicatedSourceException.class)
public void shouldFailIfSourceSavedSeveralTimes() {
- Project project = new Project("project");
JavaFile file = new JavaFile("org.foo.Bar");
- sourcePersister.saveSource(project, file, "this is the file content");
- sourcePersister.saveSource(project, file, "new content"); // fail
+ sourcePersister.saveSource(file, "this is the file content");
+ sourcePersister.saveSource(file, "new content"); // fail
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/AbstractSourceImporter.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/AbstractSourceImporter.java
index f32e3e951ff..b11a96f5655 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/AbstractSourceImporter.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/AbstractSourceImporter.java
@@ -19,11 +19,6 @@
*/
package org.sonar.api.batch;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.List;
-
import org.apache.commons.io.FileUtils;
import org.sonar.api.CoreProperties;
import org.sonar.api.resources.Language;
@@ -32,6 +27,11 @@ import org.sonar.api.resources.ProjectFileSystem;
import org.sonar.api.resources.Resource;
import org.sonar.api.utils.SonarException;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.List;
+
/**
* A pre-implementation for a sensor that imports sources
*
@@ -88,6 +88,7 @@ public abstract class AbstractSourceImporter implements Sensor {
if (resource != null) {
try {
String source = FileUtils.readFileToString(file, sourcesEncoding.name());
+ context.index(resource);
context.saveSource(resource, source);
} catch (IOException e) {
throw new SonarException("Unable to read and import the source file : '" + file.getAbsolutePath() + "' with the charset : '"
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java
index ae0f10862c4..07b58dc1a13 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SensorContext.java
@@ -23,6 +23,7 @@ import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilter;
import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.DuplicatedSourceException;
import org.sonar.api.resources.ProjectLink;
import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Violation;
@@ -37,6 +38,57 @@ import java.util.Set;
*/
public interface SensorContext {
+ /**
+ * Indexes a resource as a direct child of project. This method does nothing and returns true if the resource already indexed.
+ *
+ * @return false if the resource is excluded
+ * @since 2.6
+ */
+ boolean index(Resource resource);
+
+
+ /**
+ * Indexes a resource. This method does nothing if the resource is already indexed.
+ *
+ * @param resource the resource to index. Not nullable
+ * @param parentReference a reference to the parent. If null, the the resource is indexed as a direct child of project.
+ * @return false if the parent is not indexed or if the resource is excluded
+ * @since 2.6
+ */
+ boolean index(Resource resource, Resource parentReference);
+
+ /**
+ * Returns true if the referenced resource is excluded. An excluded resource is not indexed.
+ * @since 2.6
+ */
+ boolean isExcluded(Resource reference);
+
+ /**
+ * @since 2.6
+ */
+ boolean isIndexed(Resource reference);
+
+ /**
+ * Search for an indexed resource.
+ *
+ * @param reference the resource reference
+ * @return the indexed resource, null if it's not indexed
+ * @since 1.10. Generic types since 2.6.
+ */
+ <R extends Resource> R getResource(R reference);
+
+ /**
+ * @since 2.6
+ */
+ Resource getParent(Resource reference);
+
+ /**
+ * @since 2.6
+ */
+
+ Collection<Resource> getChildren(Resource reference);
+
+
// ----------- MEASURES ON PROJECT --------------
/**
@@ -68,15 +120,13 @@ public interface SensorContext {
/**
* Key is updated when saving the resource.
- *
+ *
* @return the key as saved in database. Null if the resource is set as excluded.
+ * @deprecated use the methods index()
*/
+ @Deprecated
String saveResource(Resource resource);
- /**
- * @return the resource saved in sonar index
- */
- Resource getResource(Resource resource);
/**
* Find all measures for this project. Never return null.
@@ -105,9 +155,9 @@ public interface SensorContext {
/**
* Save a coding rule violation.
- *
- * @since 2.5
+ *
* @param force allows to force creation of violation even if it was supressed by {@link org.sonar.api.rules.ViolationFilter}
+ * @since 2.5
*/
void saveViolation(Violation violation, boolean force);
@@ -137,9 +187,15 @@ public interface SensorContext {
// ----------- FILE SOURCES --------------
/**
- * Does nothing if the resource is set as excluded.
+ * Save the source code of a file. The file must be have been indexed before.
+ * Note: the source stream is not closed.
+ *
+ * @return false if the resource is excluded or not indexed
+ * @throws org.sonar.api.resources.DuplicatedSourceException
+ * if the source has already been set on this resource
+ * @since 1.10. Returns a boolean since 2.6.
*/
- void saveSource(Resource resource, String source);
+ boolean saveSource(Resource reference, String source) throws DuplicatedSourceException;
// ----------- LINKS --------------
@@ -163,18 +219,18 @@ public interface SensorContext {
/**
* Creates an event for a given date
- *
- * @param name the event name
+ *
+ * @param name the event name
* @param description the event description
- * @param category the event category
- * @param date the event date
+ * @param category the event category
+ * @param date the event date
* @return the created event
*/
Event createEvent(Resource resource, String name, String description, String category, Date date);
/**
* Deletes an event
- *
+ *
* @param event the event to delete
*/
void deleteEvent(Event event);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java
index de6d6e1f670..8811492b955 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java
@@ -19,41 +19,102 @@
*/
package org.sonar.api.batch;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-
import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilter;
import org.sonar.api.measures.Metric;
+import org.sonar.api.resources.DuplicatedSourceException;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.ProjectLink;
import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Violation;
import org.sonar.graph.DirectedGraphAccessor;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Dependency> {
- public abstract Project getProject();
+ /**
+ * Indexes a resource as a direct child of project. This method does nothing and returns true if the resource already indexed.
+ *
+ * @return false if the resource is excluded
+ * @since 2.6
+ */
+ public abstract boolean index(Resource resource);
+
+
+ /**
+ * Indexes a resource. This method does nothing if the resource is already indexed.
+ *
+ * @param resource the resource to index. Not nullable
+ * @param parentReference a reference to the indexed parent. If null, the resource is indexed as a direct child of project.
+ * @return false if the parent is not indexed or if the resource is excluded
+ * @since 2.6
+ */
+ public abstract boolean index(Resource resource, Resource parentReference);
- public abstract Resource getResource(Resource resource);
+ /**
+ * Returns true if the referenced resource is excluded. An excluded resource is not indexed.
+ * @since 2.6
+ */
+ public abstract boolean isExcluded(Resource reference);
+
+ /**
+ * @since 2.6
+ */
+ public abstract boolean isIndexed(Resource reference);
+
+ /**
+ * Search for an indexed resource.
+ *
+ * @param reference the resource reference
+ * @return the indexed resource, null if it's not indexed
+ * @since 1.10. Generic types since 2.6.
+ */
+ public abstract <R extends Resource> R getResource(R reference);
+
+ /**
+ * @since 2.6
+ */
+ public abstract Resource getParent(Resource reference);
+
+ /**
+ * @since 2.6
+ */
+
+ public abstract Collection<Resource> getChildren(Resource reference);
+
+ /**
+ * Save the source code of a file. The file must be have been indexed before.
+ * Note: the source stream is not closed.
+ *
+ * @return false if the resource is excluded or not indexed
+ * @throws org.sonar.api.resources.DuplicatedSourceException
+ * if the source has already been set on this resource
+ */
+ public abstract boolean setSource(Resource reference, String source) throws DuplicatedSourceException;
+
+ public abstract Project getProject();
public final Collection<Resource> getResources() {
return getVertices();
}
- public abstract List<Resource> getChildren(Resource resource);
-
+ /**
+ * Indexes the resource.
+ * @return the indexed resource, even if it's excluded
+ * @deprecated since 2.6. Use methods index()
+ */
+ @Deprecated
public abstract Resource addResource(Resource resource);
public abstract Measure getMeasure(Resource resource, Metric metric);
public abstract <M> M getMeasures(Resource resource, MeasuresFilter<M> filter);
- public abstract void setSource(Resource resource, String source);
-
/**
* @since 2.5
*/
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Directory.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Directory.java
index ebf2b745c42..b2135800217 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Directory.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Directory.java
@@ -59,11 +59,11 @@ public class Directory extends Resource {
}
public String getScope() {
- return Resource.SCOPE_SPACE;
+ return Scopes.DIRECTORY;
}
public String getQualifier() {
- return Resource.QUALIFIER_DIRECTORY;
+ return Qualifiers.DIRECTORY;
}
public Resource getParent() {
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/DuplicatedSourceException.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/DuplicatedSourceException.java
new file mode 100644
index 00000000000..8cbd6dce026
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/DuplicatedSourceException.java
@@ -0,0 +1,14 @@
+package org.sonar.api.resources;
+
+import org.apache.commons.lang.ObjectUtils;
+import org.sonar.api.utils.SonarException;
+
+/**
+ * @since 2.6
+ */
+public final class DuplicatedSourceException extends SonarException {
+
+ public DuplicatedSourceException(Resource resource) {
+ super(ObjectUtils.toString(resource));
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/File.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/File.java
index e8d2b02cafc..24b7d32b6b8 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/File.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/File.java
@@ -19,12 +19,12 @@
*/
package org.sonar.api.resources;
-import java.util.List;
-
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.sonar.api.utils.WildcardPattern;
+import java.util.List;
+
/**
* This class is an implementation of a resource of type FILE
*
@@ -32,6 +32,8 @@ import org.sonar.api.utils.WildcardPattern;
*/
public class File extends Resource<Directory> {
+ public static final String SCOPE = Scopes.FILE;
+
private String directoryKey;
private String filename;
private Language language;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Library.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Library.java
index 1681a06b108..61f85842340 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Library.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Library.java
@@ -21,7 +21,7 @@ package org.sonar.api.resources;
import org.apache.commons.lang.builder.ToStringBuilder;
-public class Library extends Resource {
+public final class Library extends Resource {
private String name;
private String description;
@@ -68,12 +68,12 @@ public class Library extends Resource {
@Override
public String getScope() {
- return Resource.SCOPE_SET;
+ return Scopes.PROJECT;
}
@Override
public String getQualifier() {
- return Resource.QUALIFIER_LIB;
+ return Qualifiers.LIBRARY;
}
@Override
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
index e4f14394dfa..9890eeb830d 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Project.java
@@ -36,6 +36,8 @@ import java.util.List;
*/
public class Project extends Resource {
+ public static final String SCOPE = Scopes.PROJECT;
+
/**
* @deprecated since version 1.11. Constant moved to CoreProperties
*/
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Qualifiers.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Qualifiers.java
index f5f87b2161a..bb1c77e99ac 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Qualifiers.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Qualifiers.java
@@ -19,13 +19,35 @@
*/
package org.sonar.api.resources;
+/**
+ * The qualifier determines the exact type of a resource.
+ * Plugins can use their own qualifiers.
+ * @since 2.6
+ */
public interface Qualifiers {
String VIEW = "VW";
String SUBVIEW = "SVW";
- String LIB = "LIB";
+
+ /**
+ * Library, for example a JAR dependency of Java projects.
+ * Scope is Scopes.PROJECT
+ */
+ String LIBRARY = "LIB";
+
+ /**
+ * Single project or root of multi-modules projects
+ * Scope is Scopes.PROJECT
+ */
String PROJECT = "TRK";
+
+ /**
+ * Module of multi-modules project. It's sometimes called sub-project.
+ * Scope is Scopes.PROJECT
+ */
String MODULE = "BRC";
+
+
String PACKAGE = "PAC";
String DIRECTORY = "DIR";
String FILE = "FIL";
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Scopes.java b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Scopes.java
index fc8a29f2bbb..001fbd96e5e 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/resources/Scopes.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/resources/Scopes.java
@@ -20,7 +20,10 @@
package org.sonar.api.resources;
/**
- * Resource scopes are not extendable by plugins.
+ * Resource scopes are used to group resources. They relate to persisted resources only (project, directories and files).
+ * They are generally used in UI to display/hide some services or in web services.
+ *
+ * Resource scopes are not extensible by plugins.
*/
public interface Scopes {
/**
@@ -31,23 +34,11 @@ public interface Scopes {
/**
* For example directory or Java package. Persisted in database.
*/
- String NAMESPACE = "DIR";
+ String DIRECTORY = "DIR";
/**
* For example a Java file. Persisted in database.
*/
String FILE = "FIL";
- /**
- * For example a Java class or a Java interface. Not persisted in database.
- */
- String TYPE = "TYP";
-
- /**
- * For example a Java method. Not persisted in database.
- */
- String METHOD = "MET";
-
-
- String[] ORDERED_SCOPES = {PROJECT, NAMESPACE, FILE, TYPE, METHOD};
-}
+} \ No newline at end of file
diff --git a/sonar-server/pom.xml b/sonar-server/pom.xml
index 54873a7cd3c..a90ae860b18 100644
--- a/sonar-server/pom.xml
+++ b/sonar-server/pom.xml
@@ -29,6 +29,11 @@
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-java-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-update-center-common</artifactId>
</dependency>
<dependency>
diff --git a/tests/integration/tests/pom.xml b/tests/integration/tests/pom.xml
index 36a218cb59e..4f6f2790741 100644
--- a/tests/integration/tests/pom.xml
+++ b/tests/integration/tests/pom.xml
@@ -31,7 +31,7 @@
<clean>true</clean>
</configuration>
<goals>
- <goal>start-war</goal>
+ <goal>start</goal>
</goals>
</execution>
<execution>
@@ -48,7 +48,7 @@
<id>stop-server</id>
<phase>post-integration-test</phase>
<goals>
- <goal>stop-war</goal>
+ <goal>stop</goal>
</goals>
</execution>
</executions>