*/
package org.sonar.server.computation.component;
+/**
+ * Allow to crawl a component tree from a given component
+ */
public interface ComponentCrawler {
- void visit(Component tree);
- enum Order {
- /**
- * Each component is visited BEFORE its children. Top-down traversal of
- * tree of components.
- */
- PRE_ORDER,
+ void visit(Component tree);
- /**
- * Each component is visited AFTER its children. Bottom-up traversal of
- * tree of components.
- */
- POST_ORDER
- }
}
*/
public abstract class DepthTraversalTypeAwareCrawler implements TypeAwareCrawler {
private final Component.Type maxDepth;
- private final Order order;
+ private final Visitor.Order order;
- protected DepthTraversalTypeAwareCrawler(Component.Type maxDepth, Order order) {
+ protected DepthTraversalTypeAwareCrawler(Component.Type maxDepth, Visitor.Order order) {
this.maxDepth = requireNonNull(maxDepth);
this.order = requireNonNull(order);
}
return;
}
- if (order == Order.PRE_ORDER) {
+ if (order == Visitor.Order.PRE_ORDER) {
visitNode(component);
}
visitChildren(component);
- if (order == Order.POST_ORDER) {
+ if (order == Visitor.Order.POST_ORDER) {
visitNode(component);
}
}
+ @Override
+ public Component.Type getMaxDepth() {
+ return maxDepth;
+ }
+
+ @Override
+ public Order getOrder() {
+ return order;
+ }
+
private void visitNode(Component component) {
visitAny(component);
switch (component.getType()) {
--- /dev/null
+/*
+ * 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;
+
+public class DequeBasedPath<T> implements PathAwareVisitor.Path<T>, Iterable<PathAwareVisitor.PathElement<T>> {
+ private final Deque<PathAwareVisitor.PathElement<T>> deque = new ArrayDeque<>();
+
+ @Override
+ public T current() {
+ return deque.getFirst().getElement();
+ }
+
+ @Override
+ public T parent() {
+ Iterator<PathAwareVisitor.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<PathAwareVisitor.PathElement<T>> iterator() {
+ return deque.iterator();
+ }
+
+ @Override
+ public Iterable<PathAwareVisitor.PathElement<T>> getCurrentPath() {
+ return this;
+ }
+
+ public void add(PathAwareVisitor.PathElement<T> pathElement) {
+ deque.addFirst(pathElement);
+ }
+
+ public PathAwareVisitor.PathElement<T> pop() {
+ return deque.pop();
+ }
+}
*/
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.ComponentCrawler.Order.POST_ORDER;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
/**
- * A ComponentVisitor which provide access to a representation of the path from the root to the currently visited
+ * A {@link ComponentCrawler} 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 DepthTraversalTypeAwareCrawler}, this visitor supports max depth visit and ordering.
+ * As for {@link DepthTraversalTypeAwareCrawler}, this crawler supports max depth visit and ordering.
*/
-public abstract class PathAwareCrawler<T> implements ComponentCrawler {
- private final Component.Type maxDepth;
- private final Order order;
- private final StackElementFactory<T> factory;
+public abstract class PathAwareCrawler<T> extends PathAwareVisitorAdapter<T> implements ComponentCrawler {
+
private final DequeBasedPath<T> stack = new DequeBasedPath<>();
- public PathAwareCrawler(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");
+ public PathAwareCrawler(Component.Type maxDepth, Visitor.Order order, StackElementFactory<T> factory) {
+ super(maxDepth, order, factory);
}
@Override
public void visit(Component component) {
- if (component.getType().isDeeperThan(maxDepth)) {
+ if (component.getType().isDeeperThan(getMaxDepth())) {
return;
}
stack.add(new PathElementImpl<>(component, createForComponent(component)));
- if (order == PRE_ORDER) {
+ if (getOrder() == PRE_ORDER) {
visitNode(component);
}
visitChildren(component);
- if (order == POST_ORDER) {
+ if (getOrder() == 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) {
for (Component child : component.getChildren()) {
- if (!child.getType().isDeeperThan(maxDepth)) {
+ if (!child.getType().isDeeperThan(getMaxDepth())) {
visit(child);
}
}
}
}
- 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();
+ private T createForComponent(Component component) {
+ switch (component.getType()) {
+ case PROJECT:
+ return getFactory().createForProject(component);
+ case MODULE:
+ return getFactory().createForModule(component);
+ case DIRECTORY:
+ return getFactory().createForDirectory(component);
+ case FILE:
+ return getFactory().createForFile(component);
+ default:
+ return getFactory().createForUnknown(component);
}
}
- 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 PathAwareCrawler.PathElement} which starts with
- * the {@link PathAwareCrawler.PathElement} of the current Component and ends with the
- * {@link PathAwareCrawler.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> {
+ public static final class PathElementImpl<T> implements PathElement<T> {
private final Component component;
private final T element;
- private PathElementImpl(Component component, T element) {
+ public PathElementImpl(Component component, T element) {
this.component = component;
this.element = element;
}
return element;
}
}
+
}
--- /dev/null
+/*
+ * 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.NoSuchElementException;
+
+/**
+ * A {@link Visitor} 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.
+ */
+public interface PathAwareVisitor<T> extends Visitor {
+
+ StackElementFactory<T> getFactory();
+
+ void visitProject(Component project, Path<T> path);
+
+ void visitModule(Component module, Path<T> path);
+
+ void visitDirectory(Component directory, Path<T> path);
+
+ void visitFile(Component file, Path<T> path);
+
+ void visitUnknown(Component unknownComponent, Path<T> path);
+
+ void visitAny(Component component, Path<T> path);
+
+ interface StackElementFactory<T> {
+ T createForProject(Component project);
+
+ T createForModule(Component module);
+
+ T createForDirectory(Component directory);
+
+ T createForFile(Component file);
+
+ T createForUnknown(Component file);
+ }
+
+ 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();
+ }
+
+ interface PathElement<T> {
+ /**
+ * The Component on the path.
+ */
+ Component getComponent();
+
+ /**
+ * The stacked element for the Component of this PathElement.
+ */
+ T getElement();
+ }
+}
--- /dev/null
+/*
+ * 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 static java.util.Objects.requireNonNull;
+
+/**
+ * A adapter of the {@link PathAwareVisitor} to be able to visit only some component types
+ */
+public abstract class PathAwareVisitorAdapter<T> implements PathAwareVisitor<T> {
+ private final Component.Type maxDepth;
+ private final Order order;
+ private final StackElementFactory<T> factory;
+
+ public PathAwareVisitorAdapter(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 Component.Type getMaxDepth() {
+ return maxDepth;
+ }
+
+ @Override
+ public Order getOrder() {
+ return order;
+ }
+
+ @Override
+ public StackElementFactory<T> getFactory() {
+ return factory;
+ }
+
+ @Override
+ public void visitProject(Component project, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ @Override
+ public void visitModule(Component module, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ @Override
+ public void visitDirectory(Component directory, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ @Override
+ public void visitFile(Component file, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ @Override
+ public void visitUnknown(Component unknownComponent, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ @Override
+ public void visitAny(Component component, Path<T> path) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+
+public class PathAwareVisitorWrapper<T> implements VisitorWrapper {
+
+ private final PathAwareVisitor<T> delegate;
+
+ private final DequeBasedPath<T> stack = new DequeBasedPath<>();
+
+ public PathAwareVisitorWrapper(PathAwareVisitor<T> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void beforeComponent(Component component){
+ stack.add(new PathElementImpl<>(component, createForComponent(component)));
+ }
+
+ @Override
+ public void afterComponent(Component component){
+ stack.pop();
+ }
+
+ @Override
+ public void visitProject(Component tree) {
+ delegate.visitProject(tree, stack);
+ }
+
+ @Override
+ public void visitModule(Component tree) {
+ delegate.visitModule(tree, stack);
+ }
+
+ @Override
+ public void visitDirectory(Component tree) {
+ delegate.visitDirectory(tree, stack);
+ }
+
+ @Override
+ public void visitFile(Component tree) {
+ delegate.visitFile(tree, stack);
+ }
+
+ @Override
+ public void visitAny(Component component) {
+ delegate.visitAny(component, stack);
+ }
+
+ @Override
+ public Visitor.Order getOrder() {
+ return delegate.getOrder();
+ }
+
+ @Override
+ public Component.Type getMaxDepth() {
+ return delegate.getMaxDepth();
+ }
+
+ private T createForComponent(Component component) {
+ switch (component.getType()) {
+ case PROJECT:
+ return delegate.getFactory().createForProject(component);
+ case MODULE:
+ return delegate.getFactory().createForModule(component);
+ case DIRECTORY:
+ return delegate.getFactory().createForDirectory(component);
+ case FILE:
+ return delegate.getFactory().createForFile(component);
+ default:
+ return delegate.getFactory().createForUnknown(component);
+ }
+ }
+
+ public static final class PathElementImpl<T> implements PathAwareVisitor.PathElement<T> {
+ private final Component component;
+ private final T element;
+
+ public PathElementImpl(Component component, T element) {
+ this.component = component;
+ this.element = element;
+ }
+
+ @Override
+ public Component getComponent() {
+ return component;
+ }
+
+ @Override
+ public T getElement() {
+ return element;
+ }
+ }
+}
import java.util.Map;
import java.util.Objects;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
/**
* Holds the reference to the root of the {@link Component} tree for the current CE run.
/**
* A {@link ComponentCrawler} which can exposes methods which ensure the type of the visited Component.
*/
-public interface TypeAwareCrawler extends ComponentCrawler {
- /**
- * Called when encountering a Component of type {@link Component.Type#PROJECT}
- */
- void visitProject(Component tree);
-
- /**
- * Called when encountering a Component of type {@link Component.Type#MODULE}
- */
- void visitModule(Component tree);
-
- /**
- * Called when encountering a Component of type {@link Component.Type#DIRECTORY}
- */
- void visitDirectory(Component tree);
-
- /**
- * Called when encountering a Component of type {@link Component.Type#FILE}
- */
- void visitFile(Component tree);
+public interface TypeAwareCrawler extends ComponentCrawler, TypeAwareVisitor {
/**
* Called when encountering a Component of an unknown type
*/
void visitUnknown(Component tree);
-
- /**
- * Called for any component, <strong>in addition</strong> to the methods specific to each type
- */
- void visitAny(Component component);
}
--- /dev/null
+/*
+ * 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;
+
+/**
+ * A {@link Visitor} which can exposes methods which ensure the type of the visited Component.
+ */
+public interface TypeAwareVisitor extends Visitor {
+ /**
+ * Called when encountering a Component of type {@link Component.Type#PROJECT}
+ */
+ void visitProject(Component project);
+
+ /**
+ * Called when encountering a Component of type {@link Component.Type#MODULE}
+ */
+ void visitModule(Component module);
+
+ /**
+ * Called when encountering a Component of type {@link Component.Type#DIRECTORY}
+ */
+ void visitDirectory(Component directory);
+
+ /**
+ * Called when encountering a Component of type {@link Component.Type#FILE}
+ */
+ void visitFile(Component file);
+
+ /**
+ * Called for any component, <strong>in addition</strong> to the methods specific to each type
+ */
+ void visitAny(Component any);
+
+}
--- /dev/null
+/*
+ * 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 static java.util.Objects.requireNonNull;
+
+/**
+ * A adapter of the {@link TypeAwareVisitor} to be able to visit only some component types
+ */
+public abstract class TypeAwareVisitorAdapter implements TypeAwareVisitor {
+
+ private final Component.Type maxDepth;
+ private final Order order;
+
+ public TypeAwareVisitorAdapter(Component.Type maxDepth, Order order) {
+ this.maxDepth = requireNonNull(maxDepth);
+ this.order = requireNonNull(order);
+ }
+
+ @Override
+ public Component.Type getMaxDepth() {
+ return maxDepth;
+ }
+
+ @Override
+ public Order getOrder() {
+ return order;
+ }
+
+ /**
+ * Called when encountering a Component of type {@link Component.Type#PROJECT}
+ */
+ @Override
+ public void visitProject(Component project) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ /**
+ * Called when encountering a Component of type {@link Component.Type#MODULE}
+ */
+ @Override
+ public void visitModule(Component module) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ /**
+ * Called when encountering a Component of type {@link Component.Type#DIRECTORY}
+ */
+ @Override
+ public void visitDirectory(Component directory) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ /**
+ * Called when encountering a Component of type {@link Component.Type#FILE}
+ */
+ @Override
+ public void visitFile(Component file) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+ /**
+ * Called for any component, <strong>in addition</strong> to the methods specific to each type
+ */
+ @Override
+ public void visitAny(Component any) {
+ // empty implementation, meant to be override at will by subclasses
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+
+public class TypeAwareVisitorWrapper implements VisitorWrapper {
+
+ private final TypeAwareVisitor delegate;
+
+ public TypeAwareVisitorWrapper(TypeAwareVisitor delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void beforeComponent(Component component){
+ // Nothing to do
+ }
+
+ @Override
+ public void afterComponent(Component component){
+ // Nothing to do
+ }
+
+ @Override
+ public void visitProject(Component tree) {
+ delegate.visitProject(tree);
+ }
+
+ @Override
+ public void visitModule(Component tree) {
+ delegate.visitModule(tree);
+ }
+
+ @Override
+ public void visitDirectory(Component tree) {
+ delegate.visitDirectory(tree);
+ }
+
+ @Override
+ public void visitFile(Component tree) {
+ delegate.visitFile(tree);
+ }
+
+ @Override
+ public void visitAny(Component component) {
+ delegate.visitAny(component);
+ }
+
+ @Override
+ public Visitor.Order getOrder() {
+ return delegate.getOrder();
+ }
+
+ @Override
+ public Component.Type getMaxDepth() {
+ return delegate.getMaxDepth();
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+
+public interface Visitor {
+
+ Order getOrder();
+
+ Component.Type getMaxDepth();
+
+ enum Order {
+ /**
+ * Each component is visited BEFORE its children. Top-down traversal of
+ * tree of components.
+ */
+ PRE_ORDER,
+
+ /**
+ * Each component is visited AFTER its children. Bottom-up traversal of
+ * tree of components.
+ */
+ POST_ORDER
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+public interface VisitorWrapper extends TypeAwareVisitor {
+
+ void beforeComponent(Component component);
+
+ void afterComponent(Component component);
+
+}
import javax.annotation.CheckForNull;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.PathAwareCrawler;
+import org.sonar.server.computation.component.Visitor;
import org.sonar.server.computation.measure.Measure;
import org.sonar.server.computation.measure.MeasureRepository;
import org.sonar.server.computation.metric.Metric;
private final List<Formula> formulas;
private FormulaExecutorComponentCrawler(Builder builder, List<Formula> formulas) {
- super(Component.Type.FILE, Order.POST_ORDER, COUNTERS_FACTORY);
+ super(Component.Type.FILE, Visitor.Order.POST_ORDER, COUNTERS_FACTORY);
this.periodsHolder = builder.periodsHolder;
this.measureRepository = builder.measureRepository;
this.metricRepository = builder.metricRepository;
}
@Override
- protected void visitProject(Component project, Path<FormulaExecutorComponentCrawler.Counters> path) {
+ public void visitProject(Component project, Path<FormulaExecutorComponentCrawler.Counters> path) {
processNotFile(project, path);
}
@Override
- protected void visitModule(Component module, Path<FormulaExecutorComponentCrawler.Counters> path) {
+ public void visitModule(Component module, Path<FormulaExecutorComponentCrawler.Counters> path) {
processNotFile(module, path);
}
@Override
- protected void visitDirectory(Component directory, Path<FormulaExecutorComponentCrawler.Counters> path) {
+ public void visitDirectory(Component directory, Path<FormulaExecutorComponentCrawler.Counters> path) {
processNotFile(directory, path);
}
@Override
- protected void visitFile(Component file, Path<FormulaExecutorComponentCrawler.Counters> path) {
+ public void visitFile(Component file, Path<FormulaExecutorComponentCrawler.Counters> path) {
processFile(file, path);
}
import org.sonar.server.computation.qualityprofile.QualityProfile;
import static org.sonar.server.computation.component.Component.Type.MODULE;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
/**
* Aggregates quality profile on lower-level module nodes on their parent modules and project
}
@Override
- protected void visitProject(Component project, Path<QProfiles> path) {
+ public void visitProject(Component project, Path<QProfiles> path) {
addMeasure(project, path.current());
Optional<Measure> qProfileMeasure = measureRepository.getRawMeasure(project, qProfilesMetric);
if (!qProfileMeasure.isPresent() || QPMeasureData.fromJson(qProfileMeasure.get().getData()).getProfiles().isEmpty()) {
}
@Override
- protected void visitModule(Component module, Path<QProfiles> path) {
+ public void visitModule(Component module, Path<QProfiles> path) {
Optional<Measure> measure = measureRepository.getRawMeasure(module, qProfilesMetric);
QProfiles qProfiles = path.current();
if (measure.isPresent()) {
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.computation.component.Visitor;
import org.sonar.server.computation.measure.Measure;
import org.sonar.server.computation.measure.MeasureRepository;
import org.sonar.server.computation.metric.Metric;
@Override
public void execute() {
- new DepthTraversalTypeAwareCrawler(Component.Type.FILE, DepthTraversalTypeAwareCrawler.Order.PRE_ORDER) {
+ new DepthTraversalTypeAwareCrawler(Component.Type.FILE, Visitor.Order.PRE_ORDER) {
@Override
public void visitAny(Component component) {
copy(component);
import org.sonar.server.computation.period.Period;
import org.sonar.server.computation.period.PeriodsHolder;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
/**
* Set variations on all numeric measures found in the repository.
import org.sonar.server.computation.issue.TrackerExecution;
import org.sonar.server.util.cache.DiskCache;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
public class IntegrateIssuesStep implements ComputationStep {
import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
import org.sonar.server.computation.component.TreeRootHolder;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
/**
* Persist duplications into
import org.sonar.server.computation.component.DbIdsRepository;
import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.computation.component.Visitor;
import org.sonar.server.computation.event.Event;
import org.sonar.server.computation.event.EventRepository;
private final long analysisDate;
public PersistEventComponentCrawler(DbSession session, long analysisDate) {
- super(Component.Type.FILE, Order.PRE_ORDER);
+ super(Component.Type.FILE, Visitor.Order.PRE_ORDER);
this.session = session;
this.analysisDate = analysisDate;
}
import org.sonar.server.computation.source.ScmLineReader;
import org.sonar.server.computation.source.SymbolsLineReader;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
public class PersistFileSourcesStep implements ComputationStep {
import static org.sonar.api.measures.CoreMetrics.CLASS_COMPLEXITY_DISTRIBUTION_KEY;
import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY;
import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
public class PersistMeasuresStep implements ComputationStep {
import org.sonar.server.source.index.SourceLineIndex;
import static com.google.common.base.Objects.firstNonNull;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep {
import org.sonar.server.computation.component.TreeRootHolder;
import static com.google.common.collect.Sets.newHashSet;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
/**
* Persist project and module links
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.computation.component.Visitor;
public class PersistTestsStep implements ComputationStep {
boolean hasUnprocessedCoverageDetails = false;
public TestDepthTraversalTypeAwareCrawler(DbSession session) {
- super(Component.Type.FILE, Order.PRE_ORDER);
+ super(Component.Type.FILE, Visitor.Order.PRE_ORDER);
this.session = session;
this.existingFileSourcesByUuid = new HashMap<>();
this.projectUuid = treeRootHolder.getRoot().getUuid();
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.computation.component.Visitor;
import org.sonar.server.computation.event.Event;
import org.sonar.server.computation.event.EventRepository;
import org.sonar.server.computation.measure.Measure;
@Override
public void execute() {
- new DepthTraversalTypeAwareCrawler(Component.Type.PROJECT, DepthTraversalTypeAwareCrawler.Order.PRE_ORDER) {
+ new DepthTraversalTypeAwareCrawler(Component.Type.PROJECT, Visitor.Order.PRE_ORDER) {
@Override
public void visitProject(Component project) {
executeForProject(project);
import org.sonar.server.computation.qualitygate.QualityGateService;
import static org.sonar.server.computation.component.Component.Type.PROJECT;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
/**
* This step retrieves the QualityGate for the current {@link ReportQueue.Item} and stores it in
import org.sonar.server.computation.qualitygate.QualityGateHolder;
import static org.sonar.server.computation.component.Component.Type.PROJECT;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
/**
* This step:
import org.sonar.server.computation.qualityprofile.QPMeasureData;
import org.sonar.server.computation.qualityprofile.QualityProfile;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
/**
* Computation of quality profile events
import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
import static org.sonar.api.measures.CoreMetrics.STATEMENTS_KEY;
import static org.sonar.server.computation.component.Component.Type.FILE;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
/**
}
@Override
- protected void visitProject(Component project, Path<Counter> path) {
+ public void visitProject(Component project, Path<Counter> path) {
createMeasures(project, path.current().directories, path.current().files);
}
@Override
- protected void visitModule(Component module, Path<Counter> path) {
+ public void visitModule(Component module, Path<Counter> path) {
createMeasures(module, path.current().directories, path.current().files);
path.parent().directories += path.current().directories;
}
@Override
- protected void visitDirectory(Component directory, Path<Counter> path) {
+ public void visitDirectory(Component directory, Path<Counter> path) {
createMeasures(directory, 1, path.current().files);
path.parent().directories += 1;
}
@Override
- protected void visitFile(Component file, Path<Counter> path) {
+ public void visitFile(Component file, Path<Counter> path) {
if (file.getFileAttributes().isUnitTest()) {
return;
}
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.PathAwareCrawler;
import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.computation.component.Visitor;
import org.sonar.server.computation.measure.Measure;
import org.sonar.server.computation.measure.MeasureRepository;
import org.sonar.server.computation.metric.Metric;
private final Metric sqaleRatingMetric;
public SqaleMeasuresCrawler() {
- super(Component.Type.FILE, Order.POST_ORDER, new SimpleStackElementFactory<DevelopmentCost>() {
+ super(Component.Type.FILE, Visitor.Order.POST_ORDER, new SimpleStackElementFactory<DevelopmentCost>() {
@Override
public DevelopmentCost createForAny(Component component) {
return new DevelopmentCost();
}
@Override
- protected void visitModule(Component module, Path<DevelopmentCost> path) {
+ public void visitModule(Component module, Path<DevelopmentCost> path) {
computeAndSaveMeasures(module, path);
}
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.computation.component.Visitor;
import static org.sonar.api.utils.DateUtils.formatDateTime;
private Component rawProject;
public ValidateProjectsCrawler(DbSession session, ComponentDao componentDao, boolean preventAutomaticProjectCreation, Map<String, ComponentDto> baseModulesByKey) {
- super(Component.Type.MODULE, Order.PRE_ORDER);
+ super(Component.Type.MODULE, Visitor.Order.PRE_ORDER);
this.session = session;
this.componentDao = componentDao;
import org.sonar.server.computation.component.MutableTreeRootHolder;
import org.sonar.server.computation.component.TreeRootHolder;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
public class TreeRootHolderRule implements TestRule, MutableTreeRootHolder {
private Component root;
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.ComponentCrawler.Order.POST_ORDER;
-import static org.sonar.server.computation.component.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
public class PathAwareCrawlerTest {
private static class TestPathAwareCrawler extends PathAwareCrawler<Integer> {
private final List<CallRecord> callsRecords = new ArrayList<>();
- public TestPathAwareCrawler(Component.Type maxDepth, ComponentCrawler.Order order) {
+ public TestPathAwareCrawler(Component.Type maxDepth, Visitor.Order order) {
super(maxDepth, order, new SimpleStackElementFactory<Integer>() {
@Override
public Integer createForAny(Component component) {
}
@Override
- protected void visitProject(Component project, Path<Integer> path) {
+ public void visitProject(Component project, Path<Integer> path) {
callsRecords.add(newCallRecord(project, path, "visitProject"));
}
@Override
- protected void visitModule(Component module, Path<Integer> path) {
+ public void visitModule(Component module, Path<Integer> path) {
callsRecords.add(newCallRecord(module, path, "visitModule"));
}
@Override
- protected void visitDirectory(Component directory, Path<Integer> path) {
+ public void visitDirectory(Component directory, Path<Integer> path) {
callsRecords.add(newCallRecord(directory, path, "visitDirectory"));
}
@Override
- protected void visitFile(Component file, Path<Integer> path) {
+ public void visitFile(Component file, Path<Integer> path) {
callsRecords.add(newCallRecord(file, path, "visitFile"));
}
@Override
- protected void visitUnknown(Component unknownComponent, Path<Integer> path) {
+ public void visitUnknown(Component unknownComponent, Path<Integer> path) {
callsRecords.add(newCallRecord(unknownComponent, path, "visitUnknown"));
}
@Override
- protected void visitAny(Component component, Path<Integer> path) {
+ public void visitAny(Component component, Path<Integer> path) {
callsRecords.add(newCallRecord(component, path, "visitAny"));
}
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.ComponentCrawler.Order.POST_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.POST_ORDER;
public class PostOrderDepthTraversalTypeAwareCrawlerTest {
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.ComponentCrawler.Order.PRE_ORDER;
+import static org.sonar.server.computation.component.Visitor.Order.PRE_ORDER;
public class PreOrderDepthTraversalTypeAwareCrawlerTest {
import org.junit.rules.ExternalResource;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.ComponentCrawler;
import org.sonar.server.computation.component.DepthTraversalTypeAwareCrawler;
import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.computation.component.Visitor;
import org.sonar.server.computation.debt.Characteristic;
import org.sonar.server.computation.metric.Metric;
import org.sonar.server.computation.metric.MetricRepositoryRule;
private final Map<Integer, Component> componentsByRef = new HashMap<>();
public TreeComponentProvider(Component root) {
- new DepthTraversalTypeAwareCrawler(Component.Type.FILE, ComponentCrawler.Order.PRE_ORDER) {
+ new DepthTraversalTypeAwareCrawler(Component.Type.FILE, Visitor.Order.PRE_ORDER) {
@Override
public void visitAny(Component component) {
checkState(!componentsByRef.containsKey(component.getRef()), "Tree contains more than one component with ref " + component.getRef());