From 62806519276a867d5f243f18fc5e8b12e34f5b69 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 29 Jan 2013 09:51:25 +0100 Subject: [PATCH] SONAR-2501 refactor BeanGraph layer --- .../org/sonar/batch/bootstrap/TaskModule.java | 12 +- .../org/sonar/batch/index/DefaultIndex.java | 8 +- .../java/org/sonar/batch/phases/Phases.java | 8 +- .../sonar/batch/index/DefaultIndexTest.java | 4 +- .../sonar/core/component/ComponentGraph.java | 96 ----------- .../sonar/core/component/ComponentVertex.java | 28 ++++ .../core/component/ComponentWrapper.java | 65 -------- .../core/component/PerspectiveBuilder.java | 15 +- .../core/component/PerspectiveLoaders.java | 72 --------- .../core/component/ResourceComponent.java | 10 +- .../org/sonar/core/component/ScanGraph.java | 77 +++++++++ ...{GraphStorage.java => ScanGraphStore.java} | 43 +++-- ...iveBuilders.java => ScanPerspectives.java} | 47 +++--- ...TransientGraph.java => SnapshotGraph.java} | 20 +-- .../core/component/SnapshotPerspectives.java | 87 ++++++++++ .../BeanEdge.java} | 28 +--- .../org/sonar/core/graph/BeanElement.java | 68 ++++++++ .../BeanElements.java} | 53 +++--- .../java/org/sonar/core/graph/BeanGraph.java | 56 +++++++ .../org/sonar/core/graph/BeanIterable.java | 55 +++++++ .../BeanVertex.java} | 23 +-- .../sonar/core/graph/{ => jdbc}/GraphDao.java | 2 +- .../sonar/core/graph/{ => jdbc}/GraphDto.java | 2 +- .../core/graph/{ => jdbc}/GraphDtoMapper.java | 2 +- .../sonar/core/graph/jdbc/package-info.java | 23 +++ .../org/sonar/core/persistence/DaoUtils.java | 2 +- .../org/sonar/core/persistence/MyBatis.java | 4 +- .../org/sonar/core/test/DefaultTestCase.java | 37 ++--- .../org/sonar/core/test/DefaultTestPlan.java | 14 +- .../org/sonar/core/test/DefaultTestable.java | 8 +- .../org/sonar/core/test/TestPlanBuilder.java | 17 +- .../org/sonar/core/test/TestableBuilder.java | 16 +- .../core/graph/{ => jdbc}/GraphDtoMapper.xml | 2 +- .../core/component/ResourceComponentTest.java | 53 ++++++ .../org/sonar/core/graph/BeanElementTest.java | 105 ++++++++++++ .../sonar/core/graph/BeanElementsTest.java | 144 +++++++++++++++++ .../core/graph/{ => jdbc}/GraphDaoTest.java | 2 +- .../sonar/core/test/TestPlanBuilderTest.java | 152 +++++++++--------- .../graph/{ => jdbc}/GraphDaoTest/shared.xml | 0 .../org/sonar/api/component/Component.java | 6 +- .../org/sonar/api/component/Perspectives.java | 8 +- .../api/component/ResourcePerspectives.java | 7 +- .../api/component/mock/MockSourceFile.java | 10 +- .../org/sonar/server/platform/Platform.java | 9 +- .../java/org/sonar/server/ui/JRubyFacade.java | 5 +- 45 files changed, 977 insertions(+), 528 deletions(-) delete mode 100644 sonar-core/src/main/java/org/sonar/core/component/ComponentGraph.java create mode 100644 sonar-core/src/main/java/org/sonar/core/component/ComponentVertex.java delete mode 100644 sonar-core/src/main/java/org/sonar/core/component/ComponentWrapper.java delete mode 100644 sonar-core/src/main/java/org/sonar/core/component/PerspectiveLoaders.java create mode 100644 sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java rename sonar-core/src/main/java/org/sonar/core/component/{GraphStorage.java => ScanGraphStore.java} (54%) rename sonar-core/src/main/java/org/sonar/core/component/{PerspectiveBuilders.java => ScanPerspectives.java} (55%) rename sonar-core/src/main/java/org/sonar/core/component/{TransientGraph.java => SnapshotGraph.java} (76%) create mode 100644 sonar-core/src/main/java/org/sonar/core/component/SnapshotPerspectives.java rename sonar-core/src/main/java/org/sonar/core/{component/ElementWrapper.java => graph/BeanEdge.java} (64%) create mode 100644 sonar-core/src/main/java/org/sonar/core/graph/BeanElement.java rename sonar-core/src/main/java/org/sonar/core/{component/ElementWrappers.java => graph/BeanElements.java} (60%) create mode 100644 sonar-core/src/main/java/org/sonar/core/graph/BeanGraph.java create mode 100644 sonar-core/src/main/java/org/sonar/core/graph/BeanIterable.java rename sonar-core/src/main/java/org/sonar/core/{component/GraphReader.java => graph/BeanVertex.java} (59%) rename sonar-core/src/main/java/org/sonar/core/graph/{ => jdbc}/GraphDao.java (98%) rename sonar-core/src/main/java/org/sonar/core/graph/{ => jdbc}/GraphDto.java (98%) rename sonar-core/src/main/java/org/sonar/core/graph/{ => jdbc}/GraphDtoMapper.java (97%) create mode 100644 sonar-core/src/main/java/org/sonar/core/graph/jdbc/package-info.java rename sonar-core/src/main/resources/org/sonar/core/graph/{ => jdbc}/GraphDtoMapper.xml (96%) create mode 100644 sonar-core/src/test/java/org/sonar/core/component/ResourceComponentTest.java create mode 100644 sonar-core/src/test/java/org/sonar/core/graph/BeanElementTest.java create mode 100644 sonar-core/src/test/java/org/sonar/core/graph/BeanElementsTest.java rename sonar-core/src/test/java/org/sonar/core/graph/{ => jdbc}/GraphDaoTest.java (98%) rename sonar-core/src/test/resources/org/sonar/core/graph/{ => jdbc}/GraphDaoTest/shared.xml (100%) 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 76f1df54be8..28d31500a82 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,9 +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.component.ScanGraph; +import org.sonar.core.component.ScanGraphStore; +import org.sonar.core.component.ScanPerspectives; import org.sonar.core.i18n.I18nManager; import org.sonar.core.i18n.RuleI18nManager; import org.sonar.core.metric.CacheMetricFinder; @@ -165,11 +165,11 @@ public class TaskModule extends Module { container.addSingleton(DryRunDatabase.class); // graphs - container.addSingleton(ComponentGraph.class); + container.addSingleton(ScanGraph.create()); container.addSingleton(TestPlanBuilder.class); container.addSingleton(TestableBuilder.class); - container.addSingleton(PerspectiveBuilders.class); - container.addSingleton(GraphStorage.class); + container.addSingleton(ScanPerspectives.class); + container.addSingleton(ScanGraphStore.class); } private void logSettings() { 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 2ad5f8a493d..26ac1277c22 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 @@ -51,7 +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 org.sonar.core.component.ScanGraph; import java.util.Collection; import java.util.Collections; @@ -70,7 +70,7 @@ public class DefaultIndex extends SonarIndex { private PersistenceManager persistence; private DefaultResourceCreationLock lock; private MetricFinder metricFinder; - private ComponentGraph graph; + private ScanGraph graph; // filters private ViolationFilters violationFilters; @@ -84,7 +84,7 @@ public class DefaultIndex extends SonarIndex { private Map> incomingDependenciesByResource = Maps.newHashMap(); private ProjectTree projectTree; - public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder, ComponentGraph graph) { + public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder, ScanGraph graph) { this.persistence = persistence; this.lock = lock; this.projectTree = projectTree; @@ -558,7 +558,7 @@ public class DefaultIndex extends SonarIndex { if (!excluded) { Snapshot snapshot = persistence.saveResource(currentProject, resource, (parentBucket != null ? parentBucket.getResource() : null)); if (ResourceUtils.isPersistable(resource) && !Qualifiers.LIBRARY.equals(resource.getQualifier())) { - graph.createComponent(resource, snapshot); + graph.addComponent(resource, snapshot); } } 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 080542eb5fe..489cdd075bd 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,7 +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 org.sonar.core.component.ScanGraphStore; import java.util.Collection; @@ -49,14 +49,14 @@ public final class Phases { private SensorContext sensorContext; private DefaultIndex index; private ProjectInitializer pi; - private GraphStorage graphStorage; + private ScanGraphStore 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, - GraphStorage graphStorage) { + ScanGraphStore graphStorage) { this.decoratorsExecutor = decoratorsExecutor; this.mavenPhaseExecutor = mavenPhaseExecutor; this.mavenPluginsConfigurator = mavenPluginsConfigurator; @@ -76,7 +76,7 @@ public final class Phases { MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index, - EventBus eventBus, ProjectInitializer pi, GraphStorage graphStorage) { + EventBus eventBus, ProjectInitializer pi, ScanGraphStore graphStorage) { this(decoratorsExecutor, mavenPhaseExecutor, mavenPluginsConfigurator, initializersExecutor, postJobsExecutor, sensorsExecutor, persistenceManager, sensorContext, index, eventBus, null, pi, graphStorage); } 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 75b06ac0fb9..87cb9361e11 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,7 +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; +import org.sonar.core.component.ScanGraph; public class DefaultIndexTest { @@ -66,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, mock(ComponentGraph.class)); + index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder, mock(ScanGraph.class)); Project project = new Project("project"); ResourceFilter filter = new ResourceFilter() { 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 deleted file mode 100644 index ff28e3a7c72..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/component/ComponentGraph.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 wrap(Element element, Class wrapperClass) { - return wrapperCache.wrap(element, wrapperClass, this); - } - - public T wrap(Component component, Class wrapperClass) { - Vertex vertex = GraphUtil.single(graph.getVertices("key", component.getKey())); - T wrapper = wrapperCache.wrap(vertex, wrapperClass, this); - return wrapper; - } - - public > T createVertex(ElementWrapper from, Class 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 createVertex(Class classWrapper) { - Vertex vertex = graph.addVertex(null); - return wrapperCache.wrap(vertex, classWrapper, this); - } - - public > ComponentWrapper 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/ComponentVertex.java b/sonar-core/src/main/java/org/sonar/core/component/ComponentVertex.java new file mode 100644 index 00000000000..351b3973491 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/component/ComponentVertex.java @@ -0,0 +1,28 @@ +package org.sonar.core.component; + +import org.sonar.api.component.Component; +import org.sonar.core.graph.BeanVertex; + +public class ComponentVertex extends BeanVertex implements Component { + + public String key() { + return (String) getProperty("key"); + } + + public String name() { + return (String) getProperty("name"); + } + + public String qualifier() { + return (String) getProperty("qualifier"); + } + + void copyFrom(Component component) { + setProperty("key", component.key()); + setProperty("name", component.name()); + setProperty("qualifier", component.qualifier()); + if (component instanceof ResourceComponent) { + setProperty("sid", ((ResourceComponent) component).snapshotId()); + } + } +} 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 deleted file mode 100644 index cdd7599bcbb..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/component/ComponentWrapper.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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> extends ElementWrapper implements Component { - - 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/PerspectiveBuilder.java b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java index 4c110c1be96..feef7ac8dfa 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java +++ b/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilder.java @@ -23,20 +23,29 @@ import org.sonar.api.BatchComponent; import org.sonar.api.ServerComponent; import org.sonar.api.component.Perspective; +import javax.annotation.CheckForNull; + public abstract class PerspectiveBuilder implements BatchComponent, ServerComponent { + private final String perspectiveKey; private final Class perspectiveClass; - protected PerspectiveBuilder(Class perspectiveClass) { + protected PerspectiveBuilder(String perspectiveKey, Class perspectiveClass) { + this.perspectiveKey = perspectiveKey; this.perspectiveClass = perspectiveClass; } + protected String getPerspectiveKey() { + return perspectiveKey; + } + protected Class getPerspectiveClass() { return perspectiveClass; } - public abstract T load(ComponentWrapper componentWrapper); + @CheckForNull + public abstract T load(ComponentVertex component); - public abstract T create(ComponentWrapper componentWrapper); + public abstract T create(ComponentVertex component); } 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 deleted file mode 100644 index c303226de0d..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveLoaders.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.Maps; -import org.sonar.api.ServerComponent; -import org.sonar.api.component.Perspective; -import org.sonar.api.test.MutableTestPlan; -import org.sonar.api.test.MutableTestable; -import org.sonar.core.graph.GraphDao; -import org.sonar.core.graph.GraphDto; - -import javax.annotation.CheckForNull; - -import java.util.Map; - -public class PerspectiveLoaders implements ServerComponent { - - private final GraphDao dao; - private Map, PerspectiveBuilder> builders = Maps.newHashMap(); - - public PerspectiveLoaders(GraphDao dao, PerspectiveBuilder[] builders) { - this.dao = dao; - for (PerspectiveBuilder builder : builders) { - // TODO check duplications - this.builders.put(builder.getPerspectiveClass(), builder); - } - } - - @CheckForNull - public Perspective as(String componentKey, String perspectiveKey) { - GraphDto graphDto = dao.selectByComponent(perspectiveKey, componentKey); - return doAs(perspectiveKey, graphDto); - } - - @CheckForNull - public Perspective as(long snapshotId, String perspectiveKey) { - GraphDto graphDto = dao.selectBySnapshot(perspectiveKey, snapshotId); - return doAs(perspectiveKey, graphDto); - } - - private Perspective doAs(String perspectiveKey, GraphDto graphDto) { - Perspective result = null; - if (graphDto != null) { - ComponentGraph graph = new GraphReader().read(graphDto.getData(), graphDto.getRootVertexId()); - ComponentWrapper componentWrapper = graph.wrap(graph.getRootVertex(), ComponentWrapper.class); - if (perspectiveKey.equals("testplan")) { - result = builders.get(MutableTestPlan.class).load(componentWrapper); - } else if (perspectiveKey.equals("testable")) { - result = builders.get(MutableTestable.class).load(componentWrapper); - } - } - return result; - } -} 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 index 413de496bc7..c200a5bf4a4 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ResourceComponent.java @@ -35,7 +35,7 @@ class ResourceComponent implements Component { this.key = resource.getEffectiveKey(); this.name = resource.getName(); this.qualifier = resource.getQualifier(); - if (snapshot!=null && snapshot.getId()!=null) { + if (snapshot != null && snapshot.getId() != null) { this.snapshotId = snapshot.getId().longValue(); } } @@ -44,19 +44,19 @@ class ResourceComponent implements Component { this(resource, null); } - public String getKey() { + public String key() { return key; } - public String getName() { + public String name() { return name; } - public String getQualifier() { + public String qualifier() { return qualifier; } - public Long getSnapshotId() { + public Long snapshotId() { return snapshotId; } } \ No newline at end of file diff --git a/sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java b/sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java new file mode 100644 index 00000000000..27328de9fc9 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/component/ScanGraph.java @@ -0,0 +1,77 @@ +/* + * 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.Graph; +import com.tinkerpop.blueprints.Vertex; +import com.tinkerpop.blueprints.impls.tg.TinkerGraph; +import org.sonar.api.BatchComponent; +import org.sonar.api.component.Component; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.resources.Resource; +import org.sonar.core.graph.BeanGraph; +import org.sonar.core.graph.BeanIterable; +import org.sonar.core.graph.GraphUtil; + +import javax.annotation.Nullable; + +public class ScanGraph extends BeanGraph implements BatchComponent { + + private final Vertex componentsRoot; + + private ScanGraph(Graph graph) { + super(graph); + componentsRoot = graph.addVertex(null); + componentsRoot.setProperty("root", "components"); + } + + public static ScanGraph create() { + TinkerGraph graph = new TinkerGraph(); + graph.createKeyIndex("key", Vertex.class); + return new ScanGraph(graph); + } + + public ComponentVertex wrapComponent(Vertex vertex) { + return wrap(vertex, ComponentVertex.class); + } + + public ComponentVertex getComponent(String key) { + Vertex vertex = GraphUtil.single(getUnderlyingGraph().getVertices("key", key)); + return (vertex != null ? wrapComponent(vertex) : null); + } + + public ComponentVertex addComponent(Resource resource, @Nullable Snapshot snapshot) { + return addComponent(new ResourceComponent(resource, snapshot)); + } + + public Iterable getComponents() { + Iterable componentVertices = componentsRoot.getVertices(Direction.OUT, "component"); + return new BeanIterable(this, ComponentVertex.class, componentVertices); + } + + public ComponentVertex addComponent(Component component) { + Vertex vertex = getUnderlyingGraph().addVertex(null); + getUnderlyingGraph().addEdge(null, componentsRoot, vertex, "component"); + ComponentVertex wrapper = wrap(vertex, ComponentVertex.class); + wrapper.copyFrom(component); + return wrapper; + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/component/GraphStorage.java b/sonar-core/src/main/java/org/sonar/core/component/ScanGraphStore.java similarity index 54% rename from sonar-core/src/main/java/org/sonar/core/component/GraphStorage.java rename to sonar-core/src/main/java/org/sonar/core/component/ScanGraphStore.java index 8789066eac7..0af38668cab 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/GraphStorage.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ScanGraphStore.java @@ -19,40 +19,51 @@ */ 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.api.component.Perspective; import org.sonar.core.graph.GraphWriter; +import org.sonar.core.graph.jdbc.GraphDto; +import org.sonar.core.graph.jdbc.GraphDtoMapper; import org.sonar.core.persistence.BatchSession; import org.sonar.core.persistence.MyBatis; -public class GraphStorage { +public class ScanGraphStore { private final MyBatis myBatis; - private final ComponentGraph componentGraph; + private final ScanGraph projectGraph; + private final PerspectiveBuilder[] builders; - public GraphStorage(MyBatis myBatis, ComponentGraph componentGraph) { + public ScanGraphStore(MyBatis myBatis, ScanGraph projectGraph, PerspectiveBuilder[] builders) { this.myBatis = myBatis; - this.componentGraph = componentGraph; + this.projectGraph = projectGraph; + this.builders = builders; } public void save() { - LoggerFactory.getLogger(GraphStorage.class).info("Persisting graphs of components"); + LoggerFactory.getLogger(ScanGraphStore.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"); + for (ComponentVertex component : projectGraph.getComponents()) { + Long snapshotId = (Long) component.element().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(); + for (PerspectiveBuilder builder : builders) { + Perspective perspective = builder.load(component); + if (perspective != null) { + String data = writer.write(projectGraph.getUnderlyingGraph()); + mapper.insert(new GraphDto() + .setData(data) + .setFormat("graphson") + .setPerspective(builder.getPerspectiveKey()) + .setVersion(1) + .setSnapshotId(snapshotId) + .setRootVertexId(component.element().getId().toString()) + ); + subGraph.clear(); + } + } } } session.commit(); diff --git a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilders.java b/sonar-core/src/main/java/org/sonar/core/component/ScanPerspectives.java similarity index 55% rename from sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilders.java rename to sonar-core/src/main/java/org/sonar/core/component/ScanPerspectives.java index aff9e1852d9..c9dc3368c52 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/PerspectiveBuilders.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ScanPerspectives.java @@ -19,28 +19,24 @@ */ 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, PerspectiveBuilder> builders = Maps.newHashMap(); - private final Map, Perspective>> components = new MapMaker().weakValues().makeMap(); +public class ScanPerspectives implements ResourcePerspectives, BatchComponent { + private final ScanGraph graph; + private final Map, PerspectiveBuilder> builders = Maps.newHashMap(); private final SonarIndex resourceIndex; - public PerspectiveBuilders(ComponentGraph graph, PerspectiveBuilder[] builders, SonarIndex resourceIndex) { + public ScanPerspectives(ScanGraph graph, PerspectiveBuilder[] builders, SonarIndex resourceIndex) { this.graph = graph; this.resourceIndex = resourceIndex; for (PerspectiveBuilder builder : builders) { @@ -50,37 +46,38 @@ public class PerspectiveBuilders implements ResourcePerspectives, BatchComponent } @CheckForNull - public

P as(Component component, Class

toClass) { - if (component.getKey() == null) { + public

P as(Class

perspectiveClass, Component component) { + if (component.key() == null) { return null; } - Map, Perspective> perspectives = components.get(component); - if (perspectives == null) { - perspectives = Maps.newHashMap(); - components.put(component, perspectives); + + ComponentVertex vertex; + if (component instanceof ComponentVertex) { + vertex = (ComponentVertex) component; + } else { + vertex = graph.getComponent(component.key()); } - P perspective = (P) perspectives.get(toClass); - if (perspective == null) { - ComponentWrapper componentWrapper = graph.wrap(component, ComponentWrapper.class); - PerspectiveBuilder

perspectiveBuilder = builderFor(toClass); - perspective = perspectiveBuilder.load(componentWrapper); + + if (vertex != null) { + PerspectiveBuilder

builder = builderFor(perspectiveClass); + P perspective = builder.load(vertex); if (perspective == null) { - perspective = perspectiveBuilder.create(componentWrapper); + perspective = builder.create(vertex); } - perspectives.put((Class) toClass, perspective); + return perspective; } - return perspective; + return null; } - public

P as(Resource resource, Class

toClass) { + public

P as(Class

perspectiveClass, Resource resource) { Resource indexedResource = resourceIndex.getResource(resource); if (indexedResource != null) { - return as(new ResourceComponent(indexedResource), toClass); + return as(perspectiveClass, new ResourceComponent(indexedResource)); } return null; } - PerspectiveBuilder builderFor(Class clazz) { + private PerspectiveBuilder builderFor(Class clazz) { PerspectiveBuilder builder = (PerspectiveBuilder) builders.get(clazz); if (builder == null) { throw new PerspectiveNotFoundException("Perspective class is not registered: " + clazz); diff --git a/sonar-core/src/main/java/org/sonar/core/component/TransientGraph.java b/sonar-core/src/main/java/org/sonar/core/component/SnapshotGraph.java similarity index 76% rename from sonar-core/src/main/java/org/sonar/core/component/TransientGraph.java rename to sonar-core/src/main/java/org/sonar/core/component/SnapshotGraph.java index 739f86555fa..a99cd30ec2b 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/TransientGraph.java +++ b/sonar-core/src/main/java/org/sonar/core/component/SnapshotGraph.java @@ -21,21 +21,17 @@ package org.sonar.core.component; import com.tinkerpop.blueprints.Graph; import com.tinkerpop.blueprints.Vertex; -import com.tinkerpop.blueprints.impls.tg.TinkerGraph; +import org.sonar.core.graph.BeanGraph; -public class TransientGraph { - private Graph graph; - private Vertex root; +class SnapshotGraph extends BeanGraph { + private final Vertex componentRoot; - public TransientGraph() { - this.graph = new TinkerGraph(); + SnapshotGraph(Graph graph, String rootVertexId) { + super(graph); + componentRoot = graph.getVertex(rootVertexId); } - public Vertex getRootVertex() { - return root; - } - - public Graph getUnderlyingGraph() { - return graph; + Vertex getComponentRoot() { + return componentRoot; } } diff --git a/sonar-core/src/main/java/org/sonar/core/component/SnapshotPerspectives.java b/sonar-core/src/main/java/org/sonar/core/component/SnapshotPerspectives.java new file mode 100644 index 00000000000..b226a429d92 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/component/SnapshotPerspectives.java @@ -0,0 +1,87 @@ +/* + * 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.Maps; +import com.tinkerpop.blueprints.impls.tg.TinkerGraph; +import org.sonar.api.ServerComponent; +import org.sonar.api.component.Perspective; +import org.sonar.core.graph.graphson.GraphsonReader; +import org.sonar.core.graph.jdbc.GraphDao; +import org.sonar.core.graph.jdbc.GraphDto; + +import javax.annotation.CheckForNull; + +import java.io.ByteArrayInputStream; +import java.util.Map; + +public class SnapshotPerspectives implements ServerComponent { + + private final GraphDao dao; + private final Map, PerspectiveBuilder> builders = Maps.newHashMap(); + + public SnapshotPerspectives(GraphDao dao, PerspectiveBuilder[] builders) { + this.dao = dao; + for (PerspectiveBuilder builder : builders) { + // TODO check duplications + this.builders.put(builder.getPerspectiveClass(), builder); + } + } + + @CheckForNull + public T as(Class perspectiveClass, String componentKey) { + PerspectiveBuilder builder = (PerspectiveBuilder) builders.get(perspectiveClass); + if (builder == null) { + throw new IllegalStateException(); + } + GraphDto graphDto = dao.selectByComponent(builder.getPerspectiveKey(), componentKey); + return doAs(builder, graphDto); + } + + @CheckForNull + public T as(Class perspectiveClass, long snapshotId) { + PerspectiveBuilder builder = (PerspectiveBuilder) builders.get(perspectiveClass); + if (builder == null) { + throw new IllegalStateException(); + } + GraphDto graphDto = dao.selectBySnapshot(builder.getPerspectiveKey(), snapshotId); + return doAs(builder, graphDto); + } + + private T doAs(PerspectiveBuilder builder, GraphDto graphDto) { + T result = null; + if (graphDto != null) { + SnapshotGraph graph = read(graphDto.getData(), graphDto.getRootVertexId()); + result = builder.load(graph.wrap(graph.getComponentRoot(), ComponentVertex.class)); + } + return result; + } + + private SnapshotGraph read(String data, String rootVertexId) { + ByteArrayInputStream input = new ByteArrayInputStream(data.getBytes()); + try { + TinkerGraph graph = new TinkerGraph(); + new GraphsonReader().read(input, graph); + return new SnapshotGraph(graph, rootVertexId); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/component/ElementWrapper.java b/sonar-core/src/main/java/org/sonar/core/graph/BeanEdge.java similarity index 64% rename from sonar-core/src/main/java/org/sonar/core/component/ElementWrapper.java rename to sonar-core/src/main/java/org/sonar/core/graph/BeanEdge.java index a53b3226087..f35e3b00ec1 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ElementWrapper.java +++ b/sonar-core/src/main/java/org/sonar/core/graph/BeanEdge.java @@ -17,31 +17,15 @@ * 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; +package org.sonar.core.graph; -import com.tinkerpop.blueprints.Element; +import com.tinkerpop.blueprints.Direction; +import com.tinkerpop.blueprints.Edge; -/** - * Wrap a Blueprints vertex or edge. - */ -public abstract class ElementWrapper { - - private T element; - private ComponentGraph graph; - - public T element() { - return element; - } +public abstract class BeanEdge extends BeanElement { - void setElement(T element) { - this.element = element; + protected final T getVertex(Class vertexClass, Direction direction) throws IllegalArgumentException { + return beanGraph().wrap(element().getVertex(direction), vertexClass); } - public ComponentGraph graph() { - return graph; - } - - void setGraph(ComponentGraph graph) { - this.graph = graph; - } } diff --git a/sonar-core/src/main/java/org/sonar/core/graph/BeanElement.java b/sonar-core/src/main/java/org/sonar/core/graph/BeanElement.java new file mode 100644 index 00000000000..d7ec50a76e7 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/graph/BeanElement.java @@ -0,0 +1,68 @@ +/* + * 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.Element; + +import javax.annotation.Nullable; + +import java.util.Set; + +public abstract class BeanElement> { + private T element; + private BeanGraph graph; + + public T element() { + return element; + } + + void setElement(T element) { + this.element = element; + } + + public BeanGraph beanGraph() { + return graph; + } + + void setBeanGraph(BeanGraph graph) { + this.graph = graph; + } + + protected final Object getProperty(String key) { + return element.getProperty(key); + } + + protected final Set getPropertyKeys() { + return element.getPropertyKeys(); + } + + protected final C setProperty(String key, @Nullable Object value) { + if (value != null) { + element.setProperty(key, value); + } else { + element.removeProperty(key); + } + return (C) this; + } + + protected final Object removeProperty(String key) { + return element.removeProperty(key); + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/component/ElementWrappers.java b/sonar-core/src/main/java/org/sonar/core/graph/BeanElements.java similarity index 60% rename from sonar-core/src/main/java/org/sonar/core/component/ElementWrappers.java rename to sonar-core/src/main/java/org/sonar/core/graph/BeanElements.java index 17496c51d56..2ba76ed860b 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ElementWrappers.java +++ b/sonar-core/src/main/java/org/sonar/core/graph/BeanElements.java @@ -17,56 +17,50 @@ * 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; +package org.sonar.core.graph; import com.google.common.collect.MapMaker; import com.tinkerpop.blueprints.Element; import java.util.Map; -public class ElementWrappers { +class BeanElements { + private final Map cache; - private final Map cache; - - public ElementWrappers() { + BeanElements() { cache = new MapMaker().weakValues().makeMap(); } - public void clear() { - cache.clear(); - } - - public T wrap(Element element, Class wrapperClass, ComponentGraph graph) { - ElementKey key = new ElementKey(element, wrapperClass); - T wrapper = (T) cache.get(key); - if (wrapper == null) { + T wrap(Element element, Class beanClass, BeanGraph graph) { + ElementKey key = new ElementKey(element, beanClass); + T bean = (T) cache.get(key); + if (bean == null) { try { - wrapper = (T)key.wrapperClass.newInstance(); - wrapper.setElement(key.element); - wrapper.setGraph(graph); - cache.put(key, wrapper); + bean = (T) key.beanClass.newInstance(); + bean.setElement(key.element); + bean.setBeanGraph(graph); + cache.put(key, bean); } catch (InstantiationException e) { - throw new IllegalStateException("Class has no default constructor: " + wrapperClass, e); + throw new IllegalStateException("Class has no default constructor: " + beanClass.getName(), e); } catch (IllegalAccessException e) { - throw new IllegalStateException("Can not access to default constructor: " + wrapperClass, e); + throw new IllegalStateException("Can not access to default constructor: " + beanClass.getName(), e); } } - return wrapper; + return bean; } - public ElementWrappers remove(Element elt, Class wrapperClass) { - cache.remove(new ElementKey(elt, wrapperClass)); - return this; + void clear() { + cache.clear(); } private static class ElementKey { Element element; - Class wrapperClass; + Class beanClass; - ElementKey(Element element, Class wrapperClass) { + ElementKey(Element element, Class beanClass) { this.element = element; - this.wrapperClass = wrapperClass; + this.beanClass = beanClass; } @Override @@ -74,21 +68,20 @@ public class ElementWrappers { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (o == null) { return false; } - ElementKey that = (ElementKey) o; if (!element.equals(that.element)) { return false; } - return wrapperClass.equals(that.wrapperClass); + return beanClass.equals(that.beanClass); } @Override public int hashCode() { int result = element.hashCode(); - result = 31 * result + wrapperClass.hashCode(); + result = 31 * result + beanClass.hashCode(); return result; } } diff --git a/sonar-core/src/main/java/org/sonar/core/graph/BeanGraph.java b/sonar-core/src/main/java/org/sonar/core/graph/BeanGraph.java new file mode 100644 index 00000000000..2cbbc1a3c2b --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/graph/BeanGraph.java @@ -0,0 +1,56 @@ +/* + * 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.Edge; +import com.tinkerpop.blueprints.Element; +import com.tinkerpop.blueprints.Graph; +import com.tinkerpop.blueprints.Vertex; +import com.tinkerpop.blueprints.util.ElementHelper; + +public class BeanGraph { + private final Graph graph; + private final BeanElements beans; + + public BeanGraph(Graph graph) { + this.graph = graph; + this.beans = new BeanElements(); + } + + public final T wrap(Element element, Class beanClass) { + return beans.wrap(element, beanClass, this); + } + + public final T createAdjacentVertex(BeanVertex from, Class beanClass, String edgeLabel, String... edgeProperties) { + T to = createVertex(beanClass); + Edge edge = graph.addEdge(null, from.element(), to.element(), edgeLabel); + ElementHelper.setProperties(edge, edgeProperties); + return to; + } + + public final T createVertex(Class beanClass) { + Vertex vertex = graph.addVertex(null); + return beans.wrap(vertex, beanClass, this); + } + + public final Graph getUnderlyingGraph() { + return graph; + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/graph/BeanIterable.java b/sonar-core/src/main/java/org/sonar/core/graph/BeanIterable.java new file mode 100644 index 00000000000..f23838be48a --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/graph/BeanIterable.java @@ -0,0 +1,55 @@ +/* + * 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.Element; + +import java.util.Iterator; + +public class BeanIterable implements Iterable { + + private final Iterable iterable; + private final BeanGraph graph; + private final Class beanClass; + + public BeanIterable(BeanGraph graph, Class beanClass, Iterable iterable) { + this.iterable = iterable; + this.graph = graph; + this.beanClass = beanClass; + } + + public Iterator iterator() { + return new Iterator() { + private final Iterator iterator = iterable.iterator(); + + public void remove() { + throw new UnsupportedOperationException(); + } + + public boolean hasNext() { + return this.iterator.hasNext(); + } + + public T next() { + return graph.wrap(this.iterator.next(), beanClass); + } + }; + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/component/GraphReader.java b/sonar-core/src/main/java/org/sonar/core/graph/BeanVertex.java similarity index 59% rename from sonar-core/src/main/java/org/sonar/core/component/GraphReader.java rename to sonar-core/src/main/java/org/sonar/core/graph/BeanVertex.java index 3062979c2a6..bd6d6156cd8 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/GraphReader.java +++ b/sonar-core/src/main/java/org/sonar/core/graph/BeanVertex.java @@ -17,25 +17,18 @@ * 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; +package org.sonar.core.graph; +import com.tinkerpop.blueprints.Direction; import com.tinkerpop.blueprints.Vertex; -import com.tinkerpop.blueprints.impls.tg.TinkerGraph; -import org.sonar.core.graph.graphson.GraphsonReader; -import java.io.ByteArrayInputStream; +public abstract class BeanVertex extends BeanElement { -public class GraphReader { + protected final Iterable getEdges(Class edgeClass, Direction direction, String... labels) { + return new BeanIterable(beanGraph(), edgeClass, element().getEdges(direction, labels)); + } - public ComponentGraph read(String data, String rootVertexId) { - ByteArrayInputStream input = new ByteArrayInputStream(data.getBytes()); - try { - TinkerGraph graph = new TinkerGraph(); - new GraphsonReader().read(input, graph); - Vertex root = graph.getVertex(rootVertexId); - return new ComponentGraph(graph, root); - } catch (Exception e) { - throw new IllegalStateException(e); - } + protected final Iterable getVertices(Class vertexClass, Direction direction, String... labels) { + return new BeanIterable(beanGraph(), vertexClass, element().getVertices(direction, labels)); } } diff --git a/sonar-core/src/main/java/org/sonar/core/graph/GraphDao.java b/sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDao.java similarity index 98% rename from sonar-core/src/main/java/org/sonar/core/graph/GraphDao.java rename to sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDao.java index cbf357f7ff3..9d39fd55f78 100644 --- a/sonar-core/src/main/java/org/sonar/core/graph/GraphDao.java +++ b/sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDao.java @@ -17,7 +17,7 @@ * 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; +package org.sonar.core.graph.jdbc; import org.apache.ibatis.session.SqlSession; import org.sonar.core.persistence.MyBatis; diff --git a/sonar-core/src/main/java/org/sonar/core/graph/GraphDto.java b/sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDto.java similarity index 98% rename from sonar-core/src/main/java/org/sonar/core/graph/GraphDto.java rename to sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDto.java index 7f06ece92a8..64ae196f765 100644 --- a/sonar-core/src/main/java/org/sonar/core/graph/GraphDto.java +++ b/sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDto.java @@ -17,7 +17,7 @@ * 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; +package org.sonar.core.graph.jdbc; public class GraphDto { private long id; diff --git a/sonar-core/src/main/java/org/sonar/core/graph/GraphDtoMapper.java b/sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDtoMapper.java similarity index 97% rename from sonar-core/src/main/java/org/sonar/core/graph/GraphDtoMapper.java rename to sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDtoMapper.java index 96f28c8bc52..33e3396b145 100644 --- a/sonar-core/src/main/java/org/sonar/core/graph/GraphDtoMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/graph/jdbc/GraphDtoMapper.java @@ -17,7 +17,7 @@ * 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; +package org.sonar.core.graph.jdbc; import org.apache.ibatis.annotations.Param; diff --git a/sonar-core/src/main/java/org/sonar/core/graph/jdbc/package-info.java b/sonar-core/src/main/java/org/sonar/core/graph/jdbc/package-info.java new file mode 100644 index 00000000000..250c0998a7e --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/graph/jdbc/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.jdbc; + +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 9d550066d2b..0c875048316 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,7 +20,7 @@ package org.sonar.core.persistence; import com.google.common.collect.ImmutableList; -import org.sonar.core.graph.GraphDao; +import org.sonar.core.graph.jdbc.GraphDao; import org.sonar.core.dashboard.ActiveDashboardDao; import org.sonar.core.dashboard.DashboardDao; import org.sonar.core.duplication.DuplicationDao; 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 2ec68c4fdb1..7fd1793971a 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,8 +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.graph.jdbc.GraphDto; +import org.sonar.core.graph.jdbc.GraphDtoMapper; import org.sonar.core.config.Logback; import org.sonar.core.dashboard.ActiveDashboardDto; import org.sonar.core.dashboard.ActiveDashboardMapper; diff --git a/sonar-core/src/main/java/org/sonar/core/test/DefaultTestCase.java b/sonar-core/src/main/java/org/sonar/core/test/DefaultTestCase.java index 6a15a79e223..1c4a8c1ebcf 100644 --- a/sonar-core/src/main/java/org/sonar/core/test/DefaultTestCase.java +++ b/sonar-core/src/main/java/org/sonar/core/test/DefaultTestCase.java @@ -26,35 +26,36 @@ import org.sonar.api.test.CoveredTestable; import org.sonar.api.test.MutableTestCase; import org.sonar.api.test.TestPlan; import org.sonar.api.test.Testable; -import org.sonar.core.component.ElementWrapper; +import org.sonar.core.graph.BeanVertex; import org.sonar.core.graph.GraphUtil; import javax.annotation.Nullable; import java.util.Collection; +import java.util.Set; -public class DefaultTestCase extends ElementWrapper implements MutableTestCase { +public class DefaultTestCase extends BeanVertex implements MutableTestCase { public String type() { - return (String) element().getProperty("type"); + return (String) getProperty("type"); } public Long durationInMs() { - return (Long) element().getProperty("duration"); + return (Long) getProperty("duration"); } public MutableTestCase setDurationInMs(@Nullable Long l) { - Preconditions.checkArgument(l==null || l >=0, String.format("Duration must be positive (got %d)", l)); - element().setProperty("duration", l); + Preconditions.checkArgument(l == null || l >= 0, String.format("Duration must be positive (got %d)", l)); + setProperty("duration", l); return this; } public String status() { - return (String) element().getProperty("status"); + return (String) getProperty("status"); } public MutableTestCase setStatus(@Nullable String s) { - element().setProperty("status", s); + setProperty("status", s); return this; } @@ -62,48 +63,48 @@ public class DefaultTestCase extends ElementWrapper implements MutableTe * The key is not blank and unique among the test plan. */ public String key() { - return (String) element().getProperty("key"); + return (String) getProperty("key"); } public MutableTestCase setKey(String s) { - element().setProperty("key", s); + setProperty("key", s); return this; } public String name() { - return (String) element().getProperty("name"); + return (String) getProperty("name"); } public MutableTestCase setName(String s) { - element().setProperty("name", s); + setProperty("name", s); return this; } public String message() { - return (String) element().getProperty("message"); + return (String) getProperty("message"); } public MutableTestCase setMessage(String s) { - element().setProperty("message", s); + setProperty("message", s); return this; } public String stackTrace() { - return (String) element().getProperty("stackTrace"); + return (String) getProperty("stackTrace"); } public MutableTestCase setStackTrace(String s) { - element().setProperty("stackTrace", s); + setProperty("stackTrace", s); return this; } - public void covers(Testable component, Collection lines) { + public void covers(Testable testable, Set lines) { } public TestPlan testPlan() { Vertex plan = GraphUtil.singleAdjacent(element(), Direction.IN, "testcase"); - return graph().wrap(plan, DefaultTestPlan.class); + return beanGraph().wrap(plan, DefaultTestPlan.class); } public Collection coveredBlocks() { diff --git a/sonar-core/src/main/java/org/sonar/core/test/DefaultTestPlan.java b/sonar-core/src/main/java/org/sonar/core/test/DefaultTestPlan.java index 536a90ade35..b3975902df1 100644 --- a/sonar-core/src/main/java/org/sonar/core/test/DefaultTestPlan.java +++ b/sonar-core/src/main/java/org/sonar/core/test/DefaultTestPlan.java @@ -25,26 +25,28 @@ import com.tinkerpop.blueprints.Vertex; import org.sonar.api.component.Component; import org.sonar.api.test.MutableTestCase; import org.sonar.api.test.MutableTestPlan; -import org.sonar.core.component.ComponentWrapper; -import org.sonar.core.component.ElementWrapper; +import org.sonar.core.component.ComponentVertex; +import org.sonar.core.graph.BeanVertex; import org.sonar.core.graph.GraphUtil; import java.util.List; -public class DefaultTestPlan extends ElementWrapper implements MutableTestPlan { +public class DefaultTestPlan extends BeanVertex implements MutableTestPlan { public Component component() { Vertex component = GraphUtil.singleAdjacent(element(), Direction.IN, "testplan"); - return graph().wrap(component, ComponentWrapper.class); + return beanGraph().wrap(component, ComponentVertex.class); } public MutableTestCase addTestCase(String key) { - return graph().createVertex(this, DefaultTestCase.class, "testcase").setKey(key); + DefaultTestCase testCase = beanGraph().createAdjacentVertex(this, DefaultTestCase.class, "testcase"); + testCase.setKey(key); + return testCase; } public List testCases() { List testCases = Lists.newArrayList(); for (Vertex testCaseVertex : element().getVertices(Direction.OUT, "testcase")) { - testCases.add(graph().wrap(testCaseVertex, DefaultTestCase.class)); + testCases.add(beanGraph().wrap(testCaseVertex, DefaultTestCase.class)); } return testCases; } diff --git a/sonar-core/src/main/java/org/sonar/core/test/DefaultTestable.java b/sonar-core/src/main/java/org/sonar/core/test/DefaultTestable.java index 521a21050c3..dc46198fff1 100644 --- a/sonar-core/src/main/java/org/sonar/core/test/DefaultTestable.java +++ b/sonar-core/src/main/java/org/sonar/core/test/DefaultTestable.java @@ -24,18 +24,18 @@ import com.tinkerpop.blueprints.Vertex; import org.sonar.api.component.Component; import org.sonar.api.test.MutableTestable; import org.sonar.api.test.TestCase; -import org.sonar.core.component.ComponentWrapper; -import org.sonar.core.component.ElementWrapper; +import org.sonar.core.component.ComponentVertex; +import org.sonar.core.graph.BeanVertex; import org.sonar.core.graph.GraphUtil; import java.util.List; import java.util.SortedSet; -public class DefaultTestable extends ElementWrapper implements MutableTestable { +public class DefaultTestable extends BeanVertex implements MutableTestable { public Component component() { Vertex component = GraphUtil.singleAdjacent(element(), Direction.IN, "testable"); - return graph().wrap(component, ComponentWrapper.class); + return beanGraph().wrap(component, ComponentVertex.class); } public List coveringTestCases() { diff --git a/sonar-core/src/main/java/org/sonar/core/test/TestPlanBuilder.java b/sonar-core/src/main/java/org/sonar/core/test/TestPlanBuilder.java index 9318c2d4cb4..07a5d0e117e 100644 --- a/sonar-core/src/main/java/org/sonar/core/test/TestPlanBuilder.java +++ b/sonar-core/src/main/java/org/sonar/core/test/TestPlanBuilder.java @@ -22,27 +22,30 @@ package org.sonar.core.test; import com.tinkerpop.blueprints.Direction; import com.tinkerpop.blueprints.Vertex; import org.sonar.api.test.MutableTestPlan; -import org.sonar.core.component.ComponentWrapper; +import org.sonar.api.test.TestPlan; +import org.sonar.core.component.ComponentVertex; import org.sonar.core.component.PerspectiveBuilder; import org.sonar.core.graph.GraphUtil; public class TestPlanBuilder extends PerspectiveBuilder { + static final String PERSPECTIVE_KEY = "testplan"; + public TestPlanBuilder() { - super(MutableTestPlan.class); + super(PERSPECTIVE_KEY, MutableTestPlan.class); } @Override - public MutableTestPlan load(ComponentWrapper componentWrapper) { - Vertex planVertex = GraphUtil.singleAdjacent(componentWrapper.element(), Direction.OUT, "testplan"); + public MutableTestPlan load(ComponentVertex component) { + Vertex planVertex = GraphUtil.singleAdjacent(component.element(), Direction.OUT, PERSPECTIVE_KEY); if (planVertex != null) { - return componentWrapper.graph().wrap(planVertex, DefaultTestPlan.class); + return component.beanGraph().wrap(planVertex, DefaultTestPlan.class); } return null; } @Override - public MutableTestPlan create(ComponentWrapper componentWrapper) { - return componentWrapper.graph().createVertex(componentWrapper, DefaultTestPlan.class, "testplan"); + public MutableTestPlan create(ComponentVertex component) { + return component.beanGraph().createAdjacentVertex(component, DefaultTestPlan.class, PERSPECTIVE_KEY); } } diff --git a/sonar-core/src/main/java/org/sonar/core/test/TestableBuilder.java b/sonar-core/src/main/java/org/sonar/core/test/TestableBuilder.java index bf4785d543d..6954a0932ff 100644 --- a/sonar-core/src/main/java/org/sonar/core/test/TestableBuilder.java +++ b/sonar-core/src/main/java/org/sonar/core/test/TestableBuilder.java @@ -22,27 +22,29 @@ package org.sonar.core.test; import com.tinkerpop.blueprints.Direction; import com.tinkerpop.blueprints.Vertex; import org.sonar.api.test.MutableTestable; -import org.sonar.core.component.ComponentWrapper; +import org.sonar.core.component.ComponentVertex; import org.sonar.core.component.PerspectiveBuilder; import org.sonar.core.graph.GraphUtil; public class TestableBuilder extends PerspectiveBuilder { + static final String PERSPECTIVE_KEY = "testable"; + public TestableBuilder() { - super(MutableTestable.class); + super(PERSPECTIVE_KEY, MutableTestable.class); } @Override - public MutableTestable load(ComponentWrapper componentWrapper) { - Vertex perspectiveVertex = GraphUtil.singleAdjacent(componentWrapper.element(), Direction.OUT, "testable"); + public MutableTestable load(ComponentVertex component) { + Vertex perspectiveVertex = GraphUtil.singleAdjacent(component.element(), Direction.OUT, PERSPECTIVE_KEY); if (perspectiveVertex != null) { - return componentWrapper.graph().wrap(perspectiveVertex, DefaultTestable.class); + return component.beanGraph().wrap(perspectiveVertex, DefaultTestable.class); } return null; } @Override - public MutableTestable create(ComponentWrapper componentWrapper) { - return componentWrapper.graph().createVertex(componentWrapper, DefaultTestable.class, "testable"); + public MutableTestable create(ComponentVertex component) { + return component.beanGraph().createAdjacentVertex(component, DefaultTestable.class, PERSPECTIVE_KEY); } } diff --git a/sonar-core/src/main/resources/org/sonar/core/graph/GraphDtoMapper.xml b/sonar-core/src/main/resources/org/sonar/core/graph/jdbc/GraphDtoMapper.xml similarity index 96% rename from sonar-core/src/main/resources/org/sonar/core/graph/GraphDtoMapper.xml rename to sonar-core/src/main/resources/org/sonar/core/graph/jdbc/GraphDtoMapper.xml index d897ec76b06..81d9dec7327 100644 --- a/sonar-core/src/main/resources/org/sonar/core/graph/GraphDtoMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/graph/jdbc/GraphDtoMapper.xml @@ -1,7 +1,7 @@ - +