Intermediate step in refactoring of FieldAccessorFactories.

This commit is contained in:
David Montag
2010-09-17 11:21:08 -07:00
parent d85b7bda3f
commit ec8a0bbf46
21 changed files with 644 additions and 666 deletions

View File

@@ -1,78 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.core.convert.ConversionService;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.api.RelationshipBacked;
import java.lang.reflect.Field;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
@Configurable
public class ConvertingNodePropertyFieldAccessor extends NodePropertyFieldAccessor {
private final ConversionService conversionService;
public ConvertingNodePropertyFieldAccessor(final Field field, final ConversionService conversionService) {
super(field);
this.conversionService = conversionService;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
super.setValue(nodeBacked, serializePropertyValue(newVal));
return newVal;
}
@Override
public Object doGetValue(final NodeBacked nodeBacked) {
return deserializePropertyValue(super.doGetValue(nodeBacked));
}
private Object serializePropertyValue(final Object newVal) {
return conversionService.convert(newVal, String.class);
}
private Object deserializePropertyValue(final Object value) {
return conversionService.convert(value, field.getType());
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new ConvertingNodePropertyFieldAccessorFactory();
}
@Configurable
private static class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Autowired
ConversionService conversionService;
@Override
public boolean accept(final Field field) {
return isSerializableField(field) && isDeserializableField(field);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
return new ConvertingNodePropertyFieldAccessor(field, conversionService);
}
private boolean isSerializableField(final Field field) {
return isSimpleValueField(field) && conversionService.canConvert(field.getType(), String.class);
}
private boolean isDeserializableField(final Field field) {
return isSimpleValueField(field) && conversionService.canConvert(String.class, field.getType());
}
private boolean isSimpleValueField(final Field field) {
final Class<?> type = field.getType();
if (Iterable.class.isAssignableFrom(type) || NodeBacked.class.isAssignableFrom(type) || RelationshipBacked.class.isAssignableFrom(type))
return false;
return true;
}
}
}

View File

@@ -0,0 +1,75 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.core.convert.ConversionService;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.api.RelationshipBacked;
import java.lang.reflect.Field;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
@Configurable
public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Autowired
ConversionService conversionService;
@Override
public boolean accept(final Field field) {
return isSerializableField(field) && isDeserializableField(field);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
return new ConvertingNodePropertyFieldAccessor(field, conversionService);
}
private boolean isSerializableField(final Field field) {
return isSimpleValueField(field) && conversionService.canConvert(field.getType(), String.class);
}
private boolean isDeserializableField(final Field field) {
return isSimpleValueField(field) && conversionService.canConvert(String.class, field.getType());
}
private boolean isSimpleValueField(final Field field) {
final Class<?> type = field.getType();
if (Iterable.class.isAssignableFrom(type) || NodeBacked.class.isAssignableFrom(type) || RelationshipBacked.class.isAssignableFrom(type))
return false;
return true;
}
@Configurable
public static class ConvertingNodePropertyFieldAccessor extends NodePropertyFieldAccessorFactory.NodePropertyFieldAccessor {
private final ConversionService conversionService;
public ConvertingNodePropertyFieldAccessor(final Field field, final ConversionService conversionService) {
super(field);
this.conversionService = conversionService;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
super.setValue(nodeBacked, serializePropertyValue(newVal));
return newVal;
}
@Override
public Object doGetValue(final NodeBacked nodeBacked) {
return deserializePropertyValue(super.doGetValue(nodeBacked));
}
private Object serializePropertyValue(final Object newVal) {
return conversionService.convert(newVal, String.class);
}
private Object deserializePropertyValue(final Object value) {
return conversionService.convert(value, field.getType());
}
}
}

View File

