package org.neo4j.graphalgo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.neo4j.commons.iterator.IterableWrapper; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.Relationship; 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; import org.neo4j.graphdb.Traverser.Order; /** * Starting from a {@link Node} this will traverse out BREADTH FIRST and find * all nodes up to a certain depth and return full paths to them * (from the start node). * * It will instantiate a traverser and return instantly. */ public class LazyAllPathsFinder { private final Node startNode; private final RelationshipType relationshipType; public LazyAllPathsFinder( Node node, RelationshipType relationshipType ) { this.startNode = node; this.relationshipType = relationshipType; } public Iterable<List<PropertyContainer>> getPaths( final int maxDepth ) { StopEvaluator stopEvaluator = new StopEvaluator() { public boolean isStopNode( TraversalPosition position ) { return position.depth() > maxDepth; } }; final Map<Node, List<PropertyContainer>> trails = new HashMap<Node, List<PropertyContainer>>(); final Traverser traverser = startNode.traverse( Order.BREADTH_FIRST, stopEvaluator, ReturnableEvaluator.ALL_BUT_START_NODE, relationshipType, Direction.BOTH ); return new IterableWrapper<List<PropertyContainer>, Node>( traverser ) { @Override protected List<PropertyContainer> underlyingObjectToObject( Node node ) { TraversalPosition position = traverser.currentPosition(); if ( position.depth() > maxDepth ) { return null; } Relationship rel = position.lastRelationshipTraversed(); List<PropertyContainer> trail = new ArrayList<PropertyContainer>(); if ( position.depth() > 1 ) { Node parent = rel.getOtherNode( node ); List<PropertyContainer> parentTrail = trails.get( parent ); trail.addAll( parentTrail ); trail.add( rel ); } else { trail.add( startNode ); trail.add( rel ); } trail.add( node ); trails.put( node, trail ); return trail; } }; } }