aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pom.xml10
-rw-r--r--sonar-application/pom.xml3
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskModule.java15
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java21
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java11
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java3
-rw-r--r--sonar-core/pom.xml11
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/ComponentGraph.java96
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/ComponentWrapper.java65
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/ElementWrapper.java47
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/ElementWrappers.java95
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/GraphReader.java43
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/GraphStorage.java63
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java40
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilders.java86
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/PerspectiveLoaders.java63
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/PerspectiveNotFoundException.java26
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java62
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/TransientGraph.java41
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/package-info.java23
-rw-r--r--sonar-core/src/main/java/org/sonar/core/graph/GraphDao.java53
-rw-r--r--sonar-core/src/main/java/org/sonar/core/graph/GraphDto.java83
-rw-r--r--sonar-core/src/main/java/org/sonar/core/graph/GraphDtoMapper.java30
-rw-r--r--sonar-core/src/main/java/org/sonar/core/graph/GraphUtil.java100
-rw-r--r--sonar-core/src/main/java/org/sonar/core/graph/GraphWriter.java45
-rw-r--r--sonar-core/src/main/java/org/sonar/core/graph/MultipleVerticesException.java26
-rw-r--r--sonar-core/src/main/java/org/sonar/core/graph/package-info.java23
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java1
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java5
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/graph/GraphDtoMapper.xml40
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql1
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl16
-rw-r--r--sonar-core/src/test/java/org/sonar/core/component/GraphUtilTest.java47
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/test/CoveredTestable.java29
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestCase.java30
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestPlan.java28
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestable.java26
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/test/TestCase.java52
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/test/TestPlan.java28
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/test/Testable.java32
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/test/package-info.java23
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/Platform.java11
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/db/migrate/370_create_graphs.rb38
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/db/migrate/README.txt2
46 files changed, 1579 insertions, 18 deletions
diff --git a/pom.xml b/pom.xml
index 643aa644654..b45669c07c3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -641,6 +641,16 @@
<version>3.2</version>
</dependency>
<dependency>
+ <groupId>com.tinkerpop.blueprints</groupId>
+ <artifactId>blueprints-core</artifactId>
+ <version>2.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>com.tinkerpop.gremlin</groupId>
+ <artifactId>gremlin-java</artifactId>
+ <version>2.2.0</version>
+ </dependency>
+ <dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-classworlds</artifactId>
<version>2.2.3</version>
diff --git a/sonar-application/pom.xml b/sonar-application/pom.xml
index 02576867e15..4ae705539db 100644
--- a/sonar-application/pom.xml
+++ b/sonar-application/pom.xml
@@ -210,7 +210,8 @@
<configuration>
<rules>
<requireFilesSize>
- <maxsize>54000000</maxsize>
+ <!-- TODO decrease after exclusion of Blueprints -> jackson/jettison -->
+ <maxsize>55000000</maxsize>
<minsize>52000000</minsize>
<files>
<file>${project.build.directory}/sonar-${project.version}.zip</file>
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskModule.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskModule.java
index d9233cb7f11..76f1df54be8 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskModule.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskModule.java
@@ -48,6 +48,9 @@ import org.sonar.batch.index.MemoryOptimizer;
import org.sonar.batch.index.SourcePersister;
import org.sonar.batch.tasks.InspectionTask;
import org.sonar.batch.tasks.ListTasksTask;
+import org.sonar.core.component.ComponentGraph;
+import org.sonar.core.component.GraphStorage;
+import org.sonar.core.component.PerspectiveBuilders;
import org.sonar.core.i18n.I18nManager;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.core.metric.CacheMetricFinder;
@@ -58,6 +61,8 @@ import org.sonar.core.persistence.MyBatis;
import org.sonar.core.persistence.SemaphoresImpl;
import org.sonar.core.resource.DefaultResourcePermissions;
import org.sonar.core.rule.CacheRuleFinder;
+import org.sonar.core.test.TestPlanBuilder;
+import org.sonar.core.test.TestableBuilder;
import org.sonar.core.user.DefaultUserFinder;
import org.sonar.jpa.dao.MeasuresDao;
import org.sonar.jpa.session.DefaultDatabaseConnector;
@@ -158,6 +163,13 @@ public class TaskModule extends Module {
container.addSingleton(DefaultFileLinesContextFactory.class);
container.addSingleton(ProjectLock.class);
container.addSingleton(DryRunDatabase.class);
+
+ // graphs
+ container.addSingleton(ComponentGraph.class);
+ container.addSingleton(TestPlanBuilder.class);
+ container.addSingleton(TestableBuilder.class);
+ container.addSingleton(PerspectiveBuilders.class);
+ container.addSingleton(GraphStorage.class);
}
private void logSettings() {
@@ -172,8 +184,7 @@ public class TaskModule extends Module {
Task task = container.getComponentByType(taskDefinition.getTask());
if (task != null) {
task.execute();
- }
- else {
+ } else {
throw new SonarException("Extension " + taskDefinition.getTask() + " was not found in declared extensions.");
}
}
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 fee88556e8b..2ad5f8a493d 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
@@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Event;
import org.sonar.api.batch.SonarIndex;
import org.sonar.api.database.model.ResourceModel;
+import org.sonar.api.database.model.Snapshot;
import org.sonar.api.design.Dependency;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.MeasuresFilter;
@@ -38,6 +39,7 @@ import org.sonar.api.measures.MetricFinder;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.ProjectLink;
+import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.api.resources.Scopes;
@@ -49,6 +51,7 @@ import org.sonar.batch.DefaultResourceCreationLock;
import org.sonar.batch.ProjectTree;
import org.sonar.batch.ResourceFilters;
import org.sonar.batch.ViolationFilters;
+import org.sonar.core.component.ComponentGraph;
import java.util.Collection;
import java.util.Collections;
@@ -67,6 +70,7 @@ public class DefaultIndex extends SonarIndex {
private PersistenceManager persistence;
private DefaultResourceCreationLock lock;
private MetricFinder metricFinder;
+ private ComponentGraph graph;
// filters
private ViolationFilters violationFilters;
@@ -80,11 +84,12 @@ public class DefaultIndex extends SonarIndex {
private Map<Resource, Map<Resource, Dependency>> incomingDependenciesByResource = Maps.newHashMap();
private ProjectTree projectTree;
- public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder) {
+ public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder, ComponentGraph graph) {
this.persistence = persistence;
this.lock = lock;
this.projectTree = projectTree;
this.metricFinder = metricFinder;
+ this.graph = graph;
}
public void start() {
@@ -465,10 +470,10 @@ public class DefaultIndex extends SonarIndex {
if (!StringUtils.equals(Scopes.PROJECT, resource.getScope())) {
// not a project nor a library
uid = new StringBuilder(ResourceModel.KEY_SIZE)
- .append(project.getKey())
- .append(':')
- .append(resource.getKey())
- .toString();
+ .append(project.getKey())
+ .append(':')
+ .append(resource.getKey())
+ .toString();
}
return uid;
}
@@ -551,8 +556,12 @@ public class DefaultIndex extends SonarIndex {
boolean excluded = checkExclusion(resource, parentBucket);
if (!excluded) {
- persistence.saveResource(currentProject, resource, (parentBucket != null ? parentBucket.getResource() : null));
+ Snapshot snapshot = persistence.saveResource(currentProject, resource, (parentBucket != null ? parentBucket.getResource() : null));
+ if (ResourceUtils.isPersistable(resource) && !Qualifiers.LIBRARY.equals(resource.getQualifier())) {
+ graph.createComponent(resource, snapshot);
+ }
}
+
return bucket;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java b/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java
index de4ace57ffc..080542eb5fe 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/phases/Phases.java
@@ -25,6 +25,7 @@ import org.sonar.api.resources.Project;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.DefaultIndex;
import org.sonar.batch.index.PersistenceManager;
+import org.sonar.core.component.GraphStorage;
import java.util.Collection;
@@ -48,12 +49,14 @@ public final class Phases {
private SensorContext sensorContext;
private DefaultIndex index;
private ProjectInitializer pi;
+ private GraphStorage graphStorage;
public Phases(DecoratorsExecutor decoratorsExecutor, MavenPhaseExecutor mavenPhaseExecutor,
MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
- EventBus eventBus, UpdateStatusJob updateStatusJob, ProjectInitializer pi) {
+ EventBus eventBus, UpdateStatusJob updateStatusJob, ProjectInitializer pi,
+ GraphStorage graphStorage) {
this.decoratorsExecutor = decoratorsExecutor;
this.mavenPhaseExecutor = mavenPhaseExecutor;
this.mavenPluginsConfigurator = mavenPluginsConfigurator;
@@ -66,15 +69,16 @@ public final class Phases {
this.eventBus = eventBus;
this.updateStatusJob = updateStatusJob;
this.pi = pi;
+ this.graphStorage = graphStorage;
}
public Phases(DecoratorsExecutor decoratorsExecutor, MavenPhaseExecutor mavenPhaseExecutor,
MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
- EventBus eventBus, ProjectInitializer pi) {
+ EventBus eventBus, ProjectInitializer pi, GraphStorage graphStorage) {
this(decoratorsExecutor, mavenPhaseExecutor, mavenPluginsConfigurator, initializersExecutor, postJobsExecutor,
- sensorsExecutor, persistenceManager, sensorContext, index, eventBus, null, pi);
+ sensorsExecutor, persistenceManager, sensorContext, index, eventBus, null, pi, graphStorage);
}
/**
@@ -94,6 +98,7 @@ public final class Phases {
persistenceManager.setDelayedMode(false);
if (project.isRoot()) {
+ graphStorage.save();
if (updateStatusJob != null) {
updateStatusJob.execute();
}
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 19babd292bd..75b06ac0fb9 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
@@ -52,6 +52,7 @@ import org.sonar.batch.DefaultResourceCreationLock;
import org.sonar.batch.ProjectTree;
import org.sonar.batch.ResourceFilters;
import org.sonar.batch.ViolationFilters;
+import org.sonar.core.component.ComponentGraph;
public class DefaultIndexTest {
@@ -65,7 +66,7 @@ public class DefaultIndexTest {
MetricFinder metricFinder = mock(MetricFinder.class);
when(metricFinder.findByKey("ncloc")).thenReturn(CoreMetrics.NCLOC);
- index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder);
+ index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder, mock(ComponentGraph.class));
Project project = new Project("project");
ResourceFilter filter = new ResourceFilter() {
diff --git a/sonar-core/pom.xml b/sonar-core/pom.xml
index bc73cee5c9f..14df0bb57fd 100644
--- a/sonar-core/pom.xml
+++ b/sonar-core/pom.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -64,6 +65,14 @@
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.tinkerpop.blueprints</groupId>
+ <artifactId>blueprints-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.tinkerpop.gremlin</groupId>
+ <artifactId>gremlin-java</artifactId>
+ </dependency>
<!-- logging -->
<dependency>
diff --git a/sonar-core/src/main/java/org/sonar/core/component/ComponentGraph.java b/sonar-core/src/main/java/org/sonar/core/component/ComponentGraph.java
new file mode 100644
index 00000000000..ff28e3a7c72
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/ComponentGraph.java
@@ -0,0 +1,96 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Element;
+import com.tinkerpop.blueprints.Graph;
+import com.tinkerpop.blueprints.KeyIndexableGraph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
+import com.tinkerpop.blueprints.util.ElementHelper;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.component.Component;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Resource;
+import org.sonar.core.graph.GraphUtil;
+
+public class ComponentGraph implements BatchComponent, ServerComponent {
+ private final KeyIndexableGraph graph;
+ private final ElementWrappers wrapperCache;
+ private final Vertex rootVertex;
+
+ public ComponentGraph() {
+ graph = new TinkerGraph();
+ graph.createKeyIndex("key", Vertex.class);
+ wrapperCache = new ElementWrappers();
+ rootVertex = graph.addVertex(null);
+ rootVertex.setProperty("root", "components");
+ }
+
+ public ComponentGraph(KeyIndexableGraph graph, Vertex rootVertex) {
+ this.graph = graph;
+ this.rootVertex = rootVertex;
+ wrapperCache = new ElementWrappers();
+ }
+
+ public <T extends ElementWrapper> T wrap(Element element, Class<T> wrapperClass) {
+ return wrapperCache.wrap(element, wrapperClass, this);
+ }
+
+ public <T extends ElementWrapper> T wrap(Component component, Class<T> wrapperClass) {
+ Vertex vertex = GraphUtil.single(graph.getVertices("key", component.getKey()));
+ T wrapper = wrapperCache.wrap(vertex, wrapperClass, this);
+ return wrapper;
+ }
+
+ public <T extends ElementWrapper<Vertex>> T createVertex(ElementWrapper<Vertex> from, Class<T> classWrapper, String edgeLabel, String... edgeProperties) {
+ T to = createVertex(classWrapper);
+ Edge edge = graph.addEdge(null, from.element(), to.element(), edgeLabel);
+ ElementHelper.setProperties(edge, edgeProperties);
+ return to;
+ }
+
+ private <T extends ElementWrapper<Vertex>> T createVertex(Class<T> classWrapper) {
+ Vertex vertex = graph.addVertex(null);
+ return wrapperCache.wrap(vertex, classWrapper, this);
+ }
+
+ public <C extends Component<C>> ComponentWrapper<C> createComponent(C component) {
+ Vertex componentVertex = graph.addVertex(null);
+ graph.addEdge(null, rootVertex, componentVertex, "component");
+ ComponentWrapper wrapper = wrapperCache.wrap(componentVertex, ComponentWrapper.class, this);
+ wrapper.populate(component);
+ return wrapper;
+ }
+
+ public ComponentWrapper createComponent(Resource resource, Snapshot snapshot) {
+ return createComponent(new ResourceComponent(resource, snapshot));
+ }
+
+ public Graph getUnderlyingGraph() {
+ return graph;
+ }
+
+ public Vertex getRootVertex() {
+ return rootVertex;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/ComponentWrapper.java b/sonar-core/src/main/java/org/sonar/core/component/ComponentWrapper.java
new file mode 100644
index 00000000000..cdd7599bcbb
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/ComponentWrapper.java
@@ -0,0 +1,65 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.tinkerpop.blueprints.Vertex;
+import org.sonar.api.component.Component;
+import org.sonar.core.graph.GraphUtil;
+
+import javax.annotation.Nullable;
+
+public class ComponentWrapper<C extends Component<C>> extends ElementWrapper<Vertex> implements Component<C> {
+
+ public String getKey() {
+ return (String) element().getProperty("key");
+ }
+
+ public String getName() {
+ return (String) element().getProperty("name");
+ }
+
+ public String getQualifier() {
+ return (String) element().getProperty("qualifier");
+ }
+
+ public ComponentWrapper setKey(String s) {
+ element().setProperty("key", s);
+ return this;
+ }
+
+ public ComponentWrapper setName(@Nullable String s) {
+ GraphUtil.setNullableProperty(element(), "name", s);
+ return this;
+ }
+
+ public ComponentWrapper setQualifier(String s) {
+ element().setProperty("qualifier", s);
+ return this;
+ }
+
+ public void populate(C component) {
+ setKey(component.getKey());
+ setName(component.getName());
+ setQualifier(component.getQualifier());
+ if (component instanceof ResourceComponent) {
+ element().setProperty("sid", ((ResourceComponent) component).getSnapshotId());
+ }
+ }
+} \ No newline at end of file
diff --git a/sonar-core/src/main/java/org/sonar/core/component/ElementWrapper.java b/sonar-core/src/main/java/org/sonar/core/component/ElementWrapper.java
new file mode 100644
index 00000000000..a53b3226087
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/ElementWrapper.java
@@ -0,0 +1,47 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.tinkerpop.blueprints.Element;
+
+/**
+ * Wrap a Blueprints vertex or edge.
+ */
+public abstract class ElementWrapper<T extends Element> {
+
+ private T element;
+ private ComponentGraph graph;
+
+ public T element() {
+ return element;
+ }
+
+ void setElement(T element) {
+ this.element = element;
+ }
+
+ public ComponentGraph graph() {
+ return graph;
+ }
+
+ void setGraph(ComponentGraph graph) {
+ this.graph = graph;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/ElementWrappers.java b/sonar-core/src/main/java/org/sonar/core/component/ElementWrappers.java
new file mode 100644
index 00000000000..17496c51d56
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/ElementWrappers.java
@@ -0,0 +1,95 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.google.common.collect.MapMaker;
+import com.tinkerpop.blueprints.Element;
+
+import java.util.Map;
+
+public class ElementWrappers {
+
+
+ private final Map<ElementKey, ElementWrapper> cache;
+
+ public ElementWrappers() {
+ cache = new MapMaker().weakValues().makeMap();
+ }
+
+ public void clear() {
+ cache.clear();
+ }
+
+ public <T extends ElementWrapper> T wrap(Element element, Class<T> wrapperClass, ComponentGraph graph) {
+ ElementKey key = new ElementKey(element, wrapperClass);
+ T wrapper = (T) cache.get(key);
+ if (wrapper == null) {
+ try {
+ wrapper = (T)key.wrapperClass.newInstance();
+ wrapper.setElement(key.element);
+ wrapper.setGraph(graph);
+ cache.put(key, wrapper);
+ } catch (InstantiationException e) {
+ throw new IllegalStateException("Class has no default constructor: " + wrapperClass, e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Can not access to default constructor: " + wrapperClass, e);
+ }
+ }
+ return wrapper;
+ }
+
+ public ElementWrappers remove(Element elt, Class wrapperClass) {
+ cache.remove(new ElementKey(elt, wrapperClass));
+ return this;
+ }
+
+ private static class ElementKey {
+ Element element;
+ Class<? extends ElementWrapper> wrapperClass;
+
+ ElementKey(Element element, Class<? extends ElementWrapper> wrapperClass) {
+ this.element = element;
+ this.wrapperClass = wrapperClass;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ElementKey that = (ElementKey) o;
+ if (!element.equals(that.element)) {
+ return false;
+ }
+ return wrapperClass.equals(that.wrapperClass);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = element.hashCode();
+ result = 31 * result + wrapperClass.hashCode();
+ return result;
+ }
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/GraphReader.java b/sonar-core/src/main/java/org/sonar/core/component/GraphReader.java
new file mode 100644
index 00000000000..c73ba75f85b
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/GraphReader.java
@@ -0,0 +1,43 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
+import com.tinkerpop.blueprints.util.io.graphson.GraphSONReader;
+import org.sonar.core.component.ComponentGraph;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+public class GraphReader {
+
+ public ComponentGraph read(String data, String rootVertexId) {
+ ByteArrayInputStream input = new ByteArrayInputStream(data.getBytes());
+ try {
+ TinkerGraph graph = new TinkerGraph();
+ GraphSONReader.inputGraph(graph, input);
+ Vertex root = graph.getVertex(rootVertexId);
+ return new ComponentGraph(graph, root);
+ } catch (IOException e) {
+ throw new IllegalStateException();
+ }
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/GraphStorage.java b/sonar-core/src/main/java/org/sonar/core/component/GraphStorage.java
new file mode 100644
index 00000000000..8789066eac7
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/GraphStorage.java
@@ -0,0 +1,63 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
+import org.slf4j.LoggerFactory;
+import org.sonar.core.graph.GraphDto;
+import org.sonar.core.graph.GraphDtoMapper;
+import org.sonar.core.graph.GraphWriter;
+import org.sonar.core.persistence.BatchSession;
+import org.sonar.core.persistence.MyBatis;
+
+public class GraphStorage {
+ private final MyBatis myBatis;
+ private final ComponentGraph componentGraph;
+
+ public GraphStorage(MyBatis myBatis, ComponentGraph componentGraph) {
+ this.myBatis = myBatis;
+ this.componentGraph = componentGraph;
+ }
+
+ public void save() {
+ LoggerFactory.getLogger(GraphStorage.class).info("Persisting graphs of components");
+ BatchSession session = myBatis.openBatchSession();
+ GraphDtoMapper mapper = session.getMapper(GraphDtoMapper.class);
+ try {
+ TinkerGraph subGraph = new TinkerGraph();
+ GraphWriter writer = new GraphWriter();
+ for (Vertex component : componentGraph.getRootVertex().getVertices(Direction.OUT, "component")) {
+ Long snapshotId = (Long) component.getProperty("sid");
+ if (snapshotId != null) {
+ String data = writer.write(componentGraph.getUnderlyingGraph());
+ mapper.insert(new GraphDto()
+ .setData(data).setFormat("graphson").setPerspective("testplan").setVersion(1)
+ .setSnapshotId(snapshotId).setRootVertexId(component.getId().toString()));
+ subGraph.clear();
+ }
+ }
+ session.commit();
+ } finally {
+ session.close();
+ }
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java
new file mode 100644
index 00000000000..9155e05bdc1
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java
@@ -0,0 +1,40 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.component.Perspective;
+
+public abstract class PerspectiveBuilder<T extends Perspective> implements BatchComponent, ServerComponent {
+
+ private final Class<T> perspectiveClass;
+
+ protected PerspectiveBuilder(Class<T> perspectiveClass) {
+ this.perspectiveClass = perspectiveClass;
+ }
+
+ protected Class<T> getPerspectiveClass() {
+ return perspectiveClass;
+ }
+
+ public abstract T build(ComponentWrapper<?> componentWrapper);
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilders.java b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilders.java
new file mode 100644
index 00000000000..ea7fa5c8370
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilders.java
@@ -0,0 +1,86 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.google.common.collect.MapMaker;
+import com.google.common.collect.Maps;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.batch.SonarIndex;
+import org.sonar.api.component.Component;
+import org.sonar.api.component.Perspective;
+import org.sonar.api.component.ResourcePerspectives;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Resource;
+
+import javax.annotation.CheckForNull;
+
+import java.util.Map;
+
+public class PerspectiveBuilders implements ResourcePerspectives, BatchComponent, ServerComponent {
+ private final ComponentGraph graph;
+ private Map<Class<?>, PerspectiveBuilder<?>> builders = Maps.newHashMap();
+ private final Map<Component, Map<Class<Perspective>, Perspective>> components = new MapMaker().weakValues().makeMap();
+ private final SonarIndex resourceIndex;
+
+ public PerspectiveBuilders(ComponentGraph graph, PerspectiveBuilder[] builders, SonarIndex resourceIndex) {
+ this.graph = graph;
+ this.resourceIndex = resourceIndex;
+ for (PerspectiveBuilder builder : builders) {
+ // TODO check duplications
+ this.builders.put(builder.getPerspectiveClass(), builder);
+ }
+ }
+
+ @CheckForNull
+ public <P extends Perspective> P as(Component component, Class<P> toClass) {
+ if (component.getKey() == null) {
+ return null;
+ }
+ Map<Class<Perspective>, Perspective> perspectives = components.get(component);
+ if (perspectives == null) {
+ perspectives = Maps.newHashMap();
+ components.put(component, perspectives);
+ }
+ P perspective = (P) perspectives.get(toClass);
+ if (perspective == null) {
+ ComponentWrapper componentWrapper = graph.wrap(component, ComponentWrapper.class);
+ perspective = builderFor(toClass).build(componentWrapper);
+ perspectives.put((Class) toClass, perspective);
+ }
+ return perspective;
+ }
+
+ public <P extends Perspective> P as(Resource resource, Class<P> toClass) {
+ Resource indexedResource = resourceIndex.getResource(resource);
+ if (indexedResource != null) {
+ return as(new ResourceComponent(indexedResource), toClass);
+ }
+ return null;
+ }
+
+ <T extends Perspective> PerspectiveBuilder<T> builderFor(Class<T> clazz) {
+ PerspectiveBuilder<T> builder = (PerspectiveBuilder<T>) builders.get(clazz);
+ if (builder == null) {
+ throw new PerspectiveNotFoundException("Perspective class is not registered: " + clazz);
+ }
+ return builder;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveLoaders.java b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveLoaders.java
new file mode 100644
index 00000000000..8aa6e930c79
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveLoaders.java
@@ -0,0 +1,63 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import org.sonar.api.ServerComponent;
+import org.sonar.api.component.Perspective;
+import org.sonar.core.graph.GraphDao;
+import org.sonar.core.graph.GraphDto;
+import org.sonar.core.test.DefaultTestPlan;
+import org.sonar.core.test.DefaultTestable;
+
+import javax.annotation.CheckForNull;
+
+public class PerspectiveLoaders implements ServerComponent {
+
+ private final GraphDao dao;
+
+ public PerspectiveLoaders(GraphDao dao) {
+ this.dao = dao;
+ }
+
+ @CheckForNull
+ <T extends Perspective> T as(String componentKey, String perspectiveKey) {
+ GraphDto graphDto = dao.selectByComponent(perspectiveKey, componentKey);
+ return doAs(perspectiveKey, graphDto);
+ }
+
+ @CheckForNull
+ <T extends Perspective> T as(long snapshotId, String perspectiveKey) {
+ GraphDto graphDto = dao.selectBySnapshot(perspectiveKey, snapshotId);
+ return doAs(perspectiveKey, graphDto);
+ }
+
+ private <T extends Perspective> T doAs(String perspectiveKey, GraphDto graphDto) {
+ T result = null;
+ if (graphDto != null) {
+ ComponentGraph graph = new GraphReader().read(graphDto.getData(), graphDto.getRootVertexId());
+ if (perspectiveKey.equals("testplan")) {
+ result = (T) graph.wrap(graph.getRootVertex(), DefaultTestPlan.class);
+ } else if (perspectiveKey.equals("testable")) {
+ result = (T) graph.wrap(graph.getRootVertex(), DefaultTestable.class);
+ }
+ }
+ return result;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveNotFoundException.java b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveNotFoundException.java
new file mode 100644
index 00000000000..78c27d5929e
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveNotFoundException.java
@@ -0,0 +1,26 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+public class PerspectiveNotFoundException extends RuntimeException {
+ public PerspectiveNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java b/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java
new file mode 100644
index 00000000000..413de496bc7
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java
@@ -0,0 +1,62 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import org.sonar.api.component.Component;
+import org.sonar.api.database.model.Snapshot;
+import org.sonar.api.resources.Resource;
+
+import javax.annotation.Nullable;
+
+class ResourceComponent implements Component {
+ private String key;
+ private String name;
+ private String qualifier;
+ private Long snapshotId;
+
+ ResourceComponent(Resource resource, @Nullable Snapshot snapshot) {
+ this.key = resource.getEffectiveKey();
+ this.name = resource.getName();
+ this.qualifier = resource.getQualifier();
+ if (snapshot!=null && snapshot.getId()!=null) {
+ this.snapshotId = snapshot.getId().longValue();
+ }
+ }
+
+ ResourceComponent(Resource resource) {
+ this(resource, null);
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getQualifier() {
+ return qualifier;
+ }
+
+ public Long getSnapshotId() {
+ return snapshotId;
+ }
+} \ No newline at end of file
diff --git a/sonar-core/src/main/java/org/sonar/core/component/TransientGraph.java b/sonar-core/src/main/java/org/sonar/core/component/TransientGraph.java
new file mode 100644
index 00000000000..739f86555fa
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/TransientGraph.java
@@ -0,0 +1,41 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.tinkerpop.blueprints.Graph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
+
+public class TransientGraph {
+ private Graph graph;
+ private Vertex root;
+
+ public TransientGraph() {
+ this.graph = new TinkerGraph();
+ }
+
+ public Vertex getRootVertex() {
+ return root;
+ }
+
+ public Graph getUnderlyingGraph() {
+ return graph;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/package-info.java b/sonar-core/src/main/java/org/sonar/core/component/package-info.java
new file mode 100644
index 00000000000..70ba35e1458
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.core.component;
+
+import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file
diff --git a/sonar-core/src/main/java/org/sonar/core/graph/GraphDao.java b/sonar-core/src/main/java/org/sonar/core/graph/GraphDao.java
new file mode 100644
index 00000000000..cbf357f7ff3
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/graph/GraphDao.java
@@ -0,0 +1,53 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.graph;
+
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.core.persistence.MyBatis;
+
+public class GraphDao {
+ private final MyBatis mybatis;
+
+ public GraphDao(MyBatis mybatis) {
+ this.mybatis = mybatis;
+ }
+
+ public GraphDto selectBySnapshot(String perspectiveKey, long snapshotId) {
+ SqlSession session = mybatis.openBatchSession();
+ try {
+ GraphDtoMapper mapper = session.getMapper(GraphDtoMapper.class);
+ return mapper.selectBySnapshot(perspectiveKey, snapshotId);
+
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public GraphDto selectByComponent(String perspectiveKey, String componentKey) {
+ SqlSession session = mybatis.openBatchSession();
+ try {
+ GraphDtoMapper mapper = session.getMapper(GraphDtoMapper.class);
+ return mapper.selectByComponent(perspectiveKey, componentKey);
+
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/graph/GraphDto.java b/sonar-core/src/main/java/org/sonar/core/graph/GraphDto.java
new file mode 100644
index 00000000000..a8e16333276
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/graph/GraphDto.java
@@ -0,0 +1,83 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.graph;
+
+public class GraphDto {
+ private long snapshotId;
+ private String format;
+ private String perspective;
+ private int version;
+ private String rootVertexId;
+ private String data;
+
+ public long getSnapshotId() {
+ return snapshotId;
+ }
+
+ public GraphDto setSnapshotId(long snapshotId) {
+ this.snapshotId = snapshotId;
+ return this;
+ }
+
+ public String getPerspective() {
+ return perspective;
+ }
+
+ public GraphDto setPerspective(String perspective) {
+ this.perspective = perspective;
+ return this;
+ }
+
+ public String getFormat() {
+ return format;
+ }
+
+ public GraphDto setFormat(String format) {
+ this.format = format;
+ return this;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public GraphDto setVersion(int version) {
+ this.version = version;
+ return this;
+ }
+
+ public String getRootVertexId() {
+ return rootVertexId;
+ }
+
+ public GraphDto setRootVertexId(String rootVertexId) {
+ this.rootVertexId = rootVertexId;
+ return this;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public GraphDto setData(String data) {
+ this.data = data;
+ return this;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/graph/GraphDtoMapper.java b/sonar-core/src/main/java/org/sonar/core/graph/GraphDtoMapper.java
new file mode 100644
index 00000000000..96f28c8bc52
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/graph/GraphDtoMapper.java
@@ -0,0 +1,30 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.graph;
+
+import org.apache.ibatis.annotations.Param;
+
+public interface GraphDtoMapper {
+ void insert(GraphDto graph);
+
+ GraphDto selectBySnapshot(@Param("perspective") String perspectiveKey, @Param("sid") long snapshotId);
+
+ GraphDto selectByComponent(@Param("perspective") String perspectiveKey, @Param("key") String componentKey);
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/graph/GraphUtil.java b/sonar-core/src/main/java/org/sonar/core/graph/GraphUtil.java
new file mode 100644
index 00000000000..4b56a69c116
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/graph/GraphUtil.java
@@ -0,0 +1,100 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.graph;
+
+import com.google.common.collect.Lists;
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Element;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
+import com.tinkerpop.blueprints.util.ElementHelper;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.Iterator;
+import java.util.List;
+
+public class GraphUtil {
+
+ private GraphUtil() {
+ }
+
+ /**
+ * Get adjacent vertex. It assumes that there are only 0 or 1 results.
+ *
+ * @throws MultipleVerticesException if there are more than 1 adjacent vertices with the given criteria.
+ */
+ @CheckForNull
+ public static Vertex adjacent(Vertex from, Direction direction, String... labels) {
+ Iterator<Vertex> vertices = from.getVertices(direction, labels).iterator();
+ Vertex result = null;
+ if (vertices.hasNext()) {
+ result = vertices.next();
+ if (vertices.hasNext()) {
+ throw new MultipleVerticesException(String.format("More than one vertex adjacent to: %s, direction: %s, labels: ", from, direction, labels));
+ }
+ }
+ return result;
+ }
+
+ public static <T extends Element> T single(Iterable<T> iterable) {
+ Iterator<T> iterator = iterable.iterator();
+ T result = null;
+ if (iterator.hasNext()) {
+ result = iterator.next();
+ if (iterator.hasNext()) {
+ throw new MultipleVerticesException("More than one elements");
+ }
+ }
+ return result;
+ }
+
+ public static void setNullableProperty(Element elt, String key, @Nullable Object value) {
+ if (value == null) {
+ elt.removeProperty(key);
+ } else {
+ elt.setProperty(key, value);
+ }
+ }
+
+ public static void subGraph(GremlinPipeline path, TinkerGraph toGraph) {
+ List<Edge> edges = Lists.newArrayList();
+ if (path.hasNext()) {
+ for (Object element : (Iterable) path.next()) {
+ if (element instanceof Vertex) {
+ Vertex v = (Vertex) element;
+ Vertex toVertex = toGraph.addVertex(v.getId());
+ ElementHelper.copyProperties(v, toVertex);
+ } else if (element instanceof Edge) {
+ edges.add((Edge) element);
+ }
+ }
+ for (Edge edge : edges) {
+ Vertex from = edge.getVertex(Direction.IN);
+ Vertex to = edge.getVertex(Direction.OUT);
+ Edge copyEdge = toGraph.addEdge(edge.getId(), toGraph.getVertex(from.getId()), toGraph.getVertex(to.getId()), edge.getLabel());
+ ElementHelper.copyProperties(edge, copyEdge);
+ }
+ }
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/graph/GraphWriter.java b/sonar-core/src/main/java/org/sonar/core/graph/GraphWriter.java
new file mode 100644
index 00000000000..1c64fa59d74
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/graph/GraphWriter.java
@@ -0,0 +1,45 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.graph;
+
+import com.tinkerpop.blueprints.Graph;
+import com.tinkerpop.blueprints.util.io.graphson.GraphSONMode;
+import com.tinkerpop.blueprints.util.io.graphson.GraphSONWriter;
+import org.apache.commons.io.IOUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class GraphWriter {
+
+ public String write(Graph graph) {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ try {
+ GraphSONWriter.outputGraph(graph, output, GraphSONMode.COMPACT);
+ output.flush();
+ output.close();
+ return new String(output.toByteArray());
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to export graph to JSON", e);
+ } finally {
+ IOUtils.closeQuietly(output);
+ }
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/graph/MultipleVerticesException.java b/sonar-core/src/main/java/org/sonar/core/graph/MultipleVerticesException.java
new file mode 100644
index 00000000000..384edd34c41
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/graph/MultipleVerticesException.java
@@ -0,0 +1,26 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.graph;
+
+public class MultipleVerticesException extends RuntimeException {
+ public MultipleVerticesException(String message) {
+ super(message);
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/graph/package-info.java b/sonar-core/src/main/java/org/sonar/core/graph/package-info.java
new file mode 100644
index 00000000000..6471810686f
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/graph/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.core.graph;
+
+import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java
index ee008ae6467..9d550066d2b 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java
@@ -20,6 +20,7 @@
package org.sonar.core.persistence;
import com.google.common.collect.ImmutableList;
+import org.sonar.core.graph.GraphDao;
import org.sonar.core.dashboard.ActiveDashboardDao;
import org.sonar.core.dashboard.DashboardDao;
import org.sonar.core.duplication.DuplicationDao;
@@ -50,6 +51,7 @@ public final class DaoUtils {
AuthorDao.class,
DashboardDao.class,
DuplicationDao.class,
+ GraphDao.class,
LoadedTemplateDao.class,
MeasureFilterDao.class,
PropertiesDao.class,
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java
index 7819ab82d3f..2707689c340 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseUtils.java
@@ -57,6 +57,7 @@ public final class DatabaseUtils {
"dependencies",
"duplications_index",
"events",
+ "graphs",
"groups",
"groups_users",
"group_roles",
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
index abaede43292..1ec8a9fbe28 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
@@ -32,7 +32,7 @@ import java.util.List;
*/
public class DatabaseVersion implements BatchComponent, ServerComponent {
- public static final int LAST_VERSION = 363;
+ public static final int LAST_VERSION = 370;
public static enum Status {
UP_TO_DATE, REQUIRES_UPGRADE, REQUIRES_DOWNGRADE, FRESH_INSTALL
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
index 2cecc87304a..2ec68c4fdb1 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
@@ -38,6 +38,8 @@ import org.sonar.api.config.Settings;
import org.sonar.api.database.model.MeasureData;
import org.sonar.api.database.model.MeasureMapper;
import org.sonar.api.database.model.MeasureModel;
+import org.sonar.core.graph.GraphDto;
+import org.sonar.core.graph.GraphDtoMapper;
import org.sonar.core.config.Logback;
import org.sonar.core.dashboard.ActiveDashboardDto;
import org.sonar.core.dashboard.ActiveDashboardMapper;
@@ -114,6 +116,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
loadAlias(conf, "Dashboard", DashboardDto.class);
loadAlias(conf, "Dependency", DependencyDto.class);
loadAlias(conf, "DuplicationUnit", DuplicationUnitDto.class);
+ loadAlias(conf, "Graph", GraphDto.class);
loadAlias(conf, "Group", GroupDto.class);
loadAlias(conf, "GroupRole", GroupRoleDto.class);
loadAlias(conf, "LoadedTemplate", LoadedTemplateDto.class);
@@ -137,7 +140,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
loadAlias(conf, "MeasureData", MeasureData.class);
Class<?>[] mappers = {ActiveDashboardMapper.class, AuthorMapper.class, DashboardMapper.class,
- DependencyMapper.class, DuplicationMapper.class, LoadedTemplateMapper.class, MeasureFilterMapper.class, PropertiesMapper.class, PurgeMapper.class,
+ DependencyMapper.class, DuplicationMapper.class, GraphDtoMapper.class, LoadedTemplateMapper.class, MeasureFilterMapper.class, PropertiesMapper.class, PurgeMapper.class,
ResourceKeyUpdaterMapper.class, ResourceIndexerMapper.class, ResourceMapper.class, ResourceSnapshotMapper.class, ReviewCommentMapper.class,
ReviewMapper.class, RoleMapper.class, RuleMapper.class, SchemaMigrationMapper.class, SemaphoreMapper.class, UserMapper.class, WidgetMapper.class, WidgetPropertyMapper.class,
MeasureMapper.class};
diff --git a/sonar-core/src/main/resources/org/sonar/core/graph/GraphDtoMapper.xml b/sonar-core/src/main/resources/org/sonar/core/graph/GraphDtoMapper.xml
new file mode 100644
index 00000000000..3da0473498c
--- /dev/null
+++ b/sonar-core/src/main/resources/org/sonar/core/graph/GraphDtoMapper.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.sonar.core.graph.GraphDtoMapper">
+
+ <select id="selectBySnapshot" parameterType="map" resultType="Graph">
+ SELECT snapshot_id as snapshotId, format, version, perspective, data
+ FROM graphs
+ WHERE snapshot_id = #{sid} AND perspective = #{perspective}
+ </select>
+
+ <select id="selectByComponent" parameterType="map" resultType="Graph">
+ SELECT g.snapshot_id as snapshotId, g.format, g.version, g.perspective, g.data
+ FROM graphs g, snapshots s
+ WHERE g.perspective = #{perspective} AND g.snapshot_id=s.id AND s.islast=${_true} and s.project_id=(
+ select id from projects where enabled=${_true} and kee=#{key} and person_id is null and copy_resource_id is null
+ )
+ </select>
+
+ <insert id="insert" parameterType="Graph" useGeneratedKeys="false">
+ insert into graphs
+ (snapshot_id, format, version, perspective, root_vertex_id, data, created_at, updated_at)
+ values (
+ #{snapshotId}, #{format}, #{version}, #{perspective}, #{rootVertexId},
+ #{data}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
+ </insert>
+
+ <!-- Oracle -->
+ <insert id="insert" databaseId="oracle" parameterType="Graph" useGeneratedKeys="false" keyProperty="id">
+ <selectKey order="BEFORE" resultType="Long" keyProperty="id">
+ select graphs_seq.NEXTVAL from DUAL
+ </selectKey>
+ insert into graphs
+ (id, snapshot_id, format, version, perspective, root_vertex_id, data, created_at, updated_at)
+ values (
+ #{id}, #{snapshotId}, #{format}, #{version}, #{perspective}, #{rootVertexId},
+ #{data}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
+ </insert>
+</mapper>
+
diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
index 7e100e3f970..18f965622b9 100644
--- a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
+++ b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
@@ -148,6 +148,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('360');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('361');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('362');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('363');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('370');
INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '2011-09-26 22:27:48.0', '2011-09-26 22:27:48.0', null, null);
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl b/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
index bb29d4e21d2..413c2f65832 100644
--- a/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
+++ b/sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
@@ -499,6 +499,18 @@ CREATE TABLE "MEASURE_FILTER_FAVOURITES" (
"CREATED_AT" TIMESTAMP
);
+CREATE TABLE "GRAPHS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "SNAPSHOT_ID" INTEGER NOT NULL,
+ "FORMAT" VARCHAR(20),
+ "PERSPECTIVE" VARCHAR(30),
+ "VERSION" VARCHAR(20),
+ "ROOT_VERTEX_ID" VARCHAR(30),
+ "DATA" CLOB(2147483647),
+ "CREATED_AT" TIMESTAMP,
+ "UPDATED_AT" TIMESTAMP
+);
+
-- ----------------------------------------------
-- DDL Statements for indexes
-- ----------------------------------------------
@@ -607,4 +619,6 @@ CREATE UNIQUE INDEX "UNIQ_AUTHOR_LOGINS" ON "AUTHORS" ("LOGIN");
CREATE INDEX "MEASURE_FILTERS_NAME" ON "MEASURE_FILTERS" ("NAME");
-CREATE INDEX "MEASURE_FILTER_FAVS_USERID" ON "MEASURE_FILTER_FAVOURITES" ("USER_ID"); \ No newline at end of file
+CREATE INDEX "MEASURE_FILTER_FAVS_USERID" ON "MEASURE_FILTER_FAVOURITES" ("USER_ID");
+
+CREATE UNIQUE INDEX "GRAPHS_PERSPECTIVES" ON "GRAPHS" ("SNAPSHOT_ID", "PERSPECTIVE"); \ No newline at end of file
diff --git a/sonar-core/src/test/java/org/sonar/core/component/GraphUtilTest.java b/sonar-core/src/test/java/org/sonar/core/component/GraphUtilTest.java
new file mode 100644
index 00000000000..82a2fbdf3d4
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/component/GraphUtilTest.java
@@ -0,0 +1,47 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.core.component;
+
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import org.junit.Test;
+import org.sonar.core.graph.GraphUtil;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class GraphUtilTest {
+ @Test
+ public void subGraph() {
+ TinkerGraph graph = new TinkerGraph();
+ Vertex a = graph.addVertex("1");
+ Vertex b = graph.addVertex("2");
+ Vertex c = graph.addVertex("3");
+ graph.addEdge("4", a, b, "likes");
+ graph.addEdge("5", b, c, "has");
+
+ TinkerGraph subGraph = new TinkerGraph();
+ GremlinPipeline pipeline = new GremlinPipeline(a).outE("likes").inV().path();
+ GraphUtil.subGraph(pipeline, subGraph);
+
+ assertThat(subGraph.getVertices()).hasSize(2);
+ assertThat(subGraph.getEdges()).hasSize(1);
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/test/CoveredTestable.java b/sonar-plugin-api/src/main/java/org/sonar/api/test/CoveredTestable.java
new file mode 100644
index 00000000000..a52d7477664
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/test/CoveredTestable.java
@@ -0,0 +1,29 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.test;
+
+import java.util.Collection;
+
+public interface CoveredTestable {
+
+ TestCase testCase();
+ Testable testable();
+ Collection<Integer> lines();
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestCase.java b/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestCase.java
new file mode 100644
index 00000000000..66cef5cc0e6
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestCase.java
@@ -0,0 +1,30 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.test;
+
+import javax.annotation.Nullable;
+
+public interface MutableTestCase extends TestCase {
+ MutableTestCase setStatus(String s);
+
+ MutableTestCase setDurationInMs(@Nullable Long l);
+
+ MutableTestCase setName(String s);
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestPlan.java b/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestPlan.java
new file mode 100644
index 00000000000..15d7e8f246f
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestPlan.java
@@ -0,0 +1,28 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.test;
+
+import org.sonar.api.component.MutablePerspective;
+
+public interface MutableTestPlan extends TestPlan<MutableTestCase>, MutablePerspective {
+
+ MutableTestCase addTestCase(String key);
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestable.java b/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestable.java
new file mode 100644
index 00000000000..87d153eb916
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestable.java
@@ -0,0 +1,26 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.test;
+
+import org.sonar.api.component.MutablePerspective;
+
+public interface MutableTestable extends Testable, MutablePerspective {
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/test/TestCase.java b/sonar-plugin-api/src/main/java/org/sonar/api/test/TestCase.java
new file mode 100644
index 00000000000..948353d32c7
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/test/TestCase.java
@@ -0,0 +1,52 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.test;
+
+import java.util.Collection;
+
+public interface TestCase {
+ String TYPE_UNIT = "unit";
+ String TYPE_INTEGRATION = "integ";
+
+ String STATUS_PASS = "pass";
+ String STATUS_FAIL = "fail";
+
+ // unit test/integration test/...
+ String type();
+
+ /**
+ * Duration in milliseconds
+ */
+ Long durationInMs();
+
+ // pass/fail/...
+ String status();
+
+ /**
+ * The key is not null and unique among the test plan.
+ */
+ String key();
+
+ String name();
+
+ TestPlan testPlan();
+
+ Collection<CoveredTestable> coveredBlocks();
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/test/TestPlan.java b/sonar-plugin-api/src/main/java/org/sonar/api/test/TestPlan.java
new file mode 100644
index 00000000000..c6c6f1827ee
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/test/TestPlan.java
@@ -0,0 +1,28 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.test;
+
+import org.sonar.api.component.Perspective;
+
+import java.util.List;
+
+public interface TestPlan<T extends TestCase> extends Perspective {
+ List<T> testCases();
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/test/Testable.java b/sonar-plugin-api/src/main/java/org/sonar/api/test/Testable.java
new file mode 100644
index 00000000000..d28401cf294
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/test/Testable.java
@@ -0,0 +1,32 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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.api.test;
+
+import org.sonar.api.component.Perspective;
+
+import java.util.List;
+import java.util.SortedSet;
+
+public interface Testable extends Perspective {
+ List<TestCase> coveringTestCases();
+
+ List<TestCase> testCasesCoveringLine(int line);
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/test/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/test/package-info.java
new file mode 100644
index 00000000000..0629ea96a37
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/test/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * 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
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.test;
+
+import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index eff0770fcf3..f87b6a1b68d 100644
--- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -36,6 +36,9 @@ import org.sonar.api.utils.TimeProfiler;
import org.sonar.api.utils.UriReader;
import org.sonar.api.workflow.internal.DefaultWorkflow;
import org.sonar.core.PicoUtils;
+import org.sonar.core.component.ComponentGraph;
+import org.sonar.core.component.PerspectiveBuilders;
+import org.sonar.core.component.PerspectiveLoaders;
import org.sonar.core.config.Logback;
import org.sonar.core.i18n.GwtI18n;
import org.sonar.core.i18n.I18nManager;
@@ -55,6 +58,8 @@ import org.sonar.core.persistence.SemaphoresImpl;
import org.sonar.core.qualitymodel.DefaultModelFinder;
import org.sonar.core.resource.DefaultResourcePermissions;
import org.sonar.core.rule.DefaultRuleFinder;
+import org.sonar.core.test.TestPlanBuilder;
+import org.sonar.core.test.TestableBuilder;
import org.sonar.core.timemachine.Periods;
import org.sonar.core.user.DefaultUserFinder;
import org.sonar.core.workflow.ReviewDatabaseStore;
@@ -256,6 +261,12 @@ public final class Platform {
servicesContainer.addSingleton(DefaultNotificationManager.class);
servicesContainer.addSingleton(ReviewsNotificationManager.class);
+ servicesContainer.addSingleton(ComponentGraph.class);
+ servicesContainer.addSingleton(TestPlanBuilder.class);
+ servicesContainer.addSingleton(TestableBuilder.class);
+ servicesContainer.addSingleton(PerspectiveBuilders.class);
+ servicesContainer.addSingleton(PerspectiveLoaders.class);
+
ServerExtensionInstaller extensionRegistrar = servicesContainer.getComponentByType(ServerExtensionInstaller.class);
extensionRegistrar.registerExtensions(servicesContainer);
diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/370_create_graphs.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/370_create_graphs.rb
new file mode 100644
index 00000000000..0b37503f165
--- /dev/null
+++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/370_create_graphs.rb
@@ -0,0 +1,38 @@
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2012 SonarSource
+# 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
+#
+
+#
+# Sonar 3.5
+#
+class CreateGraphs < ActiveRecord::Migration
+ def self.up
+ create_table 'graphs' do |t|
+ t.column 'snapshot_id', :integer, :null => false
+ t.column 'format', :string, :null => true, :limit => 20
+ t.column 'perspective', :string, :null => true, :limit => 30
+ t.column 'version', :string, :null => true, :limit => 20
+ t.column 'root_vertex_id', :string, :null => true, :limit => 30
+ t.column 'data', :text, :null => true
+ t.timestamps
+ end
+ add_index 'graphs', ['snapshot_id', 'perspective'], :name => 'graphs_perspectives', :unique => true
+ end
+end
+
diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/README.txt b/sonar-server/src/main/webapp/WEB-INF/db/migrate/README.txt
index dcc2a5250ec..c9b1b28eb5a 100644
--- a/sonar-server/src/main/webapp/WEB-INF/db/migrate/README.txt
+++ b/sonar-server/src/main/webapp/WEB-INF/db/migrate/README.txt
@@ -1,7 +1,7 @@
HOW TO ADD A MIGRATION
* Jump some versions when adding the first Ruby on Rails migration of a new sonar version. For example if sonar 2.10 is 193, then sonar 2.11 should start at 200.
-* Complete the DDL files for Derby :
+* Complete the DDL files for H2 :
+ sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
+ sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql :
- add "INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('<THE MIGRATION ID>')"