added neo4j template from 4 years ago, TODO cleanup
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
package org.springframework.datastore.graph.neo4j.template;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.Traverser;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.datastore.graph.neo4j.template.graph.GraphDescription;
|
||||
import org.springframework.datastore.graph.neo4j.template.graph.Property;
|
||||
import org.springframework.datastore.graph.neo4j.template.traversal.Traversal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Graph {
|
||||
Node createNode(Property... params);
|
||||
|
||||
Node getReferenceNode();
|
||||
|
||||
Node getNodeById(final long id);
|
||||
|
||||
Traverser traverse(final Traversal traversal);
|
||||
|
||||
Traverser traverse(Node startNode, Traversal traversal);
|
||||
|
||||
<T> List<T> traverse(Node startNode, Traversal traversal, Converter<Node, T> converter);
|
||||
|
||||
void load(final GraphDescription graph);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.springframework.datastore.graph.neo4j.template;
|
||||
|
||||
public interface NeoCallback
|
||||
{
|
||||
void neo(final Status status, final Graph graph) throws Exception;
|
||||
|
||||
|
||||
public static interface Status
|
||||
{
|
||||
void mustRollback();
|
||||
|
||||
void interimCommit();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.springframework.datastore.graph.neo4j.template;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.datastore.graph.neo4j.template.graph.NeoGraph;
|
||||
|
||||
public class NeoTemplate
|
||||
{
|
||||
private final GraphDatabaseService neo;
|
||||
|
||||
public NeoTemplate(final GraphDatabaseService neo)
|
||||
{
|
||||
if (neo == null)
|
||||
throw new IllegalArgumentException("NeoService must not be null");
|
||||
this.neo = neo;
|
||||
}
|
||||
|
||||
public void execute(final NeoCallback callback)
|
||||
{
|
||||
if (callback == null)
|
||||
throw new IllegalArgumentException("Callback must not be null");
|
||||
final TransactionStatus status = new TransactionStatus(neo);
|
||||
try
|
||||
{
|
||||
|
||||
callback.neo(status, new NeoGraph(neo));
|
||||
} catch (Exception e)
|
||||
{
|
||||
status.mustRollback();
|
||||
throw new RuntimeException("Error executing neo callback " + callback, e);
|
||||
} finally
|
||||
{
|
||||
status.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TransactionStatus implements NeoCallback.Status
|
||||
{
|
||||
private boolean rollback;
|
||||
private final GraphDatabaseService neo;
|
||||
private Transaction tx;
|
||||
|
||||
private TransactionStatus(final GraphDatabaseService neo)
|
||||
{
|
||||
if (neo == null)
|
||||
throw new IllegalArgumentException("NeoService must not be null");
|
||||
this.neo = neo;
|
||||
begin();
|
||||
}
|
||||
|
||||
private void begin()
|
||||
{
|
||||
tx = neo.beginTx();
|
||||
}
|
||||
|
||||
public void mustRollback()
|
||||
{
|
||||
this.rollback = true;
|
||||
}
|
||||
|
||||
public void interimCommit()
|
||||
{
|
||||
finish();
|
||||
begin();
|
||||
}
|
||||
|
||||
private void finish()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (rollback)
|
||||
{
|
||||
tx.failure();
|
||||
} else
|
||||
{
|
||||
tx.success();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.graph;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
import org.springframework.datastore.graph.neo4j.template.Graph;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class GraphDescription
|
||||
{
|
||||
|
||||
private Map<String, NodeInfo> nodes = new LinkedHashMap<String, NodeInfo>();
|
||||
|
||||
public GraphDescription(final Properties props)
|
||||
{
|
||||
if (props == null)
|
||||
throw new IllegalArgumentException("Properties must not be null");
|
||||
new PropertyParser(props).load(this);
|
||||
}
|
||||
|
||||
|
||||
public GraphDescription()
|
||||
{
|
||||
}
|
||||
|
||||
public NodeInfo add(final String nodeName, final String attributeName, final Object value)
|
||||
{
|
||||
return getNode(nodeName).setProperty(attributeName, value);
|
||||
}
|
||||
|
||||
private NodeInfo getNode(final String nodeName)
|
||||
{
|
||||
final NodeInfo node = nodes.get(nodeName);
|
||||
if (node != null) return node;
|
||||
final NodeInfo newNode = new NodeInfo(nodeName);
|
||||
nodes.put(nodeName, newNode);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
public void relate(final String from, final RelationshipType type, final String to)
|
||||
{
|
||||
getNode(from).relateTo(type, getNode(to));
|
||||
}
|
||||
|
||||
void addToGraph(Graph graph)
|
||||
{
|
||||
boolean first = true;
|
||||
for (NodeInfo nodeInfo : nodes.values())
|
||||
{
|
||||
final Node node = first ? graph.getReferenceNode() : graph.createNode();
|
||||
first = false;
|
||||
nodeInfo.updateProperties(node);
|
||||
}
|
||||
|
||||
for (NodeInfo nodeInfo : nodes.values())
|
||||
{
|
||||
final Node from = graph.getNodeById(nodeInfo.getId());
|
||||
nodeInfo.updateRelations(from, graph);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.graph;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.Traverser;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.datastore.graph.neo4j.template.Graph;
|
||||
import org.springframework.datastore.graph.neo4j.template.traversal.Traversal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NeoGraph implements Graph
|
||||
{
|
||||
private final GraphDatabaseService neo;
|
||||
|
||||
public NeoGraph(final GraphDatabaseService neo)
|
||||
{
|
||||
if (neo == null)
|
||||
throw new IllegalArgumentException("NeoService must not be null");
|
||||
this.neo = neo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node createNode(final Property... params)
|
||||
{
|
||||
final Node node = neo.createNode();
|
||||
if (params == null || params.length == 0) return node;
|
||||
for (final Property property : params)
|
||||
{
|
||||
node.setProperty(property.getName(), property.getValue());
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getReferenceNode()
|
||||
{
|
||||
return neo.getReferenceNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNodeById(final long id)
|
||||
{
|
||||
return neo.getNodeById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Traverser traverse(final Traversal traversal)
|
||||
{
|
||||
return traverse(neo.getReferenceNode(), traversal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Traverser traverse(final Node startNode, final Traversal traversal)
|
||||
{
|
||||
if (startNode == null)
|
||||
throw new IllegalArgumentException("StartNode must not be null");
|
||||
if (traversal == null)
|
||||
throw new IllegalArgumentException("Traversal must not be null");
|
||||
return traversal.from(startNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> traverse(final Node startNode, final Traversal traversal, final Converter<Node, T> converter)
|
||||
{
|
||||
if (converter == null)
|
||||
throw new IllegalArgumentException("Converter must not be null");
|
||||
|
||||
return map(converter, traverse(startNode, traversal));
|
||||
}
|
||||
|
||||
private <T> List<T> map(final Converter<Node, T> mapper, final Iterable<Node> nodes)
|
||||
{
|
||||
final List<T> result = new ArrayList<T>();
|
||||
for (final Node node : nodes)
|
||||
{
|
||||
result.add(mapper.convert(node));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(final GraphDescription description)
|
||||
{
|
||||
if (description == null)
|
||||
throw new IllegalArgumentException("GraphDescription must not be null");
|
||||
description.addToGraph(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.graph;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
import org.springframework.datastore.graph.neo4j.template.Graph;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class NodeInfo
|
||||
{
|
||||
|
||||
private final String name;
|
||||
private final Map<String, Object> props = new LinkedHashMap<String, Object>();
|
||||
|
||||
private final Set<RelationShipNodeInfo> relations = new LinkedHashSet<RelationShipNodeInfo>();
|
||||
private long id;
|
||||
|
||||
public NodeInfo(final String nodeName)
|
||||
{
|
||||
this.name = nodeName;
|
||||
}
|
||||
|
||||
public NodeInfo setProperty(final String name, final Object value)
|
||||
{
|
||||
this.props.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void relateTo(final RelationshipType type, final NodeInfo node)
|
||||
{
|
||||
this.relations.add(new RelationShipNodeInfo(type, node));
|
||||
}
|
||||
|
||||
public void setId(final long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
void updateProperties(final Node node)
|
||||
{
|
||||
node.setProperty("name", name);
|
||||
for (Map.Entry<String, Object> prop : props.entrySet())
|
||||
{
|
||||
node.setProperty(prop.getKey(), prop.getValue());
|
||||
}
|
||||
setId(node.getId());
|
||||
}
|
||||
|
||||
void updateRelations(final Node from, final Graph nodeService)
|
||||
{
|
||||
for (RelationShipNodeInfo relation : relations)
|
||||
{
|
||||
final Node to = nodeService.getNodeById(relation.getNodeInfo().getId());
|
||||
from.createRelationshipTo(to, relation.getRelationshipType());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final NodeInfo nodeInfo = (NodeInfo) o;
|
||||
|
||||
return name.equals(nodeInfo.name);
|
||||
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return name.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.graph;
|
||||
|
||||
public class Property
|
||||
{
|
||||
private final String name;
|
||||
private final Object value;
|
||||
|
||||
private Property(final String name, final Object value)
|
||||
{
|
||||
if (name == null)
|
||||
throw new IllegalArgumentException("Name must not be null");
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("Value must not be null");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static Property _(String name, Object value)
|
||||
{
|
||||
return new Property(name, value);
|
||||
}
|
||||
|
||||
public Object getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.graph;
|
||||
|
||||
import org.neo4j.graphdb.DynamicRelationshipType;
|
||||
import org.springframework.datastore.graph.neo4j.template.util.Converter;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class PropertyParser
|
||||
{
|
||||
private final Properties props;
|
||||
private final Converter converter = new Converter();
|
||||
|
||||
public PropertyParser(final Properties props)
|
||||
{
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
public void load(final GraphDescription graph)
|
||||
{
|
||||
final SortedMap<Object, Object> sortedSet = new TreeMap<Object, Object>(props);
|
||||
for (Map.Entry<Object, Object> entry : sortedSet.entrySet())
|
||||
{
|
||||
if (entry.getKey() == null || entry.getValue() == null)
|
||||
throw new IllegalArgumentException(format("%s=%s is partially null%nproperties %s",
|
||||
entry.getKey(), entry.getValue(), props));
|
||||
|
||||
final String key = entry.getKey().toString();
|
||||
final String value = entry.getValue().toString();
|
||||
final String[] prop = key.split("\\.");
|
||||
if (prop.length == 2)
|
||||
{
|
||||
final String[] values = value.split(":");
|
||||
if (values.length != 2)
|
||||
graph.add(prop[0], prop[1], value);
|
||||
else
|
||||
{
|
||||
graph.add(prop[0], prop[1], converter.convert(values[0], values[1]));
|
||||
}
|
||||
} else
|
||||
{
|
||||
final String[] relationships = key.split("->");
|
||||
if (relationships.length == 2)
|
||||
{
|
||||
graph.relate(relationships[0], DynamicRelationshipType.withName(relationships[1]), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.graph;
|
||||
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
|
||||
class RelationShipNodeInfo
|
||||
{
|
||||
private final RelationshipType relationshipType;
|
||||
private final NodeInfo nodeInfo;
|
||||
|
||||
RelationShipNodeInfo(final RelationshipType relationshipType, final NodeInfo nodeInfo)
|
||||
{
|
||||
this.relationshipType = relationshipType;
|
||||
this.nodeInfo = nodeInfo;
|
||||
}
|
||||
|
||||
public boolean equals(final Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final RelationShipNodeInfo that = (RelationShipNodeInfo) o;
|
||||
|
||||
return nodeInfo.equals(that.nodeInfo) && relationshipType.name().equals(that.relationshipType.name());
|
||||
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return relationshipType.name().hashCode() * 31 + nodeInfo.hashCode();
|
||||
}
|
||||
|
||||
public NodeInfo getNodeInfo()
|
||||
{
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
public RelationshipType getRelationshipType()
|
||||
{
|
||||
return relationshipType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.traversal;
|
||||
|
||||
import org.neo4j.graphdb.Direction;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
class RelationShipTypeDirection
|
||||
{
|
||||
private final RelationshipType relationshipType;
|
||||
private final Direction direction;
|
||||
|
||||
private RelationShipTypeDirection(final RelationshipType relationshipType, final Direction direction)
|
||||
{
|
||||
if (relationshipType == null)
|
||||
throw new IllegalArgumentException("RelationShipType must not be null");
|
||||
if (direction == null)
|
||||
throw new IllegalArgumentException("Direction must not be null");
|
||||
this.relationshipType = relationshipType;
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public static RelationShipTypeDirection incoming(RelationshipType relationshipType)
|
||||
{
|
||||
return new RelationShipTypeDirection(relationshipType, Direction.INCOMING);
|
||||
}
|
||||
|
||||
public static RelationShipTypeDirection outgoing(RelationshipType relationshipType)
|
||||
{
|
||||
return new RelationShipTypeDirection(relationshipType, Direction.OUTGOING);
|
||||
}
|
||||
|
||||
public static RelationShipTypeDirection twoway(RelationshipType relationshipType)
|
||||
{
|
||||
return new RelationShipTypeDirection(relationshipType, Direction.BOTH);
|
||||
}
|
||||
|
||||
public RelationshipType getRelationshipType()
|
||||
{
|
||||
return relationshipType;
|
||||
}
|
||||
|
||||
public Direction getDirection()
|
||||
{
|
||||
return direction;
|
||||
}
|
||||
|
||||
public List<Object> asList()
|
||||
{
|
||||
return Arrays.asList(relationshipType, direction);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.traversal;
|
||||
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.springframework.datastore.graph.neo4j.template.util.NodeEvaluator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class Traversal
|
||||
{
|
||||
private final Collection<RelationShipTypeDirection> relationShipTypeDirections = new HashSet<RelationShipTypeDirection>();
|
||||
|
||||
private Traverser.Order order = Traverser.Order.BREADTH_FIRST;
|
||||
private StopEvaluator stopEvaluator = StopEvaluator.END_OF_GRAPH;
|
||||
private ReturnableEvaluator returnableEvaluator = ReturnableEvaluator.ALL_BUT_START_NODE;
|
||||
|
||||
private Traversal()
|
||||
{
|
||||
}
|
||||
|
||||
Traverser.Order getOrder()
|
||||
{
|
||||
return order;
|
||||
}
|
||||
|
||||
StopEvaluator getStopEvaluator()
|
||||
{
|
||||
return stopEvaluator;
|
||||
}
|
||||
|
||||
ReturnableEvaluator getReturnableEvaluator()
|
||||
{
|
||||
return returnableEvaluator;
|
||||
}
|
||||
|
||||
public static Traversal walk()
|
||||
{
|
||||
return new Traversal();
|
||||
}
|
||||
|
||||
public Traversal order(Traverser.Order order)
|
||||
{
|
||||
if (order == null)
|
||||
throw new IllegalArgumentException("Order must not be null");
|
||||
this.order = order;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Traversal accept(ReturnableEvaluator evaluator)
|
||||
{
|
||||
if (evaluator == null)
|
||||
throw new IllegalArgumentException("Evaluator must not be null");
|
||||
this.returnableEvaluator = evaluator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Traversal accept(final NodeEvaluator evaluator)
|
||||
{
|
||||
if (evaluator == null)
|
||||
throw new IllegalArgumentException("Evaluator must not be null");
|
||||
this.returnableEvaluator = new ReturnableEvaluator()
|
||||
{
|
||||
public boolean isReturnableNode(final TraversalPosition traversalPosition)
|
||||
{
|
||||
return evaluator.accept(traversalPosition.currentNode());
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public Traversal stopOn(StopEvaluator stop)
|
||||
{
|
||||
if (stop == null)
|
||||
throw new IllegalArgumentException("StopEvaluator must not be null");
|
||||
this.stopEvaluator = stop;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Traversal breadthFirst()
|
||||
{
|
||||
return order(Traverser.Order.BREADTH_FIRST);
|
||||
}
|
||||
|
||||
public Traversal depthFirst()
|
||||
{
|
||||
return order(Traverser.Order.DEPTH_FIRST);
|
||||
}
|
||||
|
||||
public Traversal first()
|
||||
{
|
||||
return stopOn(StopEvaluator.DEPTH_ONE);
|
||||
}
|
||||
|
||||
public Traversal all()
|
||||
{
|
||||
return stopOn(StopEvaluator.END_OF_GRAPH);
|
||||
}
|
||||
|
||||
public Traversal incoming(final RelationshipType relationShipType)
|
||||
{
|
||||
if (relationShipType == null)
|
||||
throw new IllegalArgumentException("RelationShipType must not be null");
|
||||
relationShipTypeDirections.add(RelationShipTypeDirection.incoming(relationShipType));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Traversal outgoing(final RelationshipType relationShipType)
|
||||
{
|
||||
if (relationShipType == null)
|
||||
throw new IllegalArgumentException("RelationShipType must not be null");
|
||||
relationShipTypeDirections.add(RelationShipTypeDirection.outgoing(relationShipType));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Traversal twoway(final RelationshipType relationShipType)
|
||||
{
|
||||
if (relationShipType == null)
|
||||
throw new IllegalArgumentException("RelationShipType must not be null");
|
||||
relationShipTypeDirections.add(RelationShipTypeDirection.twoway(relationShipType));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Traversal both(final RelationshipType relationShipType)
|
||||
{
|
||||
return twoway(relationShipType);
|
||||
}
|
||||
|
||||
public Traverser from(final Node node)
|
||||
{
|
||||
if (node == null)
|
||||
throw new IllegalArgumentException("Node must not be null");
|
||||
return node.traverse(getOrder(), getStopEvaluator(), getReturnableEvaluator(),
|
||||
getRelationshipTypeDirectionPairs());
|
||||
}
|
||||
|
||||
private Object[] getRelationshipTypeDirectionPairs()
|
||||
{
|
||||
Collection<Object> result = new ArrayList<Object>(relationShipTypeDirections.size());
|
||||
for (RelationShipTypeDirection relationShipTypeDirection : relationShipTypeDirections)
|
||||
{
|
||||
result.addAll(relationShipTypeDirection.asList());
|
||||
}
|
||||
return result.toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Converter
|
||||
{
|
||||
private final Map<String, Method> valueOfs = new HashMap<String, Method>();
|
||||
|
||||
public Object convert(final String typeName, final String value)
|
||||
{
|
||||
if (value == null) return null;
|
||||
if (typeName == null)
|
||||
throw new IllegalArgumentException("TypeName must not be null");
|
||||
try
|
||||
{
|
||||
Method valueOf = valueOfs.get(typeName);
|
||||
if (valueOf == null)
|
||||
{
|
||||
final Class type = Class.forName(typeName.contains(".") ? typeName : "java.lang." + typeName);
|
||||
valueOf = type.getMethod("valueOf", String.class);
|
||||
valueOfs.put(typeName, valueOf);
|
||||
}
|
||||
return valueOf.invoke(null, value);
|
||||
} catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(String.format("Error converting value %s from String to type %s", value, typeName), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.springframework.datastore.graph.neo4j.template.util;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
|
||||
public interface NodeEvaluator {
|
||||
boolean accept(final Node node);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springframework.datastore.graph.neo4j.template;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.kernel.EmbeddedGraphDatabase;
|
||||
import org.springframework.datastore.graph.neo4j.template.traversal.Traversal;
|
||||
|
||||
public abstract class NeoApiTest {
|
||||
protected GraphDatabaseService neo;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
neo = new EmbeddedGraphDatabase("target/var/neo");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (neo != null) {
|
||||
clear();
|
||||
neo.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
new NeoTemplate(neo).execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
final DynamicRelationshipType relationshipType = DynamicRelationshipType.withName("HAS");
|
||||
final Traverser allNodes = graph.traverse(Traversal.walk().both(relationshipType));
|
||||
for (Node node : allNodes) {
|
||||
for (Relationship relationship : node.getRelationships()) {
|
||||
relationship.delete();
|
||||
}
|
||||
node.delete();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.springframework.datastore.graph.neo4j.template;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.neo4j.graphdb.Direction;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
import org.springframework.datastore.graph.neo4j.template.graph.GraphDescription;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.datastore.graph.neo4j.template.NeoGraphDescriptionTest.Type.HAS;
|
||||
|
||||
|
||||
public class NeoGraphDescriptionTest extends NeoApiTest {
|
||||
|
||||
enum Type implements RelationshipType {
|
||||
HAS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadGraph() {
|
||||
final NeoTemplate template = new NeoTemplate(neo);
|
||||
template.execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
final GraphDescription heaven = new GraphDescription();
|
||||
heaven.add("adam", "age", 1);
|
||||
heaven.add("eve", "age", 0);
|
||||
heaven.relate("adam", HAS, "eve");
|
||||
graph.load(heaven);
|
||||
|
||||
checkHeaven(graph);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkHeaven(final Graph graph) {
|
||||
final Node adam = graph.getReferenceNode();
|
||||
assertEquals("adam", adam.getProperty("name"));
|
||||
assertEquals(1, adam.getProperty("age"));
|
||||
final Node eve = adam.getSingleRelationship(HAS, Direction.OUTGOING).getEndNode();
|
||||
assertEquals("eve", eve.getProperty("name"));
|
||||
assertEquals(0, eve.getProperty("age"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadGraphProps() {
|
||||
final NeoTemplate template = new NeoTemplate(neo);
|
||||
template.execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
final GraphDescription heaven = new GraphDescription(createGraphProperties());
|
||||
graph.load(heaven);
|
||||
checkHeaven(graph);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Properties createGraphProperties() throws IOException {
|
||||
Properties props = new Properties();
|
||||
props.load(new ByteArrayInputStream((
|
||||
"adam.age=Integer:1\n" +
|
||||
"eve.age=Integer:0\n" +
|
||||
"adam->HAS=eve"
|
||||
).getBytes("UTF-8")));
|
||||
return props;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.springframework.datastore.graph.neo4j.template;
|
||||
|
||||
import org.junit.Test;
|
||||
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.neo4j.template.graph.Property;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.springframework.datastore.graph.neo4j.template.NeoTemplateTest.Type.HAS;
|
||||
|
||||
public class NeoTemplateTest extends NeoApiTest {
|
||||
|
||||
enum Type implements RelationshipType {
|
||||
HAS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefNode() {
|
||||
new NeoTemplate(neo).execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
Node refNode = graph.getReferenceNode();
|
||||
Node refNodeById = graph.getNodeById(refNode.getId());
|
||||
assertEquals("same ref node", refNode, refNodeById);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleNode() {
|
||||
final NeoTemplate template = new NeoTemplate(neo);
|
||||
template.execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
Node refNode = graph.getReferenceNode();
|
||||
Node node = graph.createNode(Property._("name", "Test"), Property._("size", 100));
|
||||
refNode.createRelationshipTo(node, HAS);
|
||||
|
||||
final Relationship toTestNode = refNode.getSingleRelationship(HAS, Direction.OUTGOING);
|
||||
final Node nodeByRelationship = toTestNode.getEndNode();
|
||||
assertEquals("Test", nodeByRelationship.getProperty("name"));
|
||||
assertEquals(100, nodeByRelationship.getProperty("size"));
|
||||
}
|
||||
});
|
||||
template.execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
Node refNode = graph.getReferenceNode();
|
||||
final Relationship toTestNode = refNode.getSingleRelationship(HAS, Direction.OUTGOING);
|
||||
final Node nodeByRelationship = toTestNode.getEndNode();
|
||||
assertEquals("Test", nodeByRelationship.getProperty("name"));
|
||||
assertEquals(100, nodeByRelationship.getProperty("size"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRollback() {
|
||||
final NeoTemplate template = new NeoTemplate(neo);
|
||||
template.execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
Node node = graph.getReferenceNode();
|
||||
node.setProperty("test", "test");
|
||||
assertEquals("test", node.getProperty("test"));
|
||||
status.mustRollback();
|
||||
}
|
||||
});
|
||||
template.execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
Node node = graph.getReferenceNode();
|
||||
assertFalse(node.hasProperty("test"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package org.springframework.datastore.graph.neo4j.template;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.RelationshipType;
|
||||
import org.neo4j.graphdb.StopEvaluator;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.datastore.graph.neo4j.template.graph.GraphDescription;
|
||||
import org.springframework.datastore.graph.neo4j.template.traversal.Traversal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.datastore.graph.neo4j.template.NeoTraversalTest.Type.HAS;
|
||||
import static org.springframework.datastore.graph.neo4j.template.traversal.Traversal.walk;
|
||||
|
||||
public class NeoTraversalTest extends NeoApiTest {
|
||||
|
||||
enum Type implements RelationshipType {
|
||||
MARRIED, CHILD, GRANDSON, GRANDDAUGHTER, WIFE, HUSBAND, HAS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleTraverse() {
|
||||
runAndCheckTraverse(walk().both(HAS), "wife", "man","son","daughter", "grandma","grandpa" );
|
||||
}
|
||||
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testComplexTraversal() {
|
||||
final Traversal traversal = walk().breadthFirst().depthFirst()
|
||||
.stopOn(StopEvaluator.DEPTH_ONE).first().all()
|
||||
.incoming(HAS).outgoing(HAS).twoway(HAS);
|
||||
runAndCheckTraverse(traversal, "grandpa", "grandma", "daughter", "son", "man", "wife");
|
||||
}
|
||||
|
||||
private void runAndCheckTraverse(final Traversal traversal, final String... names) {
|
||||
final NeoTemplate template = new NeoTemplate(neo);
|
||||
template.execute(new NeoCallback() {
|
||||
public void neo(final Status status, final Graph graph) throws Exception {
|
||||
createFamily(graph);
|
||||
assertEquals("all members",asList(names) ,
|
||||
graph.traverse(graph.getReferenceNode(), traversal,
|
||||
new Converter<Node, String>() {
|
||||
public String convert(Node node) {
|
||||
return (String) node.getProperty("name", "");
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createFamily(final Graph graph) {
|
||||
final GraphDescription family = new GraphDescription();
|
||||
family.add("family", "type", "small");
|
||||
family.relate("family", HAS, "wife");
|
||||
family.relate("family", HAS, "man");
|
||||
|
||||
|
||||
family.add("man", "age", 35);
|
||||
family.add("wife", "age", 30);
|
||||
family.relate("man", Type.MARRIED, "wife");
|
||||
family.relate("wife", Type.MARRIED, "man");
|
||||
family.relate("man", Type.WIFE, "wife");
|
||||
family.relate("wife", Type.HUSBAND, "man");
|
||||
|
||||
family.add("daughter", "age", 10);
|
||||
family.add("son", "age", 8);
|
||||
|
||||
family.relate("family", HAS, "son");
|
||||
family.relate("family", HAS, "daughter");
|
||||
|
||||
family.relate("man", Type.CHILD, "son");
|
||||
family.relate("wife", Type.CHILD, "son");
|
||||
family.relate("man", Type.CHILD, "daughter");
|
||||
family.relate("wife", Type.CHILD, "daughter");
|
||||
|
||||
family.add("grandma", "age", 60);
|
||||
family.add("grandpa", "age", 75);
|
||||
|
||||
family.relate("family", HAS, "grandma");
|
||||
family.relate("family", HAS, "grandpa");
|
||||
|
||||
family.relate("grandpa", Type.CHILD, "man");
|
||||
family.relate("grandma", Type.CHILD, "man");
|
||||
|
||||
family.relate("grandpa", Type.GRANDSON, "son");
|
||||
family.relate("grandma", Type.GRANDSON, "son");
|
||||
family.relate("grandpa", Type.GRANDDAUGHTER, "daughter");
|
||||
family.relate("grandma", Type.GRANDDAUGHTER, "daughter");
|
||||
|
||||
// todo even more relationships
|
||||
graph.load(family);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user