generified accessors

This commit is contained in:
Michael Hunger
2010-09-12 13:21:53 +02:00
parent 02d6201e03
commit 8896aab27b
8 changed files with 172 additions and 129 deletions

View File

@@ -1,110 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.persistence.support.EntityInstantiator;
import java.util.HashSet;
import java.util.Set;
/**
* @author Michael Hunger
* @since 11.09.2010
*/
public abstract class AbstractFieldAccessor implements FieldAccessor {
protected final RelationshipType type;
protected final Direction direction;
protected final Class<? extends NodeBacked> relatedType;
protected final EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
public AbstractFieldAccessor(Class<? extends NodeBacked> clazz, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator, Direction direction, RelationshipType type) {
this.relatedType = clazz;
this.graphEntityInstantiator = graphEntityInstantiator;
this.direction = direction;
this.type = type;
}
protected void createSingleRelationship(Node start, Node end) {
if (end==null) return;
switch(direction) {
case OUTGOING : {
obtainSingleRelationship(start, end);
break;
}
case INCOMING :
obtainSingleRelationship(end, start);
break;
default : throw new InvalidDataAccessApiUsageException("invalid direction " + direction);
}
}
private Relationship obtainSingleRelationship(Node start, Node end) {
final Relationship existingRelationship = start.getSingleRelationship(type, direction);
if (existingRelationship!=null && existingRelationship.getOtherNode(start).equals(end)) return existingRelationship;
return start.createRelationshipTo(end, type);
}
protected Node checkUnderlyingNode(NodeBacked entity) {
if (entity==null) throw new IllegalStateException("Entity is null");
Node node = entity.getUnderlyingNode();
if (node != null) return node;
throw new IllegalStateException("Entity must have a backing Node");
}
protected void removeMissingRelationships(Node node, Set<Node> targetNodes) {
for ( Relationship relationship : node.getRelationships(type, direction) ) {
if (!targetNodes.remove(relationship.getOtherNode(node)))
relationship.delete();
}
}
protected void createAddedRelationships(Node node, Set<Node> targetNodes) {
for (Node targetNode : targetNodes) {
createSingleRelationship(node,targetNode);
}
}
protected void checkNoCircularReference(Node node, Set<Node> targetNodes) {
if (targetNodes.contains(node)) throw new InvalidDataAccessApiUsageException("Cannot create a circular reference to "+ targetNodes);
}
protected Set<Node> checkTargetIsSetOfNodebacked(Object newVal) {
if (!(newVal instanceof Set)) {
throw new IllegalArgumentException("New value must be a Set, was: " + newVal.getClass());
}
Set<Node> nodes=new HashSet<Node>();
for (Object value : (Set<Object>) newVal) {
if (!(value instanceof NodeBacked)) {
throw new IllegalArgumentException("New value elements must be NodeBacked.");
}
nodes.add(((NodeBacked)value).getUnderlyingNode());
}
return nodes;
}
protected ManagedFieldAccessorSet<NodeBacked> createManagedSet(NodeBacked entity, Set<NodeBacked> result) {
return new ManagedFieldAccessorSet<NodeBacked>(entity, result, this);
}
protected Set<NodeBacked> createEntitySetFromRelationshipEndNodes(NodeBacked entity) {
final Set<Node> nodes = getStatesFromEntity(entity);
final Set<NodeBacked> result = new HashSet<NodeBacked>();
for (final Node otherNode : nodes) {
result.add(graphEntityInstantiator.createEntityFromState(otherNode, relatedType));
}
return result;
}
private Set<Node> getStatesFromEntity(NodeBacked entity) {
final Node entityNode = entity.getUnderlyingNode();
final Set<Node> result = new HashSet<Node>();
for (final Relationship rel : entityNode.getRelationships(type, direction)) {
result.add(rel.getOtherNode(entityNode));
}
return result;
}
}

View File

