package org.neo4j.kernel.impl.traversal; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Stack; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Path; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipExpander; import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.ReturnableEvaluator; import org.neo4j.graphdb.StopEvaluator; import org.neo4j.graphdb.TraversalPosition; import org.neo4j.graphdb.Traverser.Order; import org.neo4j.graphdb.traversal.PruneEvaluator; import org.neo4j.graphdb.traversal.TraversalDescription; import org.neo4j.graphdb.traversal.Uniqueness; import org.neo4j.helpers.Predicate; import org.neo4j.kernel.OrderedByTypeExpander; import org.neo4j.kernel.Traversal; public class OldTraverserWrapper { private static class TraverserImpl implements org.neo4j.graphdb.Traverser, Iterator<Node> { private TraversalPosition currentPos; private Iterator<Path> iter; private int count; public TraversalPosition currentPosition() { return currentPos; } public Collection<Node> getAllNodes() { List<Node> result = new ArrayList<Node>(); for ( Node node : this ) { result.add( node ); } return result; } public Iterator<Node> iterator() { return this; } public boolean hasNext() { return iter.hasNext(); } public Node next() { currentPos = new PositionImpl( this, iter.next() ); count++; return currentPos.currentNode(); } public void remove() { throw new UnsupportedOperationException(); } } private static class PositionImpl implements TraversalPosition { private final Path position; private final int count; PositionImpl( TraverserImpl traverser, Path position ) { this.position = position; this.count = traverser.count; } public Node currentNode() { return position.endNode(); } public int depth() { return position.length(); } public boolean isStartNode() { return position.length() == 0; } public boolean notStartNode() { return !isStartNode(); } public Relationship lastRelationshipTraversed() { return position.lastRelationship(); } public Node previousNode() { return position.lastRelationship().getOtherNode( position.endNode() ); } public int returnedNodesCount() { return count; } } private static void assertNotNull( Object object, String message ) { if ( object == null ) { throw new IllegalArgumentException( "Null " + message ); } } private static final TraversalDescription BASE_DESCRIPTION = Traversal.description().uniqueness( Uniqueness.NODE_GLOBAL ); public static org.neo4j.graphdb.Traverser traverse( Node node, Order traversalOrder, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator, Object... relationshipTypesAndDirections ) { assertNotNull( traversalOrder, "order" ); assertNotNull( stopEvaluator, "stop evaluator" ); assertNotNull( returnableEvaluator, "returnable evaluator" ); if ( relationshipTypesAndDirections.length % 2 != 0 || relationshipTypesAndDirections.length == 0 ) { throw new IllegalArgumentException(); } TraverserImpl result = new TraverserImpl(); TraversalDescription description = traversal( result, traversalOrder, stopEvaluator, returnableEvaluator ); description = description.expand( toExpander( relationshipTypesAndDirections ) ); result.iter = description.traverse( node ).iterator(); return result; } private static RelationshipExpander toExpander( Object[] relationshipTypesAndDirections ) { Stack<Object[]> entries = new Stack<Object[]>(); for ( int i = 0; i < relationshipTypesAndDirections.length; i += 2 ) { Object relType = relationshipTypesAndDirections[i]; if ( relType == null ) { throw new IllegalArgumentException( "Null relationship type at " + i ); } if ( !(relType instanceof RelationshipType) ) { throw new IllegalArgumentException( "Expected RelationshipType at var args pos " + i + ", found " + relType ); } Object direction = relationshipTypesAndDirections[i+1]; if ( direction == null ) { throw new IllegalArgumentException( "Null direction at " + (i+1) ); } if ( !(direction instanceof Direction) ) { throw new IllegalArgumentException( "Expected Direction at var args pos " + (i+1) + ", found " + direction ); } entries.push( new Object[] { relType, direction } ); } OrderedByTypeExpander expander = new OrderedByTypeExpander(); while ( !entries.isEmpty() ) { Object[] entry = entries.pop(); expander = (OrderedByTypeExpander) expander.add( (RelationshipType) entry[0], (Direction) entry[1] ); } return expander; } private static TraversalDescription traversal( TraverserImpl traverser, Order order, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator ) { TraversalDescription description = BASE_DESCRIPTION; switch ( order ) { case BREADTH_FIRST: description = description.breadthFirst(); break; case DEPTH_FIRST: description = description.depthFirst(); break; default: throw new IllegalArgumentException( "Onsupported traversal order: " + order ); } description = description.prune( new Pruner( traverser, stopEvaluator ) ); description = description.filter( new Filter( traverser, returnableEvaluator ) ); return description; } private static class Pruner implements PruneEvaluator { private final TraverserImpl traverser; private final StopEvaluator evaluator; Pruner( TraverserImpl traverser, StopEvaluator stopEvaluator ) { this.traverser = traverser; this.evaluator = stopEvaluator; } public boolean pruneAfter( Path position ) { return evaluator.isStopNode( new PositionImpl( traverser, position ) ); } } private static class Filter implements Predicate<Path> { private final TraverserImpl traverser; private final ReturnableEvaluator evaluator; Filter( TraverserImpl traverser, ReturnableEvaluator returnableEvaluator ) { this.traverser = traverser; this.evaluator = returnableEvaluator; } public boolean accept( Path position ) { return evaluator.isReturnableNode( new PositionImpl( traverser, position ) ); } } }