From: Simon Brandhof Date: Fri, 25 Jan 2013 13:03:52 +0000 (+0100) Subject: SONAR-4087 first draft of test api X-Git-Tag: 3.5~367 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=6200a323e1a2af7725ec9eb78dd9ca0902f3db38;p=sonarqube.git SONAR-4087 first draft of test api --- diff --git a/pom.xml b/pom.xml index 643aa644654..b45669c07c3 100644 --- a/pom.xml +++ b/pom.xml @@ -640,6 +640,16 @@ asm-all 3.2 + + com.tinkerpop.blueprints + blueprints-core + 2.2.0 + + + com.tinkerpop.gremlin + gremlin-java + 2.2.0 + org.codehaus.plexus plexus-classworlds 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 @@ - 54000000 + + 55000000 52000000 ${project.build.directory}/sonar-${project.version}.zip 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> 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 @@ - + 4.0.0 @@ -64,6 +65,14 @@ com.googlecode.json-simple json-simple + + com.tinkerpop.blueprints + blueprints-core + + + com.tinkerpop.gremlin + gremlin-java + 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 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/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> 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/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 { + + 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 cache; + + public ElementWrappers() { + 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) { + 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 wrapperClass; + + ElementKey(Element element, Class 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 implements BatchComponent, ServerComponent { + + private final Class perspectiveClass; + + protected PerspectiveBuilder(Class perspectiveClass) { + this.perspectiveClass = perspectiveClass; + } + + protected Class 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, PerspectiveBuilder> builders = Maps.newHashMap(); + private final Map, 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 as(Component component, Class

toClass) { + if (component.getKey() == null) { + return null; + } + Map, 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 as(Resource resource, Class

toClass) { + Resource indexedResource = resourceIndex.getResource(resource); + if (indexedResource != null) { + return as(new ResourceComponent(indexedResource), toClass); + } + return null; + } + + PerspectiveBuilder builderFor(Class clazz) { + PerspectiveBuilder builder = (PerspectiveBuilder) 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 as(String componentKey, String perspectiveKey) { + GraphDto graphDto = dao.selectByComponent(perspectiveKey, componentKey); + return doAs(perspectiveKey, graphDto); + } + + @CheckForNull + T as(long snapshotId, String perspectiveKey) { + GraphDto graphDto = dao.selectBySnapshot(perspectiveKey, snapshotId); + return doAs(perspectiveKey, graphDto); + } + + private 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 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 single(Iterable iterable) { + Iterator 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 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 @@ + + + + + + + + + + + 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) + + + + + + select graphs_seq.NEXTVAL from DUAL + + 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) + + + 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 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, 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 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 extends Perspective { + List 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 coveringTestCases(); + + List 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 ('')"