@@ -26,18 +26,18 @@ public class DelegatingFieldAccessorFactory<T> implements FieldAccessorFactory<T
}
final Collection<FieldAccessorFactory<?>> fieldAccessorFactories = Arrays.<FieldAccessorFactory<?>>asList(
IdFieldAccessor.factory(),
TransientFieldAccessor.factory(),
NodePropertyFieldAccessor.factory(),
ConvertingNodePropertyFieldAccessor.factory(),
SingleRelationshipFieldAccessor.factory(),
OneToNRelationshipFieldAccessor.factory(),
ReadOnlyOneToNRelationshipFieldAccessor.factory(),
TraversalFieldAccessor.factory(),
OneToNRelationshipEntityFieldAccessor.factory()
new IdFieldAccessorFactory(),
new TransientFieldAccessorFactory(),
new NodePropertyFieldAccessorFactory(),
new ConvertingNodePropertyFieldAccessorFactory(),
new SingleRelationshipFieldAccessorFactory(),
new OneToNRelationshipFieldAccessorFactory(),
new ReadOnlyOneToNRelationshipFieldAccessorFactory(),
new TraversalFieldAccessorFactory(),
new OneToNRelationshipEntityFieldAccessorFactory()
);
final Collection<FieldAccessorListenerFactory<?>> fieldAccessorListenerFactories = Arrays.<FieldAccessorListenerFactory<?>>asList(
IndexingNodePropertyFieldAccessorListener.factory()
final Collection<FieldAccessorListenerFactory<?>> fieldAccessorListenerFactories = Arrays.<FieldAccessorListenerFactory<?>>asList(
IndexingNodePropertyFieldAccessorListenerFactory.IndexingNodePropertyFieldAccessorListener.factory()
);
public FieldAccessor forField(Field field) {

View File

@@ -1,55 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.datastore.graph.api.NodeBacked;
import java.lang.reflect.Field;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public class IdFieldAccessor implements FieldAccessor<NodeBacked, Object> {
protected final Field field;
public IdFieldAccessor(final Field field) {
this.field = field;
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
return doReturn(null);
}
@Override
public Object getValue(final NodeBacked nodeBacked) {
return doReturn(nodeBacked.getUnderlyingNode().getId());
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new FieldAccessorFactory<NodeBacked>() {
@Override
public boolean accept(final Field f) {
return isIdField(f);
}
private boolean isIdField(Field field) {
if (!field.getName().equals("id")) return false;
final Class<?> type = field.getType();
return type.equals(Long.class) || type.equals(long.class);
}
@Override
public FieldAccessor<NodeBacked,?> forField(final Field field) {
return new IdFieldAccessor(field);
}
};
}
}

View File

@@ -0,0 +1,53 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.datastore.graph.api.NodeBacked;
import java.lang.reflect.Field;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public class IdFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Override
public boolean accept(final Field f) {
return isIdField(f);
}
private boolean isIdField(Field field) {
if (!field.getName().equals("id")) return false;
final Class<?> type = field.getType();
return type.equals(Long.class) || type.equals(long.class);
}
@Override
public FieldAccessor<NodeBacked,?> forField(final Field field) {
return new IdFieldAccessor(field);
}
public static class IdFieldAccessor implements FieldAccessor<NodeBacked, Object> {
protected final Field field;
public IdFieldAccessor(final Field field) {
this.field = field;
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
return doReturn(null);
}
@Override
public Object getValue(final NodeBacked nodeBacked) {
return doReturn(nodeBacked.getUnderlyingNode().getId());
}
}
}

View File

@@ -1,53 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.index.IndexService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.datastore.graph.api.NodeBacked;
import java.lang.reflect.Field;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public class IndexingNodePropertyFieldAccessorListener implements FieldAccessListener<NodeBacked, Object> {
protected final Field field;
private final IndexService indexService;
public IndexingNodePropertyFieldAccessorListener(final Field field, final IndexService indexService) {
this.field = field;
this.indexService = indexService;
}
@Override
public void valueChanged(final NodeBacked nodeBacked, final Object oldVal, final Object newVal) {
if (newVal==null) indexService.removeIndex(nodeBacked.getUnderlyingNode(),getPropertyName());
else indexService.index(nodeBacked.getUnderlyingNode(), getPropertyName(),newVal);
}
// todo
private String getPropertyName() {
return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field);
}
public static FieldAccessorListenerFactory<NodeBacked> factory() {
return new NodeBackedFieldAccessorListenerFactory();
}
@Configurable
private static class NodeBackedFieldAccessorListenerFactory implements FieldAccessorListenerFactory<NodeBacked> {
@Autowired
IndexService indexService;
@Override
public boolean accept(final Field f) {
return NodePropertyFieldAccessor.factory().accept(f) || ConvertingNodePropertyFieldAccessor.factory().accept(f);
}
@Override
public FieldAccessListener<NodeBacked,?> forField(final Field field) {
return new IndexingNodePropertyFieldAccessorListener(field,indexService);
}
}
}

