package org.neo4j.util;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.neo4j.kernel.impl.transaction.IllegalResourceException;
import org.neo4j.kernel.impl.transaction.LockManager;
public abstract class AbstractLink<T> implements Link<T>
{
private final GraphDatabaseService graphDb;
private final Node node;
private final RelationshipType type;
private final Direction direction;
public AbstractLink( GraphDatabaseService graphDb, Node node, RelationshipType type,
Direction direction )
{
this.graphDb = graphDb;
this.node = node;
this.type = type;
this.direction = direction;
}
public AbstractLink( GraphDatabaseService graphDb, Node node, RelationshipType type )
{
this( graphDb, node, type, Direction.OUTGOING );
}
protected GraphDatabaseService graphDb()
{
return this.graphDb;
}
protected Node node()
{
return this.node;
}
protected Direction direction()
{
return this.direction;
}
protected RelationshipType type()
{
return this.type;
}
protected abstract T newObject( Node node );
private T newObject( Relationship relationship )
{
return newObject( relationship.getOtherNode( this.node ) );
}
protected abstract Node getNodeFromItem( T item );
protected Relationship getLinkRelationshipOrNull()
{
return this.node.getSingleRelationship( this.type(),
this.direction() );
}
public T get()
{
Transaction tx = graphDb.beginTx();
try
{
Relationship relationship = getLinkRelationshipOrNull();
T result = relationship == null ? null : newObject( relationship );
tx.success();
return result;
}
finally
{
tx.finish();
}
}
public boolean has()
{
Transaction tx = graphDb.beginTx();
try
{
boolean result = getLinkRelationshipOrNull() != null;
tx.success();
return result;
}
finally
{
tx.finish();
}
}
public T remove()
{
Transaction tx = graphDb.beginTx();
try
{
Relationship relationship = getLinkRelationshipOrNull();
T result = null;
if ( relationship != null )
{
result = newObject( relationship );
entityRemoved( result, relationship );
relationship.delete();
}
tx.success();
return result;
}
finally
{
tx.finish();
}
}
public T set( T object )
{
Transaction tx = graphDb.beginTx();
LockManager lockManager =
( ( EmbeddedGraphDatabase ) graphDb ).getConfig().getLockManager();
try
{
lockManager.getWriteLock( this.node() );
Relationship existingRelationship = getLinkRelationshipOrNull();
T existingObject = null;
if ( existingRelationship != null )
{
existingObject = newObject( existingRelationship );
entityRemoved( existingObject, existingRelationship );
existingRelationship.delete();
}
Node entityNode = getNodeFromItem( object );
Node startNode = this.direction() == Direction.OUTGOING ?
this.node() : entityNode;
Node endNode = this.direction() == Direction.OUTGOING ?
entityNode : this.node();
Relationship createdRelationship =
startNode.createRelationshipTo( endNode, this.type() );
entitySet( object, createdRelationship );
tx.success();
return existingObject;
}
catch ( IllegalResourceException e )
{
throw new RuntimeException( e );
}
finally
{
try
{
lockManager.releaseWriteLock( this.node() );
}
catch ( Exception e )
{
throw new RuntimeException( e );
}
tx.finish();
}
}
protected void entitySet( T entity, Relationship createdRelationship )
{
}
protected void entityRemoved( T entity, Relationship removedRelationship )
{
}
}