/* * Copyright (c) 2002-2009 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.kernel.impl.traversal; import java.util.Arrays; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.ReturnableEvaluator; import org.neo4j.graphdb.StopEvaluator; import org.neo4j.graphdb.Traverser; import org.neo4j.graphdb.Traverser.Order; /** * The factory for {@link Traverser} instances. The TraverserFactory is * responsible for creating and parameterizing traversers. It has a single * {@link #createTraverser createTraverser()} factory method which is overloaded * with a number of different default parameters, which are described briefly * below: * <P> * <UL> * <LI><CODE>type</CODE> - which is either one of * {@link Traverser#DEPTH_FIRST} and {@link Traverser#BREADTH_FIRST}. This * parameter decides the strategy used when traversering the node space. * <LI><CODE>startNode</CODE> - the starting node for the traverser. * <LI><CODE>traversableRels</CODE> - a list of the relationship types that * will be traversed. * <LI><CODE>traversableDirs</CODE> - a list of directions in which the * traversable relationships will be traversed. The values in this array should * be either one of {@link Traverser#DIRECTION_FORWARDS}, * {@link Traverser#DIRECTION_BACKWARDS} or {@link Traverser#DIRECTION_BOTH}. * This parameter is ignored in the case of non-directed relationships. * <LI><CODE>stopEvaluator</CODE> - the visitor that is used to evaluate * whether the traverser should stop before traversing a specific node. Use this * parameter to limit the size of the traversal. * <LI><CODE>returnableEvaluator</CODE> - the visitor that is used to * evaluate whether the traverser should return a specific node. Use this * parameter to affect the selection of nodes from the traversal. * </UL> * <P> * The factory methods treat all parameters as immutable and thus do not modify * them. This guarantees that the client can optimize by reusing parameters * between invocations of <CODE>createTraverser()</CODE>. */ public final class InternalTraverserFactory { public InternalTraverserFactory() { } /** * Creates a parameterized traverser, using non-default values on all * parameters. * @param type * the traverser type, either one of * {@link Traverser#DEPTH_FIRST} and * {@link Traverser#BREADTH_FIRST} * @param startNode * the start node for the new traverser * @param traversableRels * the relationship types that the new traverser will traverse * @param traversableDirs * the directions that the traversable relationships will be * traversed in * @param stopEvaluator * the client hook for limiting the traversal size * @param returnableEvaluator * the client hook for evaluating nodes before they are returned * @throws IllegalArgumentException * if one or more of the parameters are invalid */ public Traverser createTraverser( Order traversalOrder, Node startNode, RelationshipType[] traversableRels, Direction[] traversableDirs, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator ) { if ( traversableRels == null || traversableDirs == null ) { throw new IllegalArgumentException( "Using this constructor requires that traversable " + "relationships array and traversable directions array " + "isn't null: travRels[" + Arrays.toString( traversableRels ) + "] " + "travDirs[" + Arrays.toString( traversableDirs ) + "]" ); } if ( traversableRels.length != traversableDirs.length ) { throw new IllegalArgumentException( "Length of traversable relationships array isn't equal to " + "length of traversable directions array: " + "travRels.length[" + traversableRels.length + "] != " + "travDirs.length[" + traversableDirs.length + "]" ); } if ( traversalOrder == Order.BREADTH_FIRST ) { return new BreadthFirstTraverser( startNode, traversableRels, traversableDirs, null, null, // preserving rels stopEvaluator, returnableEvaluator, null ); } else if ( traversalOrder == Order.DEPTH_FIRST ) { return new DepthFirstTraverser( startNode, traversableRels, traversableDirs, null, null, // preserving rels stopEvaluator, returnableEvaluator, null ); } else { throw new IllegalArgumentException( "Unknown traverser type: " + traversalOrder ); } } /** * Creates a parameterized traverser which traverses all relationships in * the {@link Traverser#DIRECTION_BOTH default} direction. * @param type * the traverser type, either one of * {@link Traverser#DEPTH_FIRST} and * {@link Traverser#BREADTH_FIRST} * @param startNode * the start node for the new traverser * @param traversableRels * the relationship types that the new traverser will traverse * @param stopEvaluator * the client hook for limiting the traversal size * @param returnableEvaluator * the client hook for evaluating nodes before they are returned * @throws IllegalArgumentException * if one or more of the parameters are invalid */ public Traverser createTraverser( Order traversalOrder, Node startNode, RelationshipType[] traversableRels, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator ) { if ( traversalOrder == Order.BREADTH_FIRST ) { return new BreadthFirstTraverser( startNode, traversableRels, null, null, null, // preserving rels stopEvaluator, returnableEvaluator, null ); } else if ( traversalOrder == Order.DEPTH_FIRST ) { return new DepthFirstTraverser( startNode, traversableRels, null, null, null, // preserving rels stopEvaluator, returnableEvaluator, null ); } else { throw new IllegalArgumentException( "Unknown traverser type: " + traversalOrder ); } } /** * Creates a parameterized traverser which traverses a single relationship * type. * @param type * the traverser type, either one of * {@link Traverser#DEPTH_FIRST} and * {@link Traverser#BREADTH_FIRST} * @param startNode * the start node for the new traverser * @param traversableRel * the relationship type that the new traverser will traverse * @param direction * the direction the <CODE>traversableRel</CODE> will be * traversed in * @param stopEvaluator * the client hook for limiting the traversal size * @param returnableEvaluator * the client hook for evaluating nodes before they are returned * @throws IllegalArgumentException * if one or more of the parameters are invalid */ public Traverser createTraverser( Order traversalOrder, Node startNode, RelationshipType traversableRel, Direction direction, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator ) { RelationshipType traversableRels[] = new RelationshipType[] { traversableRel }; Direction traversableDirs[] = new Direction[] { direction }; if ( traversalOrder == Order.BREADTH_FIRST ) { return new BreadthFirstTraverser( startNode, traversableRels, traversableDirs, null, null, // preserving rels stopEvaluator, returnableEvaluator, null ); } else if ( traversalOrder == Order.DEPTH_FIRST ) { return new DepthFirstTraverser( startNode, traversableRels, traversableDirs, null, null, // preserving rels stopEvaluator, returnableEvaluator, null ); } else { throw new IllegalArgumentException( "Unknown traverser type: " + traversalOrder ); } } public Traverser createTraverser( Order traversalOrder, Node startNode, RelationshipType[] traversableRels, Direction[] traversableDirs, StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator, RandomEvaluator randomEvaluator ) { if ( traversableRels == null || traversableDirs == null ) { throw new IllegalArgumentException( "Using this constructor requires that traversable " + "relationships array and traversable directions array " + "isn't null: travRels[" + Arrays.toString( traversableRels ) + "] " + "travDirs[" + Arrays.toString( traversableDirs ) + "]" ); } if ( traversableRels.length != traversableDirs.length ) { throw new IllegalArgumentException( "Length of traversable relationships array isn't equal to " + "length of traversable directions array: " + "travRels.length[" + traversableRels.length + "] != " + "travDirs.length[" + traversableDirs.length + "]" ); } if ( traversalOrder == Order.BREADTH_FIRST ) { return new BreadthFirstTraverser( startNode, traversableRels, traversableDirs, null, null, // preserving rels stopEvaluator, returnableEvaluator, randomEvaluator ); } else if ( traversalOrder == Order.DEPTH_FIRST ) { return new DepthFirstTraverser( startNode, traversableRels, traversableDirs, null, null, // preserving rels stopEvaluator, returnableEvaluator, randomEvaluator ); } else { throw new IllegalArgumentException( "Unknown traverser type: " + traversalOrder ); } } }