View File

@@ -0,0 +1,54 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.index.IndexService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.datastore.graph.api.NodeBacked;
import java.lang.reflect.Field;
@Configurable
class IndexingNodePropertyFieldAccessorListenerFactory implements FieldAccessorListenerFactory<NodeBacked> {
@Autowired
IndexService indexService;
@Override
public boolean accept(final Field f) {
return new NodePropertyFieldAccessorFactory().accept(f) || new ConvertingNodePropertyFieldAccessorFactory().accept(f);
}
@Override
public FieldAccessListener<NodeBacked,?> forField(final Field field) {
return new IndexingNodePropertyFieldAccessorListener(field,indexService);
}
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public static class IndexingNodePropertyFieldAccessorListener implements FieldAccessListener<NodeBacked, Object> {
protected final Field field;
private final IndexService indexService;
public IndexingNodePropertyFieldAccessorListener(final Field field, final IndexService indexService) {
this.field = field;
this.indexService = indexService;
}
@Override
public void valueChanged(final NodeBacked nodeBacked, final Object oldVal, final Object newVal) {
if (newVal==null) indexService.removeIndex(nodeBacked.getUnderlyingNode(),getPropertyName());
else indexService.index(nodeBacked.getUnderlyingNode(), getPropertyName(),newVal);
}
// todo
private String getPropertyName() {
return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field);
}
public static FieldAccessorListenerFactory<NodeBacked> factory() {
return new IndexingNodePropertyFieldAccessorListenerFactory();
}
}
}

View File

@@ -1,68 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.datastore.graph.api.NodeBacked;
import java.lang.reflect.Field;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public class NodePropertyFieldAccessor implements FieldAccessor<NodeBacked, Object> {
protected final Field field;
public NodePropertyFieldAccessor(final Field field) {
this.field = field;
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return true;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
nodeBacked.getUnderlyingNode().setProperty(getPropertyName(),newVal);
return newVal;
}
@Override
public final Object getValue(final NodeBacked nodeBacked) {
return doReturn(doGetValue(nodeBacked));
}
protected Object doGetValue(NodeBacked nodeBacked) {
return nodeBacked.getUnderlyingNode().getProperty(getPropertyName());
}
private String getPropertyName() {
return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field);
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new FieldAccessorFactory<NodeBacked>() {
@Override
public boolean accept(final Field f) {
return isNeo4jPropertyType(f.getType());
}
@Override
public FieldAccessor<NodeBacked,?> forField(final Field field) {
return new NodePropertyFieldAccessor(field);
}
private boolean isNeo4jPropertyType(final Class<?> fieldType) {
// todo: add array support
return fieldType.isPrimitive()
|| (fieldType.isArray() && !fieldType.getComponentType().isArray() && isNeo4jPropertyType(fieldType.getComponentType()))
|| fieldType.equals(String.class)
|| fieldType.equals(Character.class)
|| fieldType.equals(Boolean.class)
|| (fieldType.getName().startsWith("java.lang") && Number.class.isAssignableFrom(fieldType));
}
};
}
}

View File

