diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/AbstractFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/AbstractFieldAccessor.java deleted file mode 100644 index 0431c9d0d..000000000 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/AbstractFieldAccessor.java +++ /dev/null @@ -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 relatedType; - protected final EntityInstantiator graphEntityInstantiator; - - public AbstractFieldAccessor(Class clazz, EntityInstantiator 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 targetNodes) { - for ( Relationship relationship : node.getRelationships(type, direction) ) { - if (!targetNodes.remove(relationship.getOtherNode(node))) - relationship.delete(); - } - } - - protected void createAddedRelationships(Node node, Set targetNodes) { - for (Node targetNode : targetNodes) { - createSingleRelationship(node,targetNode); - } - } - - protected void checkNoCircularReference(Node node, Set targetNodes) { - if (targetNodes.contains(node)) throw new InvalidDataAccessApiUsageException("Cannot create a circular reference to "+ targetNodes); - } - - protected Set checkTargetIsSetOfNodebacked(Object newVal) { - if (!(newVal instanceof Set)) { - throw new IllegalArgumentException("New value must be a Set, was: " + newVal.getClass()); - } - Set nodes=new HashSet(); - for (Object value : (Set) newVal) { - if (!(value instanceof NodeBacked)) { - throw new IllegalArgumentException("New value elements must be NodeBacked."); - } - nodes.add(((NodeBacked)value).getUnderlyingNode()); - } - return nodes; - } - - protected ManagedFieldAccessorSet createManagedSet(NodeBacked entity, Set result) { - return new ManagedFieldAccessorSet(entity, result, this); - } - - protected Set createEntitySetFromRelationshipEndNodes(NodeBacked entity) { - final Set nodes = getStatesFromEntity(entity); - final Set result = new HashSet(); - for (final Node otherNode : nodes) { - result.add(graphEntityInstantiator.createEntityFromState(otherNode, relatedType)); - } - return result; - } - - private Set getStatesFromEntity(NodeBacked entity) { - final Node entityNode = entity.getUnderlyingNode(); - final Set result = new HashSet(); - for (final Relationship rel : entityNode.getRelationships(type, direction)) { - result.add(rel.getOtherNode(entityNode)); - } - return result; - } -} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/AbstractRelationshipFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/AbstractRelationshipFieldAccessor.java new file mode 100644 index 000000000..3437a29b8 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/AbstractRelationshipFieldAccessor.java @@ -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 implements FieldAccessor { + protected final RelationshipType type; + protected final Direction direction; + protected final Class relatedType; + protected final EntityInstantiator graphEntityInstantiator; + + public AbstractRelationshipFieldAccessor(Class clazz, EntityInstantiator 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 targetNodes) { + for ( Relationship relationship : node.getRelationships(type, direction) ) { + if (!targetNodes.remove(relationship.getOtherNode(node))) + relationship.delete(); + } + } + + protected void createAddedRelationships(STATE node, Set targetNodes) { + for (TSTATE targetNode : targetNodes) { + createSingleRelationship(node,targetNode); + } + } + + protected void checkNoCircularReference(Node node, Set targetNodes) { + if (targetNodes.contains(node)) throw new InvalidDataAccessApiUsageException("Cannot create a circular reference to "+ targetNodes); + } + + protected Set checkTargetIsSetOfNodebacked(Object newVal) { + if (!(newVal instanceof Set)) { + throw new IllegalArgumentException("New value must be a Set, was: " + newVal.getClass()); + } + Set nodes=new HashSet(); + for (Object value : (Set) newVal) { + if (!relatedType.isInstance(value)) { + throw new IllegalArgumentException("New value elements must be "+relatedType); + } + nodes.add(getState((ENTITY)value)); + } + return nodes; + } + + protected ManagedFieldAccessorSet createManagedSet(ENTITY entity, Set result) { + return new ManagedFieldAccessorSet(entity, result, this); + } + + protected Set createEntitySetFromRelationshipEndNodes(ENTITY entity) { + final Iterable nodes = getStatesFromEntity(entity); + final Set result = new HashSet(); + 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 getStatesFromEntity(ENTITY entity); + + protected abstract STATE getState(ENTITY entity); +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/FieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/FieldAccessor.java index fbed48ba2..4963e14b7 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/FieldAccessor.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/FieldAccessor.java @@ -2,10 +2,10 @@ package org.springframework.datastore.graph.neo4j.fieldaccess; import org.springframework.datastore.graph.api.NodeBacked; -public interface FieldAccessor { +public interface FieldAccessor { - Object setValue(NodeBacked entity, Object newVal); + Object setValue(ENTITY entity, Object newVal); - Object getValue(NodeBacked entity); + Object getValue(ENTITY entity); } diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ManagedFieldAccessorSet.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ManagedFieldAccessorSet.java index b2c02674e..b3c2de3fc 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ManagedFieldAccessorSet.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/ManagedFieldAccessorSet.java @@ -10,12 +10,12 @@ import java.util.Set; * TODO handle all mutating methods * @param */ -public class ManagedFieldAccessorSet extends AbstractSet { - private final NodeBacked entity; +public class ManagedFieldAccessorSet extends AbstractSet { + private final ENTITY entity; final Set delegate; - private final FieldAccessor fieldAccessor; + private final FieldAccessor 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) newVal; diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java new file mode 100644 index 000000000..0410f9341 --- /dev/null +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java @@ -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 extends AbstractRelationshipFieldAccessor { + public NodeToNodesRelationshipFieldAccessor(Class clazz, EntityInstantiator 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 getStatesFromEntity(NodeBacked entity) { + final Node entityNode = getState(entity); + final Set result = new HashSet(); + for (final Relationship rel : entityNode.getRelationships(type, direction)) { + result.add(rel.getOtherNode(entityNode)); + } + return result; + } + + @Override + protected Node getState(NodeBacked entity) { + return entity.getUnderlyingNode(); + } +} diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessor.java index b08e9eeda..52fcfbc2d 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessor.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessor.java @@ -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 elementClass; - private final EntityInstantiator relationshipEntityInstantiator; +public class OneToNRelationshipEntityFieldAccessor extends AbstractRelationshipFieldAccessor { public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final EntityInstantiator 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 result = createEntitySetFromRelationships(entity); - return new ManagedFieldAccessorSet(entity, result, this); + return new ManagedFieldAccessorSet(entity, result, this); } private Set createEntitySetFromRelationships(final NodeBacked entity) { final Set result = new HashSet(); for (final Relationship rel : getStatesFromEntity(entity)) { - result.add(relationshipEntityInstantiator.createEntityFromState(rel, elementClass)); + result.add(graphEntityInstantiator.createEntityFromState(rel, relatedType)); } return result; } - private Iterable getStatesFromEntity(NodeBacked entity) { + @Override + protected Iterable 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(); + } } diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessor.java index 652371a9c..1758b1ed7 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessor.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessor.java @@ -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 { public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class elementClass, final EntityInstantiator graphEntityInstantiator) { super(elementClass, graphEntityInstantiator, direction, type); diff --git a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessor.java b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessor.java index e3fb92a38..8a371e4af 100644 --- a/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessor.java +++ b/src/main/java/org/springframework/datastore/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessor.java @@ -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 { public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class clazz, final EntityInstantiator graphEntityInstantiator) { super(clazz, graphEntityInstantiator, direction, type); }