aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2015-06-24 16:16:10 +0200
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2015-06-26 15:10:27 +0200
commitd4c10655a1bba2681b4597deda42c61a8b7c5f99 (patch)
tree1384a26695b991f21344cc644e9f5bc998e0f966 /server
parent4b426779e1456df2ef94836f68245b55009757e5 (diff)
downloadsonarqube-d4c10655a1bba2681b4597deda42c61a8b7c5f99.tar.gz
sonarqube-d4c10655a1bba2681b4597deda42c61a8b7c5f99.zip
SONAR-6664 add PathAwareVisitor to visit a Component tree
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/PathAwareVisitor.java295
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputeIssueMeasuresStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateLoadingStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateMeasuresStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/component/PathAwareVisitorTest.java264
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/component/PostOrderDepthTraversalTypeAwareVisitorTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/component/PreOrderDepthTraversalTypeAwareVisitorTest.java2
18 files changed, 578 insertions, 19 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java
index 98e02828f48..5804e0b2b55 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentVisitor.java
@@ -21,4 +21,8 @@ package org.sonar.server.computation.component;
public interface ComponentVisitor {
void visit(Component tree);
+
+ enum Order {
+ PRE_ORDER, POST_ORDER
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java
index c43c9cbd4ee..7ff708046b5 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java
@@ -53,7 +53,7 @@ public abstract class DepthTraversalTypeAwareVisitor implements TypeAwareVisitor
}
}
- protected void visitNode(Component component) {
+ private void visitNode(Component component) {
visitAny(component);
switch (component.getType()) {
case PROJECT:
@@ -110,8 +110,4 @@ public abstract class DepthTraversalTypeAwareVisitor implements TypeAwareVisitor
public void visitAny(Component component) {
// empty implementation, meant to be override at will by subclasses
}
-
- public enum Order {
- PRE_ORDER, POST_ORDER
- }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/PathAwareVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/PathAwareVisitor.java
new file mode 100644
index 00000000000..b8114ca02cf
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/PathAwareVisitor.java
@@ -0,0 +1,295 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.computation.component;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
+
+/**
+ * A ComponentVisitor which provide access to a representation of the path from the root to the currently visited
+ * Component. It also provides a way to have an object associated to each Component and access it and all of its
+ * parent's.
+ * As for {@link DepthTraversalTypeAwareVisitor}, this visitor supports max depth visit and ordering.
+ */
+public abstract class PathAwareVisitor<T> implements ComponentVisitor {
+ private final Component.Type maxDepth;
+ private final Order order;
+ private final StackElementFactory<T> factory;
+ private final DequeBasedPath<T> stack = new DequeBasedPath<>();
+
+ public PathAwareVisitor(Component.Type maxDepth, Order order, StackElementFactory<T> factory) {
+ this.maxDepth = requireNonNull(maxDepth);
+ this.order = requireNonNull(order);
+ this.factory = requireNonNull(factory, "Factory can not be null");
+ }
+
+ @Override
+ public void visit(Component component) {
+ if (component.getType().isDeeperThan(maxDepth)) {
+ return;
+ }
+
+ stack.add(new PathElementImpl<>(component, createForComponent(component)));
+
+ if (order == PRE_ORDER) {
+ visitNode(component);
+ }
+
+ visitChildren(component);
+
+ if (order == POST_ORDER) {
+ visitNode(component);
+ }
+
+ stack.pop();
+ }
+
+ private T createForComponent(Component component) {
+ switch (component.getType()) {
+ case PROJECT:
+ return factory.createForProject(component);
+ case MODULE:
+ return factory.createForModule(component);
+ case DIRECTORY:
+ return factory.createForDirectory(component);
+ case FILE:
+ return factory.createForFile(component);
+ default:
+ return factory.createForUnknown(component);
+ }
+ }
+
+ private void visitChildren(Component component) {
+ if (component.getType() != maxDepth) {
+ for (Component child : component.getChildren()) {
+ visit(child);
+ }
+ }
+ }
+
+ private void visitNode(Component component) {
+ visitAny(component, stack);
+ switch (component.getType()) {
+ case PROJECT:
+ visitProject(component, stack);
+ break;
+ case MODULE:
+ visitModule(component, stack);
+ break;
+ case DIRECTORY:
+ visitDirectory(component, stack);
+ break;
+ case FILE:
+ visitFile(component, stack);
+ break;
+ default:
+ visitUnknown(component, stack);
+ }
+ }
+
+ protected void visitProject(Component project, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ protected void visitModule(Component module, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ protected void visitDirectory(Component directory, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ protected void visitFile(Component file, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ protected void visitUnknown(Component unknownComponent, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ protected void visitAny(Component component, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ public interface StackElementFactory<T> {
+ T createForProject(Component project);
+
+ T createForModule(Component module);
+
+ T createForDirectory(Component directory);
+
+ T createForFile(Component file);
+
+ T createForUnknown(Component file);
+ }
+
+ /**
+ * A Simple implementation which uses the same factory method for all types which can be implemented by subclasses:
+ * {@link #createForAny(Component)}.
+ */
+ public abstract static class SimpleStackElementFactory<T> implements StackElementFactory<T> {
+
+ public abstract T createForAny(Component component);
+
+ @Override
+ public T createForProject(Component project) {
+ return createForAny(project);
+ }
+
+ @Override
+ public T createForModule(Component module) {
+ return createForAny(module);
+ }
+
+ @Override
+ public T createForDirectory(Component directory) {
+ return createForAny(directory);
+ }
+
+ @Override
+ public T createForFile(Component file) {
+ return createForAny(file);
+ }
+
+ @Override
+ public T createForUnknown(Component file) {
+ return createForAny(file);
+ }
+ }
+
+ private static class DequeBasedPath<T> implements Path<T>, Iterable<PathElement<T>> {
+ private final Deque<PathElement<T>> deque = new ArrayDeque<>();
+
+ @Override
+ public T current() {
+ return deque.getFirst().getElement();
+ }
+
+ @Override
+ public T parent() {
+ Iterator<PathElement<T>> iterator = deque.iterator();
+ if (iterator.hasNext()) {
+ iterator.next();
+ if (iterator.hasNext()) {
+ return iterator.next().getElement();
+ }
+ }
+ throw new NoSuchElementException("Path is either empty or has only one element. There is no parent");
+ }
+
+ @Override
+ public boolean isRoot() {
+ return deque.size() == 1;
+ }
+
+ @Override
+ public T root() {
+ return deque.getLast().getElement();
+ }
+
+ @Override
+ public Iterator<PathElement<T>> iterator() {
+ return deque.iterator();
+ }
+
+ @Override
+ public Iterable<PathElement<T>> getCurrentPath() {
+ return this;
+ }
+
+ public void add(PathElement<T> pathElement) {
+ deque.addFirst(pathElement);
+ }
+
+ public PathElement<T> pop() {
+ return deque.pop();
+ }
+ }
+
+ public interface Path<T> {
+ /**
+ * The stacked element of the current Component.
+ */
+ T current();
+
+ /**
+ * Tells whether the current Component is the root of the tree.
+ */
+ boolean isRoot();
+
+ /**
+ * The stacked element of the parent of the current Component.
+ *
+ * @throws NoSuchElementException if the current Component is the root of the tree
+ * @see #isRoot()
+ */
+ T parent();
+
+ /**
+ * The stacked element of the root of the tree.
+ */
+ T root();
+
+ /**
+ * The path to the current Component as an Iterable of {@link PathAwareVisitor.PathElement} which starts with
+ * the {@link PathAwareVisitor.PathElement} of the current Component and ends with the
+ * {@link PathAwareVisitor.PathElement} of the root of the tree.
+ */
+ Iterable<PathElement<T>> getCurrentPath();
+ }
+
+ public interface PathElement<T> {
+ /**
+ * The Component on the path.
+ */
+ Component getComponent();
+
+ /**
+ * The stacked element for the Component of this PathElement.
+ */
+ T getElement();
+ }
+
+ private static final class PathElementImpl<T> implements PathElement<T> {
+ private final Component component;
+ private final T element;
+
+ private PathElementImpl(Component component, T element) {
+ this.component = component;
+ this.element = element;
+ }
+
+ @Override
+ public Component getComponent() {
+ return component;
+ }
+
+ @Override
+ public T getElement() {
+ return element;
+ }
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java
index fc0aee4129c..3aa32ff0c12 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java
@@ -23,7 +23,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
/**
* Holds the reference to the root of the {@link Component} tree for the current CE run.
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputeIssueMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputeIssueMeasuresStep.java
index 1fd30585f08..f7060ab065b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputeIssueMeasuresStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputeIssueMeasuresStep.java
@@ -69,7 +69,7 @@ import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES_KEY;
import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES_KEY;
import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY;
import static org.sonar.server.computation.component.Component.Type.FILE;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
/**
* Computes metrics related to number of issues.
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStep.java
index cf3e7ef1ca8..c41d928ac5d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStep.java
@@ -46,7 +46,7 @@ import org.sonar.server.computation.period.Period;
import org.sonar.server.computation.period.PeriodsHolder;
import org.sonar.server.db.DbClient;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
/**
* Set variations on all numeric measures found in the repository.
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
index 1baae898213..7e069c2dc5f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
@@ -36,7 +36,7 @@ import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
/**
* Persist duplications into
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java
index 523f4a3d608..8ab4833ba68 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java
@@ -49,7 +49,7 @@ import org.sonar.server.db.DbClient;
import org.sonar.server.source.db.FileSourceDb;
import org.sonar.server.util.CloseableIterator;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
public class PersistFileSourcesStep implements ComputationStep {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java
index 46a21ac6b90..a148c0ecb6a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java
@@ -44,7 +44,7 @@ import org.sonar.server.computation.metric.MetricRepository;
import org.sonar.server.db.DbClient;
import static com.google.common.collect.FluentIterable.from;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
public class PersistMeasuresStep implements ComputationStep {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java
index 2b3866ce742..da5a180b7fa 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java
@@ -39,7 +39,7 @@ import org.sonar.server.db.DbClient;
import org.sonar.server.source.index.SourceLineIndex;
import static com.google.common.base.Objects.firstNonNull;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java
index 949c73698de..64d5eff98b6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java
@@ -41,7 +41,7 @@ import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
import static com.google.common.collect.Sets.newHashSet;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
/**
* Persist project and module links
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateLoadingStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateLoadingStep.java
index 4cb2afa9154..22e4f9787bc 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateLoadingStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateLoadingStep.java
@@ -34,7 +34,7 @@ import org.sonar.server.computation.qualitygate.QualityGate;
import org.sonar.server.computation.qualitygate.QualityGateService;
import static org.sonar.server.computation.component.Component.Type.PROJECT;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
/**
* This step retrieves the QualityGate for the current {@link ReportQueue.Item} and stores it in
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateMeasuresStep.java
index 1ebbc1f3fb3..bc9406c721a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateMeasuresStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityGateMeasuresStep.java
@@ -44,7 +44,7 @@ import org.sonar.server.computation.qualitygate.QualityGate;
import org.sonar.server.computation.qualitygate.QualityGateHolder;
import static org.sonar.server.computation.component.Component.Type.PROJECT;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
/**
* This step:
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java
index d02909069d3..18447724fab 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java
@@ -42,7 +42,7 @@ import org.sonar.server.computation.metric.MetricRepository;
import org.sonar.server.computation.qualityprofile.QPMeasureData;
import org.sonar.server.computation.qualityprofile.QualityProfile;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
public class QualityProfileEventsStep implements ComputationStep {
private final TreeRootHolder treeRootHolder;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java
index c715cfbabb2..17b066cd5ff 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java
@@ -29,7 +29,7 @@ import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
import org.sonar.server.computation.component.TreeRootHolder;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
public class TreeRootHolderRule implements TestRule, TreeRootHolder {
private Component root;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/PathAwareVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/PathAwareVisitorTest.java
new file mode 100644
index 00000000000..4130a79b850
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/component/PathAwareVisitorTest.java
@@ -0,0 +1,264 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.computation.component;
+
+import com.google.common.base.Function;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.junit.Test;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.FluentIterable.from;
+import static com.google.common.collect.ImmutableList.of;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.FILE;
+import static org.sonar.server.computation.component.Component.Type.MODULE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
+
+public class PathAwareVisitorTest {
+
+ private static final int ROOT_REF = 1;
+ private static final DumbComponent SOME_TREE_ROOT = DumbComponent.builder(PROJECT, ROOT_REF)
+ .addChildren(
+ DumbComponent.builder(MODULE, 11)
+ .addChildren(
+ DumbComponent.builder(DIRECTORY, 111)
+ .addChildren(
+ DumbComponent.builder(FILE, 1111).build(),
+ DumbComponent.builder(FILE, 1112).build()
+ )
+ .build(),
+ DumbComponent.builder(DIRECTORY, 112)
+ .addChildren(
+ DumbComponent.builder(FILE, 1121).build()
+ )
+ .build())
+ .build(),
+ DumbComponent.builder(MODULE, 12)
+ .addChildren(
+ DumbComponent.builder(DIRECTORY, 121)
+ .addChildren(
+ DumbComponent.builder(FILE, 1211).build()
+ )
+ .build()
+ ).build()
+ ).build();
+
+ @Test
+ public void verify_preOrder() {
+ TestPathAwareVisitor underTest = new TestPathAwareVisitor(PRE_ORDER);
+ underTest.visit(SOME_TREE_ROOT);
+
+ Iterator<CallRecord> expected = of(
+ newCallRecord("visitAny", 1, null, of(1)),
+ newCallRecord("visitProject", 1, null, of(1)),
+ newCallRecord("visitAny", 11, 1, of(11, 1)),
+ newCallRecord("visitModule", 11, 1, of(11, 1)),
+ newCallRecord("visitAny", 111, 11, of(111, 11, 1)),
+ newCallRecord("visitDirectory", 111, 11, of(111, 11, 1)),
+ newCallRecord("visitAny", 1111, 111, of(1111, 111, 11, 1)),
+ newCallRecord("visitFile", 1111, 111, of(1111, 111, 11, 1)),
+ newCallRecord("visitAny", 1112, 111, of(1112, 111, 11, 1)),
+ newCallRecord("visitFile", 1112, 111, of(1112, 111, 11, 1)),
+ newCallRecord("visitAny", 112, 11, of(112, 11, 1)),
+ newCallRecord("visitDirectory", 112, 11, of(112, 11, 1)),
+ newCallRecord("visitAny", 1121, 112, of(1121, 112, 11, 1)),
+ newCallRecord("visitFile", 1121, 112, of(1121, 112, 11, 1)),
+ newCallRecord("visitAny", 12, 1, of(12, 1)),
+ newCallRecord("visitModule", 12, 1, of(12, 1)),
+ newCallRecord("visitAny", 121, 12, of(121, 12, 1)),
+ newCallRecord("visitDirectory", 121, 12, of(121, 12, 1)),
+ newCallRecord("visitAny", 1211, 121, of(1211, 121, 12, 1)),
+ newCallRecord("visitFile", 1211, 121, of(1211, 121, 12, 1))
+ ).iterator();
+ verifyCallRecords(expected, underTest.callsRecords.iterator());
+ }
+
+ @Test
+ public void verify_postOrder() {
+ TestPathAwareVisitor underTest = new TestPathAwareVisitor(POST_ORDER);
+ underTest.visit(SOME_TREE_ROOT);
+
+ Iterator<CallRecord> expected = of(
+ newCallRecord("visitAny", 1111, 111, of(1111, 111, 11, 1)),
+ newCallRecord("visitFile", 1111, 111, of(1111, 111, 11, 1)),
+ newCallRecord("visitAny", 1112, 111, of(1112, 111, 11, 1)),
+ newCallRecord("visitFile", 1112, 111, of(1112, 111, 11, 1)),
+ newCallRecord("visitAny", 111, 11, of(111, 11, 1)),
+ newCallRecord("visitDirectory", 111, 11, of(111, 11, 1)),
+ newCallRecord("visitAny", 1121, 112, of(1121, 112, 11, 1)),
+ newCallRecord("visitFile", 1121, 112, of(1121, 112, 11, 1)),
+ newCallRecord("visitAny", 112, 11, of(112, 11, 1)),
+ newCallRecord("visitDirectory", 112, 11, of(112, 11, 1)),
+ newCallRecord("visitAny", 11, 1, of(11, 1)),
+ newCallRecord("visitModule", 11, 1, of(11, 1)),
+ newCallRecord("visitAny", 1211, 121, of(1211, 121, 12, 1)),
+ newCallRecord("visitFile", 1211, 121, of(1211, 121, 12, 1)),
+ newCallRecord("visitAny", 121, 12, of(121, 12, 1)),
+ newCallRecord("visitDirectory", 121, 12, of(121, 12, 1)),
+ newCallRecord("visitAny", 12, 1, of(12, 1)),
+ newCallRecord("visitModule", 12, 1, of(12, 1)),
+ newCallRecord("visitAny", 1, null, of(1)),
+ newCallRecord("visitProject", 1, null, of(1))
+ ).iterator();
+ verifyCallRecords(expected, underTest.callsRecords.iterator());
+ }
+
+ private static void verifyCallRecords(Iterator<CallRecord> expected, Iterator<CallRecord> actual) {
+ while (expected.hasNext()) {
+ assertThat(actual.next()).isEqualTo(expected.next());
+ }
+ }
+
+ private static CallRecord newCallRecord(String method, int currentRef, @Nullable Integer parentRef, List<Integer> path) {
+ return new CallRecord(method, currentRef, currentRef, parentRef, ROOT_REF, path);
+ }
+
+ private static class TestPathAwareVisitor extends PathAwareVisitor<Integer> {
+ private final List<CallRecord> callsRecords = new ArrayList<>();
+
+ public TestPathAwareVisitor(ComponentVisitor.Order order) {
+ super(FILE, order, new SimpleStackElementFactory<Integer>() {
+ @Override
+ public Integer createForAny(Component component) {
+ return component.getRef();
+ }
+ });
+ }
+
+ @Override
+ protected void visitProject(Component project, Path<Integer> path) {
+ callsRecords.add(newCallRecord(project, path, "visitProject"));
+ }
+
+ @Override
+ protected void visitModule(Component module, Path<Integer> path) {
+ callsRecords.add(newCallRecord(module, path, "visitModule"));
+ }
+
+ @Override
+ protected void visitDirectory(Component directory, Path<Integer> path) {
+ callsRecords.add(newCallRecord(directory, path, "visitDirectory"));
+ }
+
+ @Override
+ protected void visitFile(Component file, Path<Integer> path) {
+ callsRecords.add(newCallRecord(file, path, "visitFile"));
+ }
+
+ @Override
+ protected void visitUnknown(Component unknownComponent, Path<Integer> path) {
+ callsRecords.add(newCallRecord(unknownComponent, path, "visitUnknown"));
+ }
+
+ @Override
+ protected void visitAny(Component component, Path<Integer> path) {
+ callsRecords.add(newCallRecord(component, path, "visitAny"));
+ }
+
+ private static CallRecord newCallRecord(Component project, Path<Integer> path, String method) {
+ return new CallRecord(method, project.getRef(), path.current(), getParent(path), path.root(),
+ toValueList(path));
+ }
+
+ private static List<Integer> toValueList(Path<Integer> path) {
+ return from(path.getCurrentPath()).transform(new Function<PathElement<Integer>, Integer>() {
+ @Nonnull
+ @Override
+ public Integer apply(@Nonnull PathElement<Integer> input) {
+ return input.getElement();
+ }
+ }).toList();
+ }
+
+ private static Integer getParent(Path<Integer> path) {
+ try {
+ Integer parent = path.parent();
+ checkArgument(parent != null, "Path.parent returned a null value!");
+ return parent;
+ } catch (NoSuchElementException e) {
+ return null;
+ }
+ }
+ }
+
+ private static class CallRecord {
+ private final String method;
+ private final int ref;
+ private final int current;
+ @CheckForNull
+ private final Integer parent;
+ private final int root;
+ private final List<Integer> path;
+
+ private CallRecord(String method, int ref, int current, @Nullable Integer parent, int root, List<Integer> path) {
+ this.method = method;
+ this.ref = ref;
+ this.current = current;
+ this.parent = parent;
+ this.root = root;
+ this.path = path;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CallRecord that = (CallRecord) o;
+ return Objects.equals(ref, that.ref) &&
+ Objects.equals(current, that.current) &&
+ Objects.equals(root, that.root) &&
+ Objects.equals(method, that.method) &&
+ Objects.equals(parent, that.parent) &&
+ Objects.equals(path, that.path);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(method, ref, current, parent, root, path);
+ }
+
+ @Override
+ public String toString() {
+ return "{" +
+ "method='" + method + '\'' +
+ ", ref=" + ref +
+ ", current=" + current +
+ ", parent=" + parent +
+ ", root=" + root +
+ ", path=" + path +
+ '}';
+ }
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/PostOrderDepthTraversalTypeAwareVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/PostOrderDepthTraversalTypeAwareVisitorTest.java
index 48e57e23f76..3e3514b115b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/component/PostOrderDepthTraversalTypeAwareVisitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/component/PostOrderDepthTraversalTypeAwareVisitorTest.java
@@ -29,7 +29,7 @@ import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
import static org.sonar.server.computation.component.Component.Type.FILE;
import static org.sonar.server.computation.component.Component.Type.MODULE;
import static org.sonar.server.computation.component.Component.Type.PROJECT;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
public class PostOrderDepthTraversalTypeAwareVisitorTest {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/PreOrderDepthTraversalTypeAwareVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/PreOrderDepthTraversalTypeAwareVisitorTest.java
index c471d2341fc..f2129085694 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/component/PreOrderDepthTraversalTypeAwareVisitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/component/PreOrderDepthTraversalTypeAwareVisitorTest.java
@@ -29,7 +29,7 @@ import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
import static org.sonar.server.computation.component.Component.Type.FILE;
import static org.sonar.server.computation.component.Component.Type.MODULE;
import static org.sonar.server.computation.component.Component.Type.PROJECT;
-import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
public class PreOrderDepthTraversalTypeAwareVisitorTest {