@@ -0,0 +1,66 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.datastore.graph.api.NodeBacked;
import java.lang.reflect.Field;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public class NodePropertyFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Override
public boolean accept(final Field f) {
return isNeo4jPropertyType(f.getType());
}
@Override
public FieldAccessor<NodeBacked,?> forField(final Field field) {
return new NodePropertyFieldAccessor(field);
}
private boolean isNeo4jPropertyType(final Class<?> fieldType) {
// todo: add array support
return fieldType.isPrimitive()
|| (fieldType.isArray() && !fieldType.getComponentType().isArray() && isNeo4jPropertyType(fieldType.getComponentType()))
|| fieldType.equals(String.class)
|| fieldType.equals(Character.class)
|| fieldType.equals(Boolean.class)
|| (fieldType.getName().startsWith("java.lang") && Number.class.isAssignableFrom(fieldType));
}
public static class NodePropertyFieldAccessor implements FieldAccessor<NodeBacked, Object> {
protected final Field field;
public NodePropertyFieldAccessor(final Field field) {
this.field = field;
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return true;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
nodeBacked.getUnderlyingNode().setProperty(getPropertyName(),newVal);
return newVal;
}
@Override
public final Object getValue(final NodeBacked nodeBacked) {
return doReturn(doGetValue(nodeBacked));
}
protected Object doGetValue(NodeBacked nodeBacked) {
return nodeBacked.getUnderlyingNode().getProperty(getPropertyName());
}
private String getPropertyName() {
return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field);
}
}
}

View File

@@ -1,106 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.graph.api.GraphEntityRelationshipEntity;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.api.RelationshipBacked;
import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
public class OneToNRelationshipEntityFieldAccessor extends AbstractRelationshipFieldAccessor<NodeBacked, Node, RelationshipBacked, Relationship> {
public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends RelationshipBacked> elementClass, final GraphDatabaseContext graphDatabaseContext) {
super(elementClass, graphDatabaseContext, direction, type);
}
@Override
public Object setValue(final NodeBacked entity, final Object newVal) {
throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field.");
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
@Override
public Object getValue(final NodeBacked entity) {
checkUnderlyingNode(entity);
final Set<RelationshipBacked> result = createEntitySetFromRelationships(entity);
return doReturn(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)) {
final RelationshipBacked relationshipEntity = (RelationshipBacked) graphDatabaseContext.createEntityFromState(rel, (Class<?>) relatedType);
result.add(relationshipEntity);
}
return result;
}
@Override
protected Iterable<Relationship> getStatesFromEntity(final NodeBacked entity) {
return entity.getUnderlyingNode().getRelationships(type, direction);
}
@Override
protected Relationship obtainSingleRelationship(final Node start, final Relationship end) {
return null;
}
@Override
protected Node getState(final NodeBacked nodeBacked) {
return nodeBacked.getUnderlyingNode();
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new RelationshipEntityFieldAccessorFactory();
}
@Configurable
private static class RelationshipEntityFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Override
public boolean accept(final Field f) {
return Iterable.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
final GraphEntityRelationshipEntity relEntityAnnotation = getRelationshipAnnotation(field);
return new OneToNRelationshipEntityFieldAccessor(typeFrom(relEntityAnnotation), dirFrom(relEntityAnnotation), targetFrom(relEntityAnnotation), graphDatabaseContext);
}
private boolean hasValidRelationshipAnnotation(final Field f) {
final GraphEntityRelationshipEntity relEntityAnnotation = getRelationshipAnnotation(f);
return relEntityAnnotation != null && !RelationshipBacked.class.equals(relEntityAnnotation.elementClass());
}
private GraphEntityRelationshipEntity getRelationshipAnnotation(final Field field) {
return field.getAnnotation(GraphEntityRelationshipEntity.class);
}
private Class<? extends RelationshipBacked> targetFrom(final GraphEntityRelationshipEntity relEntityAnnotation) {
return relEntityAnnotation.elementClass();
}
private Direction dirFrom(final GraphEntityRelationshipEntity relEntityAnnotation) {
return relEntityAnnotation.direction().toNeo4jDir();
}
private DynamicRelationshipType typeFrom(final GraphEntityRelationshipEntity relEntityAnnotation) {
return DynamicRelationshipType.withName(relEntityAnnotation.type());
}
}
}

View File

