Merge branch 'master' of github.com:SpringSource/spring-data-graph
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
package org.springframework.data.graph.neo4j.support;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.NotFoundException;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
import org.neo4j.graphdb.index.IndexHits;
|
||||
import org.neo4j.helpers.Predicate;
|
||||
import org.neo4j.helpers.collection.FilteringIterable;
|
||||
import org.neo4j.helpers.collection.IterableWrapper;
|
||||
import org.springframework.data.graph.annotation.NodeEntity;
|
||||
import org.springframework.data.graph.core.NodeBacked;
|
||||
import org.springframework.data.graph.core.NodeTypeStrategy;
|
||||
import org.springframework.persistence.support.EntityInstantiator;
|
||||
|
||||
public class IndexingNodeTypeStrategy implements NodeTypeStrategy {
|
||||
|
||||
private EntityInstantiator<NodeBacked, Node> graphEntityInstantiator;
|
||||
private GraphDatabaseService graphDb;
|
||||
|
||||
public IndexingNodeTypeStrategy(GraphDatabaseService graphDb, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
|
||||
this.graphDb = graphDb;
|
||||
this.graphEntityInstantiator = graphEntityInstantiator;
|
||||
}
|
||||
|
||||
private Index<Node> getTypesIndex() {
|
||||
return graphDb.index().forNodes("__types__");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postEntityCreation(NodeBacked entity) {
|
||||
Node node = entity.getPersistentState();
|
||||
Class<? extends NodeBacked> entityClass = entity.getClass();
|
||||
addToTypesIndex(node, entityClass);
|
||||
node.setProperty("__type__", entityClass.getName());
|
||||
}
|
||||
|
||||
private void addToTypesIndex(Node node, Class<? extends NodeBacked> entityClass) {
|
||||
Class<?> klass = entityClass;
|
||||
while (klass.getAnnotation(NodeEntity.class) != null) {
|
||||
getTypesIndex().add(node, "className", klass.getName());
|
||||
klass = klass.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <ENTITY extends NodeBacked> Iterable<ENTITY> findAll(Class<ENTITY> clazz) {
|
||||
final IndexHits<Node> allEntitiesOfType = getTypesIndex().get("className", clazz.getName());
|
||||
return new FilteringIterable<ENTITY>(new IterableWrapper<ENTITY, Node>(allEntitiesOfType) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ENTITY underlyingObjectToObject(Node node) {
|
||||
Class<ENTITY> javaType = (Class<ENTITY>) getJavaType(node);
|
||||
if (javaType == null) return null;
|
||||
return graphEntityInstantiator.createEntityFromState(node, javaType);
|
||||
}
|
||||
}, new Predicate<ENTITY>() {
|
||||
@Override
|
||||
public boolean accept(ENTITY item) {
|
||||
return item != null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count(Class<? extends NodeBacked> entityClass) {
|
||||
return getTypesIndex().get("className", entityClass.getName()).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <ENTITY extends NodeBacked> Class<ENTITY> getJavaType(Node node) {
|
||||
if (node == null) throw new IllegalArgumentException("Node is null");
|
||||
try {
|
||||
return (Class<ENTITY>) Class.forName((String) node.getProperty("__type__"));
|
||||
} catch (NotFoundException e) {
|
||||
return null;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preEntityRemoval(NodeBacked entity) {
|
||||
getTypesIndex().remove(entity.getPersistentState(), "className", entity.getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NodeBacked> Class<T> confirmType(Node node, Class<T> type) {
|
||||
Class<T> javaType = getJavaType(node);
|
||||
if (javaType == null) throw new IllegalStateException("No type stored on node.");
|
||||
if (type.isAssignableFrom(javaType)) return javaType;
|
||||
throw new IllegalArgumentException(String.format("%s does not correspond to the node type %s of node %s", type, javaType, node));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.springframework.data.graph.neo4j.support;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.springframework.data.graph.core.NodeBacked;
|
||||
import org.springframework.data.graph.core.NodeTypeStrategy;
|
||||
|
||||
public class NoopNodeTypeStrategy implements NodeTypeStrategy {
|
||||
@Override
|
||||
public void postEntityCreation(NodeBacked entity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NodeBacked> Iterable<T> findAll(Class<T> clazz) {
|
||||
throw new UnsupportedOperationException("findAll not supported by NoopNodeTypeStrategy.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count(Class<? extends NodeBacked> entityClass) {
|
||||
throw new UnsupportedOperationException("count not supported by NoopNodeTypeStrategy.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NodeBacked> Class<T> getJavaType(Node node) {
|
||||
throw new UnsupportedOperationException("getJavaType not supported NoopNodeTypeStrategy.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preEntityRemoval(NodeBacked entity) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NodeBacked> Class<T> confirmType(Node node, Class<T> type) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package org.springframework.data.graph.neo4j.support;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
import org.neo4j.graphdb.index.IndexHits;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.graph.annotation.NodeEntity;
|
||||
import org.springframework.data.graph.neo4j.support.node.Neo4jHelper;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.transaction.BeforeTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml",
|
||||
"classpath:org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyOverride-context.xml"})
|
||||
@Ignore
|
||||
public class IndexingNodeTypeStrategyTest {
|
||||
|
||||
@Autowired
|
||||
private GraphDatabaseService graphDatabaseService;
|
||||
@Autowired
|
||||
private IndexingNodeTypeStrategy nodeTypeStrategy;
|
||||
|
||||
private Thing thing;
|
||||
private SubThing subThing;
|
||||
|
||||
@BeforeTransaction
|
||||
public void cleanDb() {
|
||||
Neo4jHelper.cleanDb(graphDatabaseService);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
if (thing == null) {
|
||||
createThings();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void testPostEntityCreation() throws Exception {
|
||||
Index<Node> typesIndex = graphDatabaseService.index().forNodes("__types__");
|
||||
IndexHits<Node> thingHits = typesIndex.get("className", thing.getClass().getName());
|
||||
assertEquals(set(node(thing), node(subThing)), IteratorUtil.addToCollection((Iterable<Node>)thingHits, new HashSet<Node>()));
|
||||
assertEquals(thing.getClass().getName(), node(thing).getProperty("__type__"));
|
||||
assertEquals(subThing.getClass().getName(), node(subThing).getProperty("__type__"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAll() throws Exception {
|
||||
assertEquals("Did not find all things.",
|
||||
Arrays.asList(thing, subThing), IteratorUtil.addToCollection(nodeTypeStrategy.findAll(Thing.class), new ArrayList<Thing>()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCount() throws Exception {
|
||||
assertEquals(2, nodeTypeStrategy.count(Thing.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetJavaType() throws Exception {
|
||||
assertEquals(Thing.class, nodeTypeStrategy.getJavaType(node(thing)));
|
||||
assertEquals(SubThing.class, nodeTypeStrategy.getJavaType(node(subThing)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreEntityRemoval() throws Exception {
|
||||
manualCleanDb();
|
||||
Transaction tx;
|
||||
tx = graphDatabaseService.beginTx();
|
||||
try {
|
||||
nodeTypeStrategy.preEntityRemoval(thing);
|
||||
nodeTypeStrategy.preEntityRemoval(subThing);
|
||||
tx.success();
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
Index<Node> typesIndex = graphDatabaseService.index().forNodes("__types__");
|
||||
IndexHits<Node> thingHits = typesIndex.get("className", thing.getClass().getName());
|
||||
assertEquals(0, thingHits.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfirmType() throws Exception {
|
||||
assertEquals(Thing.class, nodeTypeStrategy.confirmType(node(thing), Thing.class));
|
||||
assertEquals(SubThing.class, nodeTypeStrategy.confirmType(node(subThing), Thing.class));
|
||||
}
|
||||
|
||||
private static Node node(Thing thing) {
|
||||
return thing.getPersistentState();
|
||||
}
|
||||
|
||||
private Thing createThings() {
|
||||
Transaction tx = graphDatabaseService.beginTx();
|
||||
try {
|
||||
thing = new Thing(graphDatabaseService.createNode());
|
||||
nodeTypeStrategy.postEntityCreation(thing);
|
||||
subThing = new SubThing(graphDatabaseService.createNode());
|
||||
nodeTypeStrategy.postEntityCreation(subThing);
|
||||
tx.success();
|
||||
return thing;
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@NodeEntity
|
||||
public static class Thing {
|
||||
|
||||
String name;
|
||||
|
||||
public Thing() {
|
||||
}
|
||||
public Thing(Node n) {
|
||||
setPersistentState(n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SubThing extends Thing {
|
||||
|
||||
public SubThing() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SubThing(Node n) {
|
||||
super(n);
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<Node> set(Node... nodes) {
|
||||
return new HashSet<Node>(Arrays.asList(nodes));
|
||||
}
|
||||
|
||||
private void manualCleanDb() {
|
||||
Transaction tx = graphDatabaseService.beginTx();
|
||||
try {
|
||||
cleanDb();
|
||||
tx.success();
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.springframework.data.graph.neo4j.support;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.Transaction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.graph.annotation.NodeEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml",
|
||||
"classpath:org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml"})
|
||||
public class NoopNodeTypeStrategyTest {
|
||||
|
||||
@Autowired
|
||||
private GraphDatabaseContext graphDatabaseContext;
|
||||
@Autowired
|
||||
private NoopNodeTypeStrategy nodeTypeStrategy;
|
||||
|
||||
private Thing thing;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
thing = createThing();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostEntityCreation() throws Exception {
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testFindAll() throws Exception {
|
||||
nodeTypeStrategy.findAll(Thing.class);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testCount() throws Exception {
|
||||
nodeTypeStrategy.count(Thing.class);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testGetJavaType() throws Exception {
|
||||
nodeTypeStrategy.getJavaType(node(thing));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreEntityRemoval() throws Exception {
|
||||
nodeTypeStrategy.preEntityRemoval(thing);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfirmType() throws Exception {
|
||||
assertEquals(Thing.class, nodeTypeStrategy.confirmType(node(thing), Thing.class));
|
||||
}
|
||||
|
||||
private static Node node(Thing thing) {
|
||||
return thing.getPersistentState();
|
||||
}
|
||||
|
||||
private Thing createThing() {
|
||||
Transaction tx = graphDatabaseContext.beginTx();
|
||||
try {
|
||||
Node node = graphDatabaseContext.createNode();
|
||||
Thing thing = new Thing(node);
|
||||
nodeTypeStrategy.postEntityCreation(thing);
|
||||
tx.success();
|
||||
return thing;
|
||||
} finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@NodeEntity
|
||||
public static class Thing {
|
||||
String name;
|
||||
|
||||
public Thing() {
|
||||
}
|
||||
|
||||
public Thing(Node n) {
|
||||
setPersistentState(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:jee="http://www.springframework.org/schema/jee"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:task="http://www.springframework.org/schema/task"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
|
||||
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.IndexingNodeTypeStrategy">
|
||||
<constructor-arg ref="graphDatabaseService" />
|
||||
<constructor-arg ref="graphEntityInstantiator" />
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -82,26 +82,27 @@
|
||||
<constructor-arg index="0" value="${neo4j.databaseDirectory}" />
|
||||
</bean>
|
||||
|
||||
<bean id="graphDatabaseContext" class="org.springframework.data.graph.neo4j.support.GraphDatabaseContext">
|
||||
<property name="graphDatabaseService" ref="graphDatabaseService"/>
|
||||
<property name="relationshipEntityInstantiator">
|
||||
<bean class="org.springframework.data.graph.neo4j.support.relationship.ConstructorBypassingGraphRelationshipInstantiator" />
|
||||
</property>
|
||||
<property name="graphEntityInstantiator">
|
||||
<bean class="org.springframework.data.graph.neo4j.support.node.Neo4jConstructorGraphEntityInstantiator" />
|
||||
</property>
|
||||
<property name="conversionService">
|
||||
<bean class="org.springframework.data.graph.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean"/>
|
||||
</property>
|
||||
<property name="nodeTypeStrategy">
|
||||
<bean class="org.springframework.data.graph.neo4j.support.SubReferenceNodeTypeStrategy">
|
||||
<constructor-arg index="0" ref="graphDatabaseContext"/>
|
||||
</bean>
|
||||
</property>
|
||||
<bean id="graphDatabaseContext" class="org.springframework.data.graph.neo4j.support.GraphDatabaseContext">
|
||||
<property name="graphDatabaseService" ref="graphDatabaseService"/>
|
||||
<property name="relationshipEntityInstantiator">
|
||||
<bean class="org.springframework.data.graph.neo4j.support.relationship.ConstructorBypassingGraphRelationshipInstantiator"/>
|
||||
</property>
|
||||
<property name="graphEntityInstantiator" ref="graphEntityInstantiator"/>
|
||||
<property name="conversionService">
|
||||
<bean class="org.springframework.data.graph.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean"/>
|
||||
</property>
|
||||
<property name="nodeTypeStrategy" ref="nodeTypeStrategy"/>
|
||||
<property name="validator">
|
||||
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
|
||||
</property>
|
||||
</bean>
|
||||
</bean>
|
||||
|
||||
<bean id="graphEntityInstantiator"
|
||||
class="org.springframework.data.graph.neo4j.support.node.Neo4jConstructorGraphEntityInstantiator"/>
|
||||
|
||||
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.SubReferenceNodeTypeStrategy">
|
||||
<constructor-arg index="0" ref="graphDatabaseContext"/>
|
||||
</bean>
|
||||
|
||||
<bean id="nodeEntityStateFactory" class="org.springframework.data.graph.neo4j.fieldaccess.NodeEntityStateFactory">
|
||||
<property name="nodeDelegatingFieldAccessorFactory">
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:jee="http://www.springframework.org/schema/jee"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:task="http://www.springframework.org/schema/task"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
|
||||
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<bean id="nodeTypeStrategy" class="org.springframework.data.graph.neo4j.support.NoopNodeTypeStrategy" />
|
||||
</beans>
|
||||
Reference in New Issue
Block a user