/**
* Copyright (c) 2002-2010 "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.Iterator;
import java.util.LinkedList;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.TraversalBranch;
import org.neo4j.kernel.Traversal;
public class TraversalPath implements Path
{
private final TraversalBranch branch;
private LinkedList<Node> nodes;
private LinkedList<Relationship> relationships;
TraversalPath( TraversalBranch branch )
{
this.branch = branch;
}
private void ensureEntitiesAreGathered()
{
if ( nodes == null )
{
// We don't synchronize on nodes/relationship... and that's fine
// because even if there would be a situation where two (or more)
// threads comes here at the same time everything would still
// work as expected (in here as well as outside).
LinkedList<Node> nodesList = new LinkedList<Node>();
LinkedList<Relationship> relationshipsList = new LinkedList<Relationship>();
TraversalBranch stepper = branch;
while ( stepper != null )
{
nodesList.addFirst( stepper.node() );
Relationship relationship = stepper.relationship();
if (relationship != null)
{
relationshipsList.addFirst( relationship );
}
stepper = stepper.parent();
}
nodes = nodesList;
relationships = relationshipsList;
}
}
public Node startNode()
{
ensureEntitiesAreGathered();
return nodes.getFirst();
}
public Node endNode()
{
return branch.node();
}
public Relationship lastRelationship()
{
return branch.relationship();
}
public Iterable<Node> nodes()
{
ensureEntitiesAreGathered();
return nodes;
}
public Iterable<Relationship> relationships()
{
ensureEntitiesAreGathered();
return relationships;
}
public Iterator<PropertyContainer> iterator()
{
ensureEntitiesAreGathered();
return new Iterator<PropertyContainer>()
{
Iterator<? extends PropertyContainer> current = nodes().iterator();
Iterator<? extends PropertyContainer> next = relationships().iterator();
public boolean hasNext()
{
return current.hasNext();
}
public PropertyContainer next()
{
try
{
return current.next();
}
finally
{
Iterator<? extends PropertyContainer> temp = current;
current = next;
next = temp;
}
}
public void remove()
{
next.remove();
}
};
}
public int length()
{
return branch.depth();
}
@Override
public String toString()
{
return Traversal.defaultPathToString( this );
}
@Override
public int hashCode()
{
ensureEntitiesAreGathered();
if ( relationships.isEmpty() )
{
return startNode().hashCode();
}
else
{
return relationships.hashCode();
}
}
@Override
public boolean equals( Object obj )
{
ensureEntitiesAreGathered();
if ( this == obj )
{
return true;
}
else if ( obj instanceof TraversalPath )
{
TraversalPath other = (TraversalPath) obj;
return startNode().equals( other.startNode() )
&& relationships.equals( other.relationships );
}
else if ( obj instanceof Path )
{
Path other = (Path) obj;
if ( startNode().equals( other.startNode() ) )
{
Iterator<Relationship> these = relationships().iterator();
Iterator<Relationship> those = other.relationships().iterator();
while ( these.hasNext() && those.hasNext() )
{
if ( !these.next().equals( those.next() ) )
{
return false;
}
}
if ( these.hasNext() || those.hasNext() )
{
return false;
}
return true;
}
}
return false;
}
}