@@ -0,0 +1,103 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.graph.api.GraphEntityRelationshipEntity;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.api.RelationshipBacked;
import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
@Configurable
public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Override
public boolean accept(final Field f) {
return Iterable.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
final GraphEntityRelationshipEntity relEntityAnnotation = getRelationshipAnnotation(field);
return new OneToNRelationshipEntityFieldAccessor(typeFrom(relEntityAnnotation), dirFrom(relEntityAnnotation), targetFrom(relEntityAnnotation), graphDatabaseContext);
}
private boolean hasValidRelationshipAnnotation(final Field f) {
final GraphEntityRelationshipEntity relEntityAnnotation = getRelationshipAnnotation(f);
return relEntityAnnotation != null && !RelationshipBacked.class.equals(relEntityAnnotation.elementClass());
}
private GraphEntityRelationshipEntity getRelationshipAnnotation(final Field field) {
return field.getAnnotation(GraphEntityRelationshipEntity.class);
}
private Class<? extends RelationshipBacked> targetFrom(final GraphEntityRelationshipEntity relEntityAnnotation) {
return relEntityAnnotation.elementClass();
}
private Direction dirFrom(final GraphEntityRelationshipEntity relEntityAnnotation) {
return relEntityAnnotation.direction().toNeo4jDir();
}
private DynamicRelationshipType typeFrom(final GraphEntityRelationshipEntity relEntityAnnotation) {
return DynamicRelationshipType.withName(relEntityAnnotation.type());
}
public static class OneToNRelationshipEntityFieldAccessor extends AbstractRelationshipFieldAccessor<NodeBacked, Node, RelationshipBacked, Relationship> {
public OneToNRelationshipEntityFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends RelationshipBacked> elementClass, final GraphDatabaseContext graphDatabaseContext) {
super(elementClass, graphDatabaseContext, direction, type);
}
@Override
public Object setValue(final NodeBacked entity, final Object newVal) {
throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field.");
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
@Override
public Object getValue(final NodeBacked entity) {
checkUnderlyingNode(entity);
final Set<RelationshipBacked> result = createEntitySetFromRelationships(entity);
return doReturn(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)) {
final RelationshipBacked relationshipEntity = (RelationshipBacked) graphDatabaseContext.createEntityFromState(rel, (Class<?>) relatedType);
result.add(relationshipEntity);
}
return result;
}
@Override
protected Iterable<Relationship> getStatesFromEntity(final NodeBacked entity) {
return entity.getUnderlyingNode().getRelationships(type, direction);
}
@Override
protected Relationship obtainSingleRelationship(final Node start, final Relationship end) {
return null;
}
@Override
protected Node getState(final NodeBacked nodeBacked) {
return nodeBacked.getUnderlyingNode();
}
}
}

View File

@@ -1,60 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.datastore.graph.api.GraphEntityRelationship;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
public class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final GraphDatabaseContext graphDatabaseContext) {
super(elementClass, graphDatabaseContext, direction, type);
}
public Object setValue(final NodeBacked entity, final Object newVal) {
final Node node = checkUnderlyingNode(entity);
if (newVal == null) {
removeMissingRelationships(node, Collections.<Node>emptySet());
return null;
}
final Set<Node> targetNodes = checkTargetIsSetOfNodebacked(newVal);
checkNoCircularReference(node, targetNodes);
removeMissingRelationships(node, targetNodes);
createAddedRelationships(node, targetNodes);
return createManagedSet(entity, (Set<NodeBacked>) newVal);
}
@Override
public Object getValue(final NodeBacked entity) {
checkUnderlyingNode(entity);
final Set<NodeBacked> result = createEntitySetFromRelationshipEndNodes(entity);
return doReturn(createManagedSet(entity, result));
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new RelationshipFieldAccessorFactory() {
@Override
public boolean accept(final Field f) {
return Collection.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field);
return new OneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext);
}
};
}
}

View File

