/*
* Copyright (c) 2008-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.remote;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotFoundException;
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;
final class RemoteNode extends RemotePropertyContainer implements Node
{
RemoteNode( RemoteGraphDbEngine txService, long id )
{
super( txService, id );
}
@Override
public int hashCode()
{
return ( int ) id;
}
@Override
public boolean equals( Object obj )
{
if ( obj instanceof RemoteNode )
{
RemoteNode node = ( RemoteNode ) obj;
return node.id == id && node.engine.equals( engine );
}
else
{
return false;
}
}
@Override
public String toString()
{
return "Node[" + id + "]";
}
public Relationship createRelationshipTo( Node otherNode,
RelationshipType type )
{
if ( otherNode instanceof RemoteNode )
{
RemoteNode other = ( RemoteNode ) otherNode;
if ( other.engine.equals( engine ) )
{
return engine.current().createRelationship( type, this, other );
}
}
throw new IllegalArgumentException(
"Other node not in same node space." );
}
public void delete()
{
engine.current().deleteNode( this );
}
public long getId()
{
return id;
}
public Iterable<Relationship> getRelationships()
{
return engine.current().getRelationships( this, Direction.BOTH,
( ( RelationshipType[] ) null ) );
}
public Iterable<Relationship> getRelationships( RelationshipType... types )
{
return engine.current().getRelationships( this, Direction.BOTH,
( types == null ? types : new RelationshipType[ 0 ] ) );
}
public Iterable<Relationship> getRelationships( Direction dir )
{
return engine.current().getRelationships( this, dir,
( ( RelationshipType[] ) null ) );
}
public Iterable<Relationship> getRelationships( RelationshipType type,
Direction dir )
{
RelationshipType[] types = { type };
return engine.current().getRelationships( this, dir, types );
}
public Relationship getSingleRelationship( RelationshipType type,
Direction dir )
{
Iterator<Relationship> relations = getRelationships( type, dir )
.iterator();
if ( !relations.hasNext() )
{
return null;
}
else
{
Relationship relation = relations.next();
if ( relations.hasNext() )
{
throw new NotFoundException( "More then one relationship["
+ type + "] found" );
}
return relation;
}
}
public boolean hasRelationship()
{
return getRelationships().iterator().hasNext();
}
public boolean hasRelationship( RelationshipType... types )
{
return getRelationships( types ).iterator().hasNext();
}
public boolean hasRelationship( Direction dir )
{
return getRelationships( dir ).iterator().hasNext();
}
public boolean hasRelationship( RelationshipType type, Direction dir )
{
return getRelationships( type, dir ).iterator().hasNext();
}
/*
* NOTE: traversers are harder to build up remotely. Maybe traversal should
* be done on the client side, using the regular primitive accessors.
*/
public Traverser traverse( Order traversalOrder,
StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator,
RelationshipType relationshipType, Direction direction )
{
return traversal( traversalOrder, stopEvaluator, returnableEvaluator,
new RelationshipType[] { relationshipType },
new Direction[] { direction } );
}
public Traverser traverse( Order traversalOrder,
StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator,
RelationshipType firstRelationshipType, Direction firstDirection,
RelationshipType secondRelationshipType, Direction secondDirection )
{
return traversal( traversalOrder, stopEvaluator, returnableEvaluator,
new RelationshipType[] { firstRelationshipType,
secondRelationshipType }, new Direction[] { firstDirection,
secondDirection } );
}
public Traverser traverse( Order traversalOrder,
StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator,
Object... relationshipTypesAndDirections )
{
if ( relationshipTypesAndDirections.length % 2 != 0 )
{
throw new IllegalArgumentException(
"Not as many directions as relationship types." );
}
RelationshipType[] relationshipTypes = new RelationshipType[ relationshipTypesAndDirections.length / 2 ];
Direction[] directions = new Direction[ relationshipTypesAndDirections.length / 2 ];
for ( int i = 0, j = 0; j < directions.length; i += 2, j++ )
{
try
{
relationshipTypes[ j ] = ( RelationshipType ) relationshipTypesAndDirections[ i ];
}
catch ( ClassCastException ex )
{
throw new IllegalArgumentException( "Not a RelationshipType: "
+ relationshipTypesAndDirections[ i ] );
}
try
{
directions[ j ] = ( Direction ) relationshipTypesAndDirections[ i + 1 ];
}
catch ( ClassCastException ex )
{
throw new IllegalArgumentException( "Not a Direction: "
+ relationshipTypesAndDirections[ i + 1 ] );
}
}
return traversal( traversalOrder, stopEvaluator, returnableEvaluator,
relationshipTypes, directions );
}
@Override
Object getContainerProperty( String key )
{
return engine.current().getProperty( this, key );
}
public Iterable<String> getPropertyKeys()
{
return engine.current().getPropertyKeys( this );
}
public boolean hasProperty( String key )
{
return engine.current().hasProperty( this, key );
}
public Object removeProperty( String key )
{
return engine.current().removeProperty( this, key );
}
public void setProperty( String key, Object value )
{
engine.current().setProperty( this, key, value );
}
private Traverser traversal( Order traversalOrder,
StopEvaluator stopEvaluator, ReturnableEvaluator returnableEvaluator,
RelationshipType[] relationshipTypes, Direction[] directions )
{
final Iterable<TraversalPosition> positions = engine.current()
.traverse( this, traversalOrder, stopEvaluator,
returnableEvaluator, relationshipTypes, directions );
return new Traverser()
{
Iterator<TraversalPosition> iter = positions.iterator();
TraversalPosition last = null;
TraversalPosition current = null;
public TraversalPosition currentPosition()
{
return last;
}
public Collection<Node> getAllNodes()
{
Collection<Node> result = new LinkedList<Node>();
for ( Node node : this )
{
result.add( node );
}
return result;
}
public Iterator<Node> iterator()
{
return new Iterator<Node>()
{
public boolean hasNext()
{
if ( current != null )
{
return true;
}
else if ( iter.hasNext() )
{
current = iter.next();
return true;
}
else
{
return false;
}
}
public Node next()
{
if ( hasNext() )
{
last = current;
current = null;
return last.currentNode();
}
else
{
throw new NoSuchElementException();
}
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
};
}
}