@@ -0,0 +1,102 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.persistence.support.EntityInstantiator;
import java.util.HashSet;
import java.util.Set;
/**
* @author Michael Hunger
* @since 11.09.2010
*/
public abstract class AbstractRelationshipFieldAccessor<ENTITY,STATE,TARGET,TSTATE> implements FieldAccessor<ENTITY,TARGET> {
protected final RelationshipType type;
protected final Direction direction;
protected final Class<? extends TARGET> relatedType;
protected final EntityInstantiator<TARGET, TSTATE> graphEntityInstantiator;
public AbstractRelationshipFieldAccessor(Class<? extends TARGET> clazz, EntityInstantiator<TARGET, TSTATE> graphEntityInstantiator, Direction direction, RelationshipType type) {
this.relatedType = clazz;
this.graphEntityInstantiator = graphEntityInstantiator;
this.direction = direction;
this.type = type;
}
protected STATE checkUnderlyingNode(ENTITY entity) {
if (entity==null) throw new IllegalStateException("Entity is null");
STATE node = getState(entity);
if (node != null) return node;
throw new IllegalStateException("Entity must have a backing Node");
}
protected void removeMissingRelationships(Node node, Set<Node> targetNodes) {
for ( Relationship relationship : node.getRelationships(type, direction) ) {
if (!targetNodes.remove(relationship.getOtherNode(node)))
relationship.delete();
}
}
protected void createAddedRelationships(STATE node, Set<TSTATE> targetNodes) {
for (TSTATE targetNode : targetNodes) {
createSingleRelationship(node,targetNode);
}
}
protected void checkNoCircularReference(Node node, Set<STATE> targetNodes) {
if (targetNodes.contains(node)) throw new InvalidDataAccessApiUsageException("Cannot create a circular reference to "+ targetNodes);
}
protected Set<STATE> checkTargetIsSetOfNodebacked(Object newVal) {
if (!(newVal instanceof Set)) {
throw new IllegalArgumentException("New value must be a Set, was: " + newVal.getClass());
}
Set<STATE> nodes=new HashSet<STATE>();
for (Object value : (Set<Object>) newVal) {
if (!relatedType.isInstance(value)) {
throw new IllegalArgumentException("New value elements must be "+relatedType);
}
nodes.add(getState((ENTITY)value));
}
return nodes;
}
protected ManagedFieldAccessorSet<ENTITY,TARGET> createManagedSet(ENTITY entity, Set<TARGET> result) {
return new ManagedFieldAccessorSet<ENTITY,TARGET>(entity, result, this);
}
protected Set<TARGET> createEntitySetFromRelationshipEndNodes(ENTITY entity) {
final Iterable<TSTATE> nodes = getStatesFromEntity(entity);
final Set<TARGET> result = new HashSet<TARGET>();
for (final TSTATE otherNode : nodes) {
result.add(graphEntityInstantiator.createEntityFromState(otherNode, relatedType));
}
return result;
}
protected void createSingleRelationship(STATE start, TSTATE end) {
if (end==null) return;
switch(direction) {
case OUTGOING : {
obtainSingleRelationship(start, end);
break;
}
case INCOMING :
obtainSingleRelationship((STATE)end, (TSTATE)start);
break;
default : throw new InvalidDataAccessApiUsageException("invalid direction " + direction);
}
}
protected abstract Relationship obtainSingleRelationship(STATE start, TSTATE end);
protected abstract Iterable<TSTATE> getStatesFromEntity(ENTITY entity);
protected abstract STATE getState(ENTITY entity);
}

View File

@@ -2,10 +2,10 @@ package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.datastore.graph.api.NodeBacked;
public interface FieldAccessor {
public interface FieldAccessor<ENTITY, TARGET> {
Object setValue(NodeBacked entity, Object newVal);
Object setValue(ENTITY entity, Object newVal);
Object getValue(NodeBacked entity);
Object getValue(ENTITY entity);
}

View File

@@ -10,12 +10,12 @@ import java.util.Set;
* TODO handle all mutating methods
* @param <T>
*/
public class ManagedFieldAccessorSet<T> extends AbstractSet<T> {
private final NodeBacked entity;
public class ManagedFieldAccessorSet<ENTITY,T> extends AbstractSet<T> {
private final ENTITY entity;
final Set<T> delegate;
private final FieldAccessor fieldAccessor;
private final FieldAccessor<ENTITY,T> fieldAccessor;
public ManagedFieldAccessorSet(final NodeBacked entity, final Object newVal, final FieldAccessor fieldAccessor) {
public ManagedFieldAccessorSet(final ENTITY entity, final Object newVal, final FieldAccessor fieldAccessor) {
this.entity = entity;
this.fieldAccessor = fieldAccessor;
delegate = (Set<T>) newVal;

View File

@@ -0,0 +1,43 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.persistence.support.EntityInstantiator;
import java.util.HashSet;
import java.util.Set;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public abstract class NodeToNodesRelationshipFieldAccessor<TARGET> extends AbstractRelationshipFieldAccessor<NodeBacked, Node, TARGET, Node> {
public NodeToNodesRelationshipFieldAccessor(Class<? extends TARGET> clazz, EntityInstantiator<TARGET, Node> graphEntityInstantiator, Direction direction, RelationshipType type) {
super(clazz, graphEntityInstantiator, direction, type);
}
@Override
protected Relationship obtainSingleRelationship(Node start, Node end) {
final Relationship existingRelationship = start.getSingleRelationship(type, direction);
if (existingRelationship!=null && existingRelationship.getOtherNode(start).equals(end)) return existingRelationship;
return start.createRelationshipTo(end, type);
}
@Override
protected Iterable<Node> getStatesFromEntity(NodeBacked entity) {
final Node entityNode = getState(entity);
final Set<Node> result = new HashSet<Node>();
for (final Relationship rel : entityNode.getRelationships(type, direction)) {
result.add(rel.getOtherNode(entityNode));
}
return result;
}
@Override
protected Node getState(NodeBacked entity) {
return entity.getUnderlyingNode();
}
}

View File

@@ -4,6 +4,7 @@ import java.util.HashSet;
import java.util.Set;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.dao.InvalidDataAccessApiUsageException;
@@ -11,15 +12,10 @@ import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.api.RelationshipBacked;
import org.springframework.persistence.support.EntityInstantiator;
public class OneToNRelationshipEntityFieldAccessor extends AbstractFieldAccessor {
private final Class<? extends RelationshipBacked> elementClass;
private final EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator;
public class OneToNRelationshipEntityFieldAccessor extends AbstractRelationshipFieldAccessor<NodeBacked, Node, RelationshipBacked,Relationship> {
public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends RelationshipBacked> elementClass, final EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator) {
super(null,null,direction,type);
this.elementClass = elementClass;
this.relationshipEntityInstantiator = relationshipEntityInstantiator;
super(elementClass,relationshipEntityInstantiator,direction,type);
}
@Override
@@ -31,18 +27,29 @@ public class OneToNRelationshipEntityFieldAccessor extends AbstractFieldAccessor
public Object getValue(final NodeBacked entity) {
checkUnderlyingNode(entity);
final Set<RelationshipBacked> result = createEntitySetFromRelationships(entity);
return new ManagedFieldAccessorSet<RelationshipBacked>(entity, result, this);
return new ManagedFieldAccessorSet<NodeBacked, RelationshipBacked>(entity, result, this);
}
private Set<RelationshipBacked> createEntitySetFromRelationships(final NodeBacked entity) {
final Set<RelationshipBacked> result = new HashSet<RelationshipBacked>();
for (final Relationship rel : getStatesFromEntity(entity)) {
result.add(relationshipEntityInstantiator.createEntityFromState(rel, elementClass));
result.add(graphEntityInstantiator.createEntityFromState(rel, relatedType));
}
return result;
}
private Iterable<Relationship> getStatesFromEntity(NodeBacked entity) {
@Override
protected Iterable<Relationship> getStatesFromEntity(NodeBacked entity) {
return entity.getUnderlyingNode().getRelationships(type, direction);
}
@Override
protected Relationship obtainSingleRelationship(Node start, Relationship end) {
return null;
}
@Override
protected Node getState(NodeBacked nodeBacked) {
return nodeBacked.getUnderlyingNode();
}
}

View File

@@ -9,7 +9,7 @@ import org.neo4j.graphdb.RelationshipType;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.persistence.support.EntityInstantiator;
public class OneToNRelationshipFieldAccessor extends AbstractFieldAccessor {
public class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
super(elementClass, graphEntityInstantiator, direction, type);

View File

@@ -4,12 +4,13 @@ import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.api.RelationshipBacked;
import org.springframework.persistence.support.EntityInstantiator;
import java.util.Collections;
import java.util.Set;
public class SingleRelationshipFieldAccessor extends AbstractFieldAccessor {
public class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> clazz, final EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
super(clazz, graphEntityInstantiator, direction, type);
}