@@ -0,0 +1,56 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.datastore.graph.api.GraphEntityRelationship;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
public class OneToNRelationshipFieldAccessorFactory extends RelationshipFieldAccessorFactory {
@Override
public boolean accept(final Field f) {
return Collection.class.isAssignableFrom(f.getType()) && hasValidRelationshipAnnotation(f);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field);
return new OneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext);
}
public static class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
public OneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final GraphDatabaseContext graphDatabaseContext) {
super(elementClass, graphDatabaseContext, direction, type);
}
public Object setValue(final NodeBacked entity, final Object newVal) {
final Node node = checkUnderlyingNode(entity);
if (newVal == null) {
removeMissingRelationships(node, Collections.<Node>emptySet());
return null;
}
final Set<Node> targetNodes = checkTargetIsSetOfNodebacked(newVal);
checkNoCircularReference(node, targetNodes);
removeMissingRelationships(node, targetNodes);
createAddedRelationships(node, targetNodes);
return createManagedSet(entity, (Set<NodeBacked>) newVal);
}
@Override
public Object getValue(final NodeBacked entity) {
checkUnderlyingNode(entity);
final Set<NodeBacked> result = createEntitySetFromRelationshipEndNodes(entity);
return doReturn(createManagedSet(entity, result));
}
}
}

View File

@@ -1,43 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import java.lang.reflect.Field;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.graph.api.GraphEntityRelationship;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext;
public class ReadOnlyOneToNRelationshipFieldAccessor extends OneToNRelationshipFieldAccessor {
public ReadOnlyOneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final GraphDatabaseContext graphDatabaseContext) {
super(type,direction,elementClass, graphDatabaseContext);
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
public Object setValue(final NodeBacked entity, final Object newVal) {
throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field.");
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new RelationshipFieldAccessorFactory() {
@Override
public boolean accept(final Field f) {
return Iterable.class.equals(f.getType()) && hasValidRelationshipAnnotation(f);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field);
return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext);
}
};
}
}

View File

@@ -0,0 +1,40 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.graph.api.GraphEntityRelationship;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext;
import java.lang.reflect.Field;
public class ReadOnlyOneToNRelationshipFieldAccessorFactory extends RelationshipFieldAccessorFactory {
@Override
public boolean accept(final Field f) {
return Iterable.class.equals(f.getType()) && hasValidRelationshipAnnotation(f);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field);
return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext);
}
public static class ReadOnlyOneToNRelationshipFieldAccessor extends OneToNRelationshipFieldAccessorFactory.OneToNRelationshipFieldAccessor {
public ReadOnlyOneToNRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> elementClass, final GraphDatabaseContext graphDatabaseContext) {
super(type,direction,elementClass, graphDatabaseContext);
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
public Object setValue(final NodeBacked entity, final Object newVal) {
throw new InvalidDataAccessApiUsageException("Cannot set read-only relationship entity field.");
}
}
}

View File

@@ -1,57 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.datastore.graph.api.GraphEntityRelationship;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Set;
public class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> clazz, final GraphDatabaseContext graphDatabaseContext) {
super(clazz, graphDatabaseContext, direction, type);
}
@Override
public Object setValue(final NodeBacked entity, final Object newVal) {
final Node node=checkUnderlyingNode(entity);
if (newVal == null) {
removeMissingRelationships(node, Collections.<Node>emptySet());
return null;
}
final Set<Node> target=checkTargetIsSetOfNodebacked(Collections.singleton(newVal));
checkNoCircularReference(node,target);
removeMissingRelationships(node, target);
createAddedRelationships(node,target);
return newVal;
}
@Override
public Object getValue(final NodeBacked entity) {
checkUnderlyingNode(entity);
final Set<NodeBacked> result = createEntitySetFromRelationshipEndNodes(entity);
return result.isEmpty() ? null : result.iterator().next();
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new RelationshipFieldAccessorFactory() {
@Override
public boolean accept(final Field f) {
return NodeBacked.class.isAssignableFrom(f.getType());
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field);
if (relAnnotation == null)
return new SingleRelationshipFieldAccessor(typeFrom(field), Direction.OUTGOING, targetFrom(field), graphDatabaseContext);
return new SingleRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(field), graphDatabaseContext);
}
};
}
}

View File

@@ -0,0 +1,55 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.RelationshipType;
import org.springframework.datastore.graph.api.GraphEntityRelationship;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.neo4j.support.GraphDatabaseContext;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Set;
public class SingleRelationshipFieldAccessorFactory extends RelationshipFieldAccessorFactory {
@Override
public boolean accept(final Field f) {
return NodeBacked.class.isAssignableFrom(f.getType());
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
final GraphEntityRelationship relAnnotation = getRelationshipAnnotation(field);
if (relAnnotation == null)
return new SingleRelationshipFieldAccessor(typeFrom(field), Direction.OUTGOING, targetFrom(field), graphDatabaseContext);
return new SingleRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(field), graphDatabaseContext);
}
public static class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor<NodeBacked> {
public SingleRelationshipFieldAccessor(final RelationshipType type, final Direction direction, final Class<? extends NodeBacked> clazz, final GraphDatabaseContext graphDatabaseContext) {
super(clazz, graphDatabaseContext, direction, type);
}
@Override
public Object setValue(final NodeBacked entity, final Object newVal) {
final Node node=checkUnderlyingNode(entity);
if (newVal == null) {
removeMissingRelationships(node, Collections.<Node>emptySet());
return null;
}
final Set<Node> target=checkTargetIsSetOfNodebacked(Collections.singleton(newVal));
checkNoCircularReference(node,target);
removeMissingRelationships(node, target);
createAddedRelationships(node,target);
return newVal;
}
@Override
public Object getValue(final NodeBacked entity) {
checkUnderlyingNode(entity);
final Set<NodeBacked> result = createEntitySetFromRelationshipEndNodes(entity);
return result.isEmpty() ? null : result.iterator().next();
}
}
}

View File

@@ -1,47 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.datastore.graph.api.NodeBacked;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public class TransientFieldAccessor implements FieldAccessor<NodeBacked, Object> {
protected final Field field;
public TransientFieldAccessor(final Field field) {
this.field = field;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
return newVal;
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return true;
}
@Override
public Object getValue(final NodeBacked nodeBacked) {
return null;
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new FieldAccessorFactory<NodeBacked>() {
@Override
public boolean accept(final Field f) {
return Modifier.isTransient(f.getModifiers());
}
@Override
public FieldAccessor<NodeBacked,?> forField(final Field field) {
return new TransientFieldAccessor(field);
}
};
}
}

View File

@@ -0,0 +1,46 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.springframework.datastore.graph.api.NodeBacked;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class TransientFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Override
public boolean accept(final Field f) {
return Modifier.isTransient(f.getModifiers());
}
@Override
public FieldAccessor<NodeBacked,?> forField(final Field field) {
return new TransientFieldAccessor(field);
}
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public static class TransientFieldAccessor implements FieldAccessor<NodeBacked, Object> {
protected final Field field;
public TransientFieldAccessor(final Field field) {
this.field = field;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
return newVal;
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return true;
}
@Override
public Object getValue(final NodeBacked nodeBacked) {
return null;
}
}
}

View File

@@ -1,88 +0,0 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.graph.api.FieldTraversalDescriptionBuilder;
import org.springframework.datastore.graph.api.GraphEntityTraversal;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.neo4j.finder.Finder;
import org.springframework.datastore.graph.neo4j.finder.FinderFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public class TraversalFieldAccessor implements FieldAccessor<NodeBacked, Object> {
protected final Field field;
private final FinderFactory finderFactory;
private final FieldTraversalDescriptionBuilder fieldTraversalDescriptionBuilder;
private Class<? extends NodeBacked> target;
public TraversalFieldAccessor(final Field field, FinderFactory finderFactory) {
this.field = field;
this.finderFactory = finderFactory;
final GraphEntityTraversal graphEntityTraversal = field.getAnnotation(GraphEntityTraversal.class);
this.target = graphEntityTraversal.elementClass();
this.fieldTraversalDescriptionBuilder = createTraversalDescription(graphEntityTraversal);
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
throw new InvalidDataAccessApiUsageException("Cannot set readonly traversal description field " + field);
}
@Override
public Object getValue(final NodeBacked nodeBacked) {
final Finder<? extends NodeBacked> finder = finderFactory.getFinderForClass(target);
final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(nodeBacked,field);
return doReturn(finder.findAllByTraversal(nodeBacked, traversalDescription));
}
private FieldTraversalDescriptionBuilder createTraversalDescription(final GraphEntityTraversal graphEntityTraversal) {
try {
final Class<? extends FieldTraversalDescriptionBuilder> traversalDescriptionClass = graphEntityTraversal.traversalBuilder();
final Constructor<? extends FieldTraversalDescriptionBuilder> constructor = traversalDescriptionClass.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (Exception e) {
throw new RuntimeException("Error creating TraversalDescription from " + field,e);
}
}
public static FieldAccessorFactory<NodeBacked> factory() {
return new TraversalFieldAccessorFactory();
}
@Configurable
private static class TraversalFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Autowired
private FinderFactory finderFactory;
@Override
public boolean accept(final Field f) {
final GraphEntityTraversal graphEntityTraversal = f.getAnnotation(GraphEntityTraversal.class);
return graphEntityTraversal != null
&& graphEntityTraversal.traversalBuilder() != TraversalDescription.class
&& f.getType().equals(Iterable.class);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
return new TraversalFieldAccessor(field, finderFactory);
}
}
}

View File

@@ -0,0 +1,85 @@
package org.springframework.datastore.graph.neo4j.fieldaccess;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.graph.api.FieldTraversalDescriptionBuilder;
import org.springframework.datastore.graph.api.GraphEntityTraversal;
import org.springframework.datastore.graph.api.NodeBacked;
import org.springframework.datastore.graph.neo4j.finder.Finder;
import org.springframework.datastore.graph.neo4j.finder.FinderFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import static org.springframework.datastore.graph.neo4j.fieldaccess.DoReturn.doReturn;
@Configurable
public class TraversalFieldAccessorFactory implements FieldAccessorFactory<NodeBacked> {
@Autowired
private FinderFactory finderFactory;
@Override
public boolean accept(final Field f) {
final GraphEntityTraversal graphEntityTraversal = f.getAnnotation(GraphEntityTraversal.class);
return graphEntityTraversal != null
&& graphEntityTraversal.traversalBuilder() != TraversalDescription.class
&& f.getType().equals(Iterable.class);
}
@Override
public FieldAccessor<NodeBacked, ?> forField(final Field field) {
return new TraversalFieldAccessor(field, finderFactory);
}
/**
* @author Michael Hunger
* @since 12.09.2010
*/
public static class TraversalFieldAccessor implements FieldAccessor<NodeBacked, Object> {
protected final Field field;
private final FinderFactory finderFactory;
private final FieldTraversalDescriptionBuilder fieldTraversalDescriptionBuilder;
private Class<? extends NodeBacked> target;
public TraversalFieldAccessor(final Field field, FinderFactory finderFactory) {
this.field = field;
this.finderFactory = finderFactory;
final GraphEntityTraversal graphEntityTraversal = field.getAnnotation(GraphEntityTraversal.class);
this.target = graphEntityTraversal.elementClass();
this.fieldTraversalDescriptionBuilder = createTraversalDescription(graphEntityTraversal);
}
@Override
public boolean isWriteable(NodeBacked nodeBacked) {
return false;
}
@Override
public Object setValue(final NodeBacked nodeBacked, final Object newVal) {
throw new InvalidDataAccessApiUsageException("Cannot set readonly traversal description field " + field);
}
@Override
public Object getValue(final NodeBacked nodeBacked) {
final Finder<? extends NodeBacked> finder = finderFactory.getFinderForClass(target);
final TraversalDescription traversalDescription = fieldTraversalDescriptionBuilder.build(nodeBacked,field);
return doReturn(finder.findAllByTraversal(nodeBacked, traversalDescription));
}
private FieldTraversalDescriptionBuilder createTraversalDescription(final GraphEntityTraversal graphEntityTraversal) {
try {
final Class<? extends FieldTraversalDescriptionBuilder> traversalDescriptionClass = graphEntityTraversal.traversalBuilder();
final Constructor<? extends FieldTraversalDescriptionBuilder> constructor = traversalDescriptionClass.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (Exception e) {
throw new RuntimeException("Error creating TraversalDescription from " + field,e);
}
}
}
}