From 9c4c1af97e97b3f5213990948f9bf3d1cb7f59df Mon Sep 17 00:00:00 2001 From: David Montag Date: Mon, 21 Mar 2011 10:38:56 -0700 Subject: [PATCH 01/20] Refactored SubReferenceNodeTypeStrategy to work like the others. The IndexingNodeTypeStrategy is now pluggable for the subref one. --- .../jpa/Neo4jEntityManagerTest-context.xml | 40 ++++++++-------- .../neo4j/config/Neo4jConfiguration.java | 26 ++++++----- .../neo4j/support/GraphDatabaseContext.java | 22 --------- .../support/IndexingNodeTypeStrategy.java | 2 +- .../support/SubReferenceNodeTypeStrategy.java | 35 +++++++++++--- .../support/IndexingNodeTypeStrategyTest.java | 22 +++++++-- .../SubReferenceNodeTypeStrategyTest.java | 8 ++-- .../Neo4jGraphRecommendationTest-context.xml | 46 ++++++++++--------- .../Neo4jGraphPersistenceTest-context.xml | 8 +++- ...erenceNodeTypeStrategyOverride-context.xml | 22 +++++++++ 10 files changed, 141 insertions(+), 90 deletions(-) create mode 100644 spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml diff --git a/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml b/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml index 7c42a9636..e24b5865d 100644 --- a/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml +++ b/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml @@ -88,25 +88,27 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java index 331903284..027d3c70d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java @@ -17,12 +17,14 @@ package org.springframework.data.graph.neo4j.config; import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Node; import org.neo4j.kernel.impl.transaction.SpringTransactionManager; import org.neo4j.kernel.impl.transaction.UserTransactionImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean; import org.springframework.data.graph.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory; import org.springframework.data.graph.neo4j.fieldaccess.NodeEntityStateFactory; @@ -36,13 +38,11 @@ import org.springframework.data.graph.neo4j.support.node.PartialNeo4jEntityInsta import org.springframework.data.graph.neo4j.support.relationship.ConstructorBypassingGraphRelationshipInstantiator; import org.springframework.data.graph.neo4j.support.relationship.Neo4jRelationshipBacking; import org.springframework.data.graph.neo4j.transaction.ChainedTransactionManager; -import org.springframework.orm.jpa.EntityManagerFactoryUtils; import org.springframework.orm.jpa.JpaTransactionManager; -import org.springframework.persistence.transaction.NaiveDoubleTransactionManager; +import org.springframework.persistence.support.EntityInstantiator; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; -import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.validation.Validator; @@ -82,7 +82,7 @@ public class Neo4jConfiguration { } public boolean isUsingCrossStorePersistence() { - return entityManagerFactory!=null; + return entityManagerFactory != null; } @Bean @@ -90,20 +90,24 @@ public class Neo4jConfiguration { GraphDatabaseContext gdc = new GraphDatabaseContext(); gdc.setGraphDatabaseService(getGraphDatabaseService()); gdc.setRelationshipEntityInstantiator(new ConstructorBypassingGraphRelationshipInstantiator()); - if (isUsingCrossStorePersistence()) { - gdc.setGraphEntityInstantiator(new PartialNeo4jEntityInstantiator(new Neo4jConstructorGraphEntityInstantiator(), entityManagerFactory)); - } - else { - gdc.setGraphEntityInstantiator(new Neo4jConstructorGraphEntityInstantiator()); - } + EntityInstantiator graphEntityInstantiator = getGraphEntityInstantiator(); + gdc.setGraphEntityInstantiator(graphEntityInstantiator); gdc.setConversionService(new Neo4jConversionServiceFactoryBean().getObject()); - gdc.setNodeTypeStrategy(new SubReferenceNodeTypeStrategy(gdc)); + gdc.setNodeTypeStrategy(new SubReferenceNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator)); if (validator!=null) { gdc.setValidator(validator); } return gdc; } + private EntityInstantiator getGraphEntityInstantiator() { + if (isUsingCrossStorePersistence()) { + return new PartialNeo4jEntityInstantiator(new Neo4jConstructorGraphEntityInstantiator(), entityManagerFactory); + } else { + return new Neo4jConstructorGraphEntityInstantiator(); + } + } + @Bean public FinderFactory finderFactory(GraphDatabaseContext graphDatabaseContext) throws Exception { return new FinderFactory(graphDatabaseContext); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java index adfc42d67..9f0fa655a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java @@ -269,28 +269,6 @@ public class GraphDatabaseContext { } - /** - * @param relType - * @return - */ - public Node getOrCreateSubReferenceNode(final RelationshipType relType) { - return getOrCreateSingleOtherNode(graphDatabaseService.getReferenceNode(), relType, Direction.OUTGOING); - } - - private Node getOrCreateSingleOtherNode(Node fromNode, RelationshipType type, - Direction direction) { - Relationship singleRelationship = fromNode.getSingleRelationship(type, direction); - if (singleRelationship != null) { - return singleRelationship.getOtherNode(fromNode); - } - - Node otherNode = graphDatabaseService.createNode(); - fromNode.createRelationshipTo(otherNode, type); - return otherNode; - - } - - /** * @return Neo4j Transaction manager */ diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java index 671d30bce..ae6c78270 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java @@ -82,7 +82,7 @@ public class IndexingNodeTypeStrategy implements NodeTypeStrategy { @Override public void preEntityRemoval(NodeBacked entity) { - getTypesIndex().remove(entity.getPersistentState(), "className", entity.getClass().getName()); + getTypesIndex().remove(entity.getPersistentState()); } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java index 6aa094180..5ad527504 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java @@ -25,6 +25,7 @@ import org.neo4j.helpers.collection.IterableWrapper; import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; +import org.springframework.persistence.support.EntityInstantiator; import java.util.*; @@ -47,11 +48,13 @@ public class SubReferenceNodeTypeStrategy implements NodeTypeStrategy { public static final String SUBREF_PREFIX = "SUBREF_"; public static final String SUBREF_CLASS_KEY = "class"; - private final GraphDatabaseContext graphDatabaseContext; + private GraphDatabaseService graphDatabaseService; + private EntityInstantiator entityInstantiator; - public SubReferenceNodeTypeStrategy(final GraphDatabaseContext graphDatabaseContext) { - this.graphDatabaseContext = graphDatabaseContext; - } + public SubReferenceNodeTypeStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator entityInstantiator) { + this.graphDatabaseService = graphDatabaseService; + this.entityInstantiator = entityInstantiator; + } public static Node getSingleOtherNode(Node node, RelationshipType type, Direction direction) { @@ -184,7 +187,7 @@ public class SubReferenceNodeTypeStrategy implements NodeTypeStrategy { @Override protected T underlyingObjectToObject(final Relationship rel) { final Node node = rel.getStartNode(); - T entity = (T) graphDatabaseContext.createEntityFromState(node, getJavaType(node)); + T entity = (T) entityInstantiator.createEntityFromState(node, getJavaType(node)); if (log.isDebugEnabled()) log.debug("Converting node: " + node + " to entity: " + entity); return entity; } @@ -195,15 +198,33 @@ public class SubReferenceNodeTypeStrategy implements NodeTypeStrategy { public Node obtainSubreferenceNode(final Class entityClass) { - return graphDatabaseContext.getOrCreateSubReferenceNode(subRefRelationshipType(entityClass)); + return getOrCreateSubReferenceNode(subRefRelationshipType(entityClass)); } public Node findSubreferenceNode(final Class entityClass) { - final Relationship subrefRelationship = graphDatabaseContext.getReferenceNode().getSingleRelationship(subRefRelationshipType(entityClass), Direction.OUTGOING); + final Relationship subrefRelationship = graphDatabaseService.getReferenceNode().getSingleRelationship(subRefRelationshipType(entityClass), Direction.OUTGOING); return subrefRelationship != null ? subrefRelationship.getEndNode() : null; } private DynamicRelationshipType subRefRelationshipType(Class clazz) { return DynamicRelationshipType.withName(SUBREF_PREFIX + clazz.getName()); } + + public Node getOrCreateSubReferenceNode(final RelationshipType relType) { + return getOrCreateSingleOtherNode(graphDatabaseService.getReferenceNode(), relType, Direction.OUTGOING); + } + + private Node getOrCreateSingleOtherNode(Node fromNode, RelationshipType type, + Direction direction) { + Relationship singleRelationship = fromNode.getSingleRelationship(type, direction); + if (singleRelationship != null) { + return singleRelationship.getOtherNode(fromNode); + } + + Node otherNode = graphDatabaseService.createNode(); + fromNode.createRelationshipTo(otherNode, type); + return otherNode; + + } + } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java index 0353215e3..5bb723793 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java @@ -28,7 +28,7 @@ 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 +//@Ignore public class IndexingNodeTypeStrategyTest { @Autowired @@ -81,18 +81,34 @@ public class IndexingNodeTypeStrategyTest { @Test public void testPreEntityRemoval() throws Exception { manualCleanDb(); + createThings(); + Index typesIndex = graphDatabaseService.index().forNodes("__types__"); Transaction tx; tx = graphDatabaseService.beginTx(); try { nodeTypeStrategy.preEntityRemoval(thing); + tx.success(); + } finally { + tx.finish(); + } + + IndexHits thingHits = typesIndex.get("className", thing.getClass().getName()); + assertEquals(1, thingHits.size()); + IndexHits subThingHits = typesIndex.get("className", subThing.getClass().getName()); + assertEquals(1, subThingHits.size()); + + tx = graphDatabaseService.beginTx(); + try { nodeTypeStrategy.preEntityRemoval(subThing); tx.success(); } finally { tx.finish(); } - Index typesIndex = graphDatabaseService.index().forNodes("__types__"); - IndexHits thingHits = typesIndex.get("className", thing.getClass().getName()); + + thingHits = typesIndex.get("className", thing.getClass().getName()); assertEquals(0, thingHits.size()); + subThingHits = typesIndex.get("className", subThing.getClass().getName()); + assertEquals(0, subThingHits.size()); } @Test diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyTest.java index ad40b5fb0..f9f51585d 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyTest.java @@ -39,7 +39,8 @@ import static org.junit.Assert.assertEquals; * @since 20.01.11 */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml"}) +@ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml", + "classpath:org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml"}) public class SubReferenceNodeTypeStrategyTest { protected final Log log = LogFactory.getLog(getClass()); @@ -48,8 +49,8 @@ public class SubReferenceNodeTypeStrategyTest { GraphDatabaseContext graphDatabaseContext; @Autowired private FinderFactory finderFactory; - - private NodeTypeStrategy nodeTypeStrategy; + @Autowired + private SubReferenceNodeTypeStrategy nodeTypeStrategy; private Node thingNode; private Thing thing; @@ -61,7 +62,6 @@ public class SubReferenceNodeTypeStrategyTest { @Before public void setUp() { - nodeTypeStrategy = graphDatabaseContext.getNodeTypeStrategy(); thingNode = createThing(); } diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml index 3f0482541..40d380a6c 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml @@ -86,28 +86,30 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml index 1e2ea1075..14873ec46 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml @@ -101,9 +101,15 @@ class="org.springframework.data.graph.neo4j.support.node.Neo4jConstructorGraphEntityInstantiator"/> - + + + + + + + diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml new file mode 100644 index 000000000..e2d8e83f7 --- /dev/null +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategyOverride-context.xml @@ -0,0 +1,22 @@ + + + + + + + + + From ac011bf81314628dcbd83a9912ef9f248a3b13c6 Mon Sep 17 00:00:00 2001 From: David Montag Date: Mon, 21 Mar 2011 12:36:52 -0700 Subject: [PATCH 02/20] Switched 1.0.0.BUILD-SNAPSHOT to depend on Neo4j 1.3-SNAPSHOT instead of 1.3.M04. Updated code to reflect snapshot version. Still waiting for some more Neo4j snapshot changes. --- spring-data-graph-parent/pom.xml | 2 +- ...gPropertyFieldAccessorListenerFactory.java | 2 +- .../graph/neo4j/finder/AbstractFinder.java | 1 - .../support/IndexingNodeTypeStrategyTest.java | 64 +++++++++---------- 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/spring-data-graph-parent/pom.xml b/spring-data-graph-parent/pom.xml index dbedc3d67..a946b752b 100644 --- a/spring-data-graph-parent/pom.xml +++ b/spring-data-graph-parent/pom.xml @@ -16,7 +16,7 @@ 1.5.10 3.0.5.RELEASE 1.0.0.BUILD-SNAPSHOT - 1.3.M04 + 1.3-SNAPSHOT 1.6.11.M2 diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java index 85e075b65..a13d689be 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java @@ -20,7 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.index.Index; -import org.neo4j.index.impl.lucene.ValueContext; +import org.neo4j.index.lucene.ValueContext; import org.springframework.data.annotation.Indexed; import org.springframework.data.graph.annotation.NodeEntity; import org.springframework.data.graph.core.GraphBacked; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java index 924b351c7..90bd5fe9d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java @@ -6,7 +6,6 @@ import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.index.Index; import org.neo4j.graphdb.index.IndexHits; import org.neo4j.helpers.collection.IterableWrapper; -import org.neo4j.index.impl.lucene.ValueContext; import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java index 5bb723793..b65d6ee7f 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java @@ -24,6 +24,8 @@ import java.util.HashSet; import java.util.Set; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml", @@ -57,14 +59,41 @@ public class IndexingNodeTypeStrategyTest { Index typesIndex = graphDatabaseService.index().forNodes("__types__"); IndexHits thingHits = typesIndex.get("className", thing.getClass().getName()); assertEquals(set(node(thing), node(subThing)), IteratorUtil.addToCollection((Iterable)thingHits, new HashSet())); + IndexHits subThingHits = typesIndex.get("className", subThing.getClass().getName()); + assertEquals(node(subThing), subThingHits.getSingle()); assertEquals(thing.getClass().getName(), node(thing).getProperty("__type__")); assertEquals(subThing.getClass().getName(), node(subThing).getProperty("__type__")); } + @Test + @Transactional + public void testPreEntityRemoval() throws Exception { + Index typesIndex = graphDatabaseService.index().forNodes("__types__"); + IndexHits thingHits; + IndexHits subThingHits; + + nodeTypeStrategy.preEntityRemoval(thing); + + thingHits = typesIndex.get("className", thing.getClass().getName()); +// assertEquals(node(subThing), thingHits.getSingle()); // TODO: enable this when Neo4j indexing bug is fixed. + assertEquals(1, thingHits.size()); + subThingHits = typesIndex.get("className", subThing.getClass().getName()); + assertEquals(node(subThing), subThingHits.getSingle()); + + nodeTypeStrategy.preEntityRemoval(subThing); + + thingHits = typesIndex.get("className", thing.getClass().getName()); + assertEquals( 0, thingHits.size()); + subThingHits = typesIndex.get("className", subThing.getClass().getName()); +// assertEquals( 0, subThingHits.size()); // TODO: enable this when Neo4j indexing bug is fixed. + assertTrue(subThingHits.size() <= 0); + } + @Test public void testFindAll() throws Exception { assertEquals("Did not find all things.", - Arrays.asList(thing, subThing), IteratorUtil.addToCollection(nodeTypeStrategy.findAll(Thing.class), new ArrayList())); + Arrays.asList(thing, subThing), + IteratorUtil.addToCollection(nodeTypeStrategy.findAll(Thing.class), new ArrayList())); } @Test @@ -78,39 +107,6 @@ public class IndexingNodeTypeStrategyTest { assertEquals(SubThing.class, nodeTypeStrategy.getJavaType(node(subThing))); } - @Test - public void testPreEntityRemoval() throws Exception { - manualCleanDb(); - createThings(); - Index typesIndex = graphDatabaseService.index().forNodes("__types__"); - Transaction tx; - tx = graphDatabaseService.beginTx(); - try { - nodeTypeStrategy.preEntityRemoval(thing); - tx.success(); - } finally { - tx.finish(); - } - - IndexHits thingHits = typesIndex.get("className", thing.getClass().getName()); - assertEquals(1, thingHits.size()); - IndexHits subThingHits = typesIndex.get("className", subThing.getClass().getName()); - assertEquals(1, subThingHits.size()); - - tx = graphDatabaseService.beginTx(); - try { - nodeTypeStrategy.preEntityRemoval(subThing); - tx.success(); - } finally { - tx.finish(); - } - - thingHits = typesIndex.get("className", thing.getClass().getName()); - assertEquals(0, thingHits.size()); - subThingHits = typesIndex.get("className", subThing.getClass().getName()); - assertEquals(0, subThingHits.size()); - } - @Test public void testConfirmType() throws Exception { assertEquals(Thing.class, nodeTypeStrategy.confirmType(node(thing), Thing.class)); From d54d5b482a85c87dca2aad424e4059fa36080d5e Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Mon, 21 Mar 2011 16:00:06 -0400 Subject: [PATCH 03/20] added neo4j maven snapshot repo --- spring-data-neo4j/pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml index 1bb7d7048..3f3ae2312 100644 --- a/spring-data-neo4j/pom.xml +++ b/spring-data-neo4j/pom.xml @@ -168,6 +168,14 @@ + + neo4j-public-repository + Neo4J Public Repository + http://m2.neo4j.org + + true + + jboss-repository JBoss Public Repository From f7453c2f96bdcb61fc38b4fa0a4d25aa45b1d7d3 Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Mon, 21 Mar 2011 16:27:44 -0400 Subject: [PATCH 04/20] made all test methods @Transactional so cleanDb() gets run for each --- .../graph/neo4j/support/IndexingNodeTypeStrategyTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java index b65d6ee7f..764b93626 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java @@ -1,7 +1,6 @@ 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; @@ -24,7 +23,6 @@ import java.util.HashSet; import java.util.Set; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @RunWith(SpringJUnit4ClassRunner.class) @@ -90,6 +88,7 @@ public class IndexingNodeTypeStrategyTest { } @Test + @Transactional public void testFindAll() throws Exception { assertEquals("Did not find all things.", Arrays.asList(thing, subThing), @@ -97,17 +96,20 @@ public class IndexingNodeTypeStrategyTest { } @Test + @Transactional public void testCount() throws Exception { assertEquals(2, nodeTypeStrategy.count(Thing.class)); } @Test + @Transactional public void testGetJavaType() throws Exception { assertEquals(Thing.class, nodeTypeStrategy.getJavaType(node(thing))); assertEquals(SubThing.class, nodeTypeStrategy.getJavaType(node(subThing))); } @Test + @Transactional public void testConfirmType() throws Exception { assertEquals(Thing.class, nodeTypeStrategy.confirmType(node(thing), Thing.class)); assertEquals(SubThing.class, nodeTypeStrategy.confirmType(node(subThing), Thing.class)); From 9abbcc294990d8cba6187405aed7ea536ea57b0e Mon Sep 17 00:00:00 2001 From: David Montag Date: Mon, 21 Mar 2011 14:45:37 -0700 Subject: [PATCH 05/20] Updated docs on NodeTypeStrategy. --- .../programming-model/nodetypestrategy.xml | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/docbkx/reference/programming-model/nodetypestrategy.xml b/src/docbkx/reference/programming-model/nodetypestrategy.xml index fb93dd6d6..87492e71e 100644 --- a/src/docbkx/reference/programming-model/nodetypestrategy.xml +++ b/src/docbkx/reference/programming-model/nodetypestrategy.xml @@ -4,20 +4,44 @@ Reified types for entities There are several ways to represent the Java type hierarchy of the data model in the graph. In general for all - node and relationship entities type information is needed to perform certain repository operations. That's - why the hierarchy up to java.lang.Object of all these classes will be persisted in the graph. - Implementations of NodeTypeStrategy take care of persisting this information on entity instance + node and relationship entities type information is needed to perform certain repository operations. Some of + this type information is saved in the graph database. + + + Implementations of NodeTypeStrategy take care of persisting this information on entity instance creation. They also provide the repository methods that use this type information to perform their operations - like findAll, count etc. + like findAll, count, etc. - The current implementation uses nodes to represent the Java type hierarchy which are connected via SUBCLASS_OF - relationships to their superclass nodes and via INSTANCE_OF relationships to the concrete node entity - instance node. + There are three available implementations to choose from. + + + SubReferenceNodeTypeStrategy + + Stores entity types in a tree in the graph representing the type hierarchy. Each entity + has a INSTANCE_OF relationship to a type node representing that entity's type. The type may or + may not have a SUBCLASS_OF relationship to another type node. + + + + IndexingNodeTypeStrategy + + Stores entity types in the integrated index. Each entity node gets indexed with its type and + any supertypes that are also @NodeEntity-annotated. The special index used for this + is called __types__. Additionally, in order to get the type of an entity node, each + node has a property __type__ with the type of that entity. + + + + NoopNodeTypeStrategy + + Does not store any type information, and does hence not support finding by type, counting by type, + or retrieving the type of any entity. + + + - An alternative approach could use indexing operations to perform the same functionality. Or one could skip the - NodeTypeStrategy altogether if no strict checks on type conformity are needed, which would allow for a much - more flexible data model. + The default implementation is SubReferenceNodeTypeStrategy. \ No newline at end of file From 0fcadd026b8609de28286eed0b870cbdafa514bc Mon Sep 17 00:00:00 2001 From: David Montag Date: Mon, 21 Mar 2011 15:58:43 -0700 Subject: [PATCH 06/20] Commented out troubled test for now. --- .../data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java index 764b93626..3dda6dc42 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java @@ -1,6 +1,7 @@ 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; @@ -64,6 +65,7 @@ public class IndexingNodeTypeStrategyTest { } @Test + @Ignore // TODO: Enable when indexing works properly. @Transactional public void testPreEntityRemoval() throws Exception { Index typesIndex = graphDatabaseService.index().forNodes("__types__"); From d0ff6c8be26557ebc1a24c7be007e926e0296181 Mon Sep 17 00:00:00 2001 From: David Montag Date: Mon, 21 Mar 2011 15:59:45 -0700 Subject: [PATCH 07/20] Made relationship type attribute of RelatedTo optional, defaulting to the field name (modulo useShortNames). --- .../data/graph/annotation/RelatedTo.java | 13 +++++++------ .../NodeRelationshipFieldAccessorFactory.java | 4 ++++ .../OneToNRelationshipFieldAccessorFactory.java | 2 +- ...dOnlyOneToNRelationshipFieldAccessorFactory.java | 2 +- .../SingleRelationshipFieldAccessorFactory.java | 3 +-- .../org/springframework/data/graph/neo4j/Group.java | 2 +- .../springframework/data/graph/neo4j/Person.java | 2 +- .../neo4j/support/NodeEntityRelationshipTest.java | 2 +- 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/annotation/RelatedTo.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/annotation/RelatedTo.java index 0069041f3..315a81ba7 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/annotation/RelatedTo.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/annotation/RelatedTo.java @@ -16,14 +16,14 @@ package org.springframework.data.graph.annotation; +import org.springframework.data.graph.core.Direction; +import org.springframework.data.graph.core.NodeBacked; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.springframework.data.graph.core.Direction; -import org.springframework.data.graph.core.NodeBacked; - /** * Annotation for {@link org.springframework.data.graph.annotation.NodeEntity} fields that relate to other entities via * relationships. Works for one-to-one and one-to-many relationships. It is optionally possible to define the relationship type, @@ -31,10 +31,11 @@ import org.springframework.data.graph.core.NodeBacked; * * Collection based one-to-many relationships return managed collections that reflect addition and removal to the underlying relationships. * + * Examples: *
- * @RelatedTo([type="friends"], elementClass=Person.class)
+ * @RelatedTo(elementClass=Person.class)
  * Collection<Person> friends;
- * @RelatedTo([type="spouse"], [elementClass=Person.class])
+ * @RelatedTo(type="partner")
  * Person spouse;
  * 
@@ -47,7 +48,7 @@ public @interface RelatedTo { /** * @return name of the relationship type, optional, can be inferred from the field name */ - String type(); + String type() default ""; /** * @return direction for the relationship, by default outgoing diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java index 825cc9ce8..f3303f71c 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java @@ -58,6 +58,10 @@ abstract class NodeRelationshipFieldAccessorFactory implements FieldAccessorFact return DynamicRelationshipType.withName(relAnnotation.type()); } + protected DynamicRelationshipType typeFrom(Field field, RelatedTo relAnnotation) { + return "".equals(relAnnotation.type()) ? typeFrom(field) : typeFrom(relAnnotation); + } + protected RelatedTo getRelationshipAnnotation(Field field) { return field.getAnnotation(RelatedTo.class); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java index 94b274c34..f085d7b19 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java @@ -44,7 +44,7 @@ public class OneToNRelationshipFieldAccessorFactory extends NodeRelationshipFiel @Override public FieldAccessor forField(final Field field) { final RelatedTo relAnnotation = getRelationshipAnnotation(field); - return new OneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext); + return new OneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext); } public static class OneToNRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java index 70e3c1ace..8c4379108 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/ReadOnlyOneToNRelationshipFieldAccessorFactory.java @@ -39,7 +39,7 @@ public class ReadOnlyOneToNRelationshipFieldAccessorFactory extends NodeRelation @Override public FieldAccessor forField(final Field field) { final RelatedTo relAnnotation = getRelationshipAnnotation(field); - return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext); + return new ReadOnlyOneToNRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(relAnnotation), graphDatabaseContext); } public static class ReadOnlyOneToNRelationshipFieldAccessor extends OneToNRelationshipFieldAccessorFactory.OneToNRelationshipFieldAccessor { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java index 54ae107bd..7d97b2565 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/SingleRelationshipFieldAccessorFactory.java @@ -24,7 +24,6 @@ import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; import java.lang.reflect.Field; -import java.util.Collection; import java.util.Collections; import java.util.Set; @@ -46,7 +45,7 @@ public class SingleRelationshipFieldAccessorFactory extends NodeRelationshipFiel final RelatedTo 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); + return new SingleRelationshipFieldAccessor(typeFrom(field, relAnnotation), dirFrom(relAnnotation), targetFrom(field), graphDatabaseContext); } public static class SingleRelationshipFieldAccessor extends NodeToNodesRelationshipFieldAccessor { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Group.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Group.java index a5511d84b..db7ecadf3 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Group.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Group.java @@ -26,7 +26,7 @@ public class Group { public final static String OTHER_NAME_INDEX="other_name"; public static final String SEARCH_GROUPS_INDEX = "search-groups"; - @RelatedTo(type = "persons", direction = Direction.OUTGOING, elementClass = Person.class) + @RelatedTo(direction = Direction.OUTGOING, elementClass = Person.class) private Collection persons; @RelatedTo(type = "persons", elementClass = Person.class) diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Person.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Person.java index b250a2ae2..c7c33ff62 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Person.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/Person.java @@ -44,7 +44,7 @@ public class Person { private Car car; - @RelatedTo(type = "mother", direction = Direction.OUTGOING) + @RelatedTo private Person mother; @RelatedTo(type = "boss", direction = Direction.INCOMING) diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NodeEntityRelationshipTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NodeEntityRelationshipTest.java index e1b022667..2f77f4bb4 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NodeEntityRelationshipTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NodeEntityRelationshipTest.java @@ -61,7 +61,7 @@ public class NodeEntityRelationshipTest { Person p = persistedPerson("Michael", 35); Person mother = persistedPerson("Gabi", 60); p.setMother(mother); - Node motherNode = p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("mother"), Direction.OUTGOING).getEndNode(); + Node motherNode = p.getPersistentState().getSingleRelationship(DynamicRelationshipType.withName("Person.mother"), Direction.OUTGOING).getEndNode(); assertEquals(mother.getPersistentState(), motherNode); assertEquals(mother, p.getMother()); } From 4fc038eab26b21c61dbaa0234e938cd7c7a05efe Mon Sep 17 00:00:00 2001 From: David Montag Date: Mon, 21 Mar 2011 16:56:05 -0700 Subject: [PATCH 08/20] Throw exception with descriptive message when trying to instantiate an entity class with a misconfigured @RelatedTo annotation missing its elementClass attribute for a 1:N relationship. --- .../data/graph/annotation/RelatedToVia.java | 2 +- .../neo4j/fieldaccess/DefaultEntityState.java | 4 ++-- .../DelegatingFieldAccessorFactory.java | 6 ++--- .../NodeRelationshipFieldAccessorFactory.java | 10 +++++++-- ...elationshipEntityFieldAccessorFactory.java | 12 +++++++--- .../data/graph/neo4j/InvalidOneToNEntity.java | 12 ++++++++++ .../neo4j/InvalidReadOnlyOneToNEntity.java | 10 +++++++++ .../graph/neo4j/support/PropertyTest.java | 22 +++++++++++++------ 8 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/InvalidOneToNEntity.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/InvalidReadOnlyOneToNEntity.java diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/annotation/RelatedToVia.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/annotation/RelatedToVia.java index 318bc997d..1d73667f8 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/annotation/RelatedToVia.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/annotation/RelatedToVia.java @@ -52,5 +52,5 @@ public @interface RelatedToVia { /** * @return target relationship entity class */ - Class elementClass() default RelationshipBacked.class; + Class elementClass(); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/DefaultEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/DefaultEntityState.java index ce2615b71..2c9e19766 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/DefaultEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/DefaultEntityState.java @@ -43,8 +43,8 @@ public abstract class DefaultEntityState, STAT this.entity = entity; this.type = type; fieldAccessorFactoryProviders = delegatingFieldAccessorFactory.accessorFactoriesFor(type); - this.fieldAccessors= fieldAccessorFactoryProviders.getFieldAccessors(); - this.fieldAccessorListeners= fieldAccessorFactoryProviders.getFieldAccessListeners(); + this.fieldAccessors = fieldAccessorFactoryProviders.getFieldAccessors(); + this.fieldAccessorListeners = fieldAccessorFactoryProviders.getFieldAccessListeners(); } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java index e2996d827..bc48e4bae 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/DelegatingFieldAccessorFactory.java @@ -119,11 +119,11 @@ public abstract class DelegatingFieldAccessorFactory implements FieldAccessor - private final Map, FieldAccessorFactoryProviders> acessorFactoryProviderCache = new HashMap, FieldAccessorFactoryProviders>(); + private final Map, FieldAccessorFactoryProviders> accessorFactoryProviderCache = new HashMap, FieldAccessorFactoryProviders>(); public FieldAccessorFactoryProviders accessorFactoriesFor(final Class type) { synchronized (this) { - final FieldAccessorFactoryProviders fieldAccessorFactoryProviders = acessorFactoryProviderCache.get(type); + final FieldAccessorFactoryProviders fieldAccessorFactoryProviders = accessorFactoryProviderCache.get(type); if (fieldAccessorFactoryProviders != null) return fieldAccessorFactoryProviders; final FieldAccessorFactoryProviders newFieldAccessorFactories = new FieldAccessorFactoryProviders(type); ReflectionUtils.doWithFields(type, new ReflectionUtils.FieldCallback() { @@ -133,7 +133,7 @@ public abstract class DelegatingFieldAccessorFactory implements FieldAccessor newFieldAccessorFactories.add(field, factory, listenerFactories); } }); - acessorFactoryProviderCache.put(type, newFieldAccessorFactories); + accessorFactoryProviderCache.put(type, newFieldAccessorFactories); return newFieldAccessorFactories; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java index f3303f71c..6955d2f39 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeRelationshipFieldAccessorFactory.java @@ -18,6 +18,7 @@ package org.springframework.data.graph.neo4j.fieldaccess; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.DynamicRelationshipType; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.graph.annotation.RelatedTo; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; @@ -59,7 +60,7 @@ abstract class NodeRelationshipFieldAccessorFactory implements FieldAccessorFact } protected DynamicRelationshipType typeFrom(Field field, RelatedTo relAnnotation) { - return "".equals(relAnnotation.type()) ? typeFrom(field) : typeFrom(relAnnotation); + return "".equals(relAnnotation.type()) ? typeFrom(field) : typeFrom(relAnnotation); } protected RelatedTo getRelationshipAnnotation(Field field) { @@ -68,6 +69,11 @@ abstract class NodeRelationshipFieldAccessorFactory implements FieldAccessorFact protected boolean hasValidRelationshipAnnotation(Field field) { final RelatedTo relAnnotation = getRelationshipAnnotation(field); - return relAnnotation != null && !relAnnotation.elementClass().equals(NodeBacked.class); + if (relAnnotation == null) return false; + boolean hasElementClass = !relAnnotation.elementClass().equals(NodeBacked.class); + if (!hasElementClass) throw new InvalidDataAccessApiUsageException(String.format( + "Missing mandatory attribute @RelatedTo.elementClass for one-to-N relationship field %s in class: %s", + field.getName(), field.getDeclaringClass().getName())); + return true; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java index 1f6d6c50c..96552a528 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java @@ -50,9 +50,15 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess return new OneToNRelationshipEntityFieldAccessor(typeFrom(relEntityAnnotation), dirFrom(relEntityAnnotation), targetFrom(relEntityAnnotation), graphDatabaseContext); } - private boolean hasValidRelationshipAnnotation(final Field f) { - final RelatedToVia relEntityAnnotation = getRelationshipAnnotation(f); - return relEntityAnnotation != null && !RelationshipBacked.class.equals(relEntityAnnotation.elementClass()); + private boolean hasValidRelationshipAnnotation(final Field field) { + final RelatedToVia relEntityAnnotation = getRelationshipAnnotation(field); + if (relEntityAnnotation == null) return false; + Class elementClass = relEntityAnnotation.elementClass(); + boolean hasElementClass = elementClass != null && !RelationshipBacked.class.equals(elementClass); + if (!hasElementClass) throw new InvalidDataAccessApiUsageException(String.format( + "Missing mandatory attribute @RelatedTo.elementClass for one-to-N relationship field %s in class: %s", + field.getName(), field.getDeclaringClass().getName())); + return hasElementClass; } private RelatedToVia getRelationshipAnnotation(final Field field) { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/InvalidOneToNEntity.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/InvalidOneToNEntity.java new file mode 100644 index 000000000..5585d7181 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/InvalidOneToNEntity.java @@ -0,0 +1,12 @@ +package org.springframework.data.graph.neo4j; + +import org.springframework.data.graph.annotation.NodeEntity; +import org.springframework.data.graph.annotation.RelatedTo; + +import java.util.Collection; + +@NodeEntity +public class InvalidOneToNEntity { + @RelatedTo + private Collection others; +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/InvalidReadOnlyOneToNEntity.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/InvalidReadOnlyOneToNEntity.java new file mode 100644 index 000000000..e1b2993dc --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/InvalidReadOnlyOneToNEntity.java @@ -0,0 +1,10 @@ +package org.springframework.data.graph.neo4j; + +import org.springframework.data.graph.annotation.NodeEntity; +import org.springframework.data.graph.annotation.RelatedTo; + +@NodeEntity +public class InvalidReadOnlyOneToNEntity { + @RelatedTo + private Iterable others; +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/PropertyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/PropertyTest.java index 6bad30933..917a732cc 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/PropertyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/PropertyTest.java @@ -2,19 +2,14 @@ package org.springframework.data.graph.neo4j.support; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.neo4j.graphdb.NotFoundException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.graph.neo4j.Friendship; -import org.springframework.data.graph.neo4j.Person; -import static org.springframework.data.graph.neo4j.Person.persistedPerson; -import org.springframework.data.graph.neo4j.Personality; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.graph.neo4j.*; import org.springframework.data.graph.neo4j.finder.FinderFactory; import org.springframework.data.graph.neo4j.support.node.Neo4jHelper; - import org.springframework.test.annotation.Rollback; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -24,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Date; import static org.junit.Assert.assertEquals; +import static org.springframework.data.graph.neo4j.Person.persistedPerson; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml"}) @@ -131,4 +127,16 @@ public class PropertyTest { Friendship f = p.knows(p2); assertEquals("Wrong ID.", (Long)f.getPersistentState().getId(), f.getRelationshipId()); } + + @Test(expected = InvalidDataAccessApiUsageException.class) + @Transactional + public void testFailFastOnMisconfiguredOneToNProperty() { + new InvalidOneToNEntity(); + } + + @Test(expected = InvalidDataAccessApiUsageException.class) + @Transactional + public void testFailFastOnMisconfiguredReadOnlyOneToNProperty() { + new InvalidReadOnlyOneToNEntity(); + } } From 87f64892fccb61a3c0123548709cc9287ce194d5 Mon Sep 17 00:00:00 2001 From: David Montag Date: Tue, 22 Mar 2011 13:31:21 -0700 Subject: [PATCH 09/20] Updated some docs on annotations --- .../programming-model/annotations.xml | 89 +++++++++++-------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/src/docbkx/reference/programming-model/annotations.xml b/src/docbkx/reference/programming-model/annotations.xml index 4f42f682c..7b1985e77 100644 --- a/src/docbkx/reference/programming-model/annotations.xml +++ b/src/docbkx/reference/programming-model/annotations.xml @@ -7,8 +7,9 @@ annotation.
- Entities with @NodeEntity - The @NodeEntity annotation is used to declare a POJO entity to be backed by a node in the + @NodeEntity: The basic building block + + The @NodeEntity annotation is used to declare a POJO entity to be backed by a node in the graph store. Simple fields on the entity are mapped by default to properties of the node. Object references to other NodeEntities (whether single or Collection) are mapped via relationships. If the annotation parameter useShortNames is set to false, the properties and relationship @@ -26,47 +27,20 @@ public class Movie { } ]]>
+
- RelationshipEntities with @RelationshipEntity - To access the rich data model of graph relationships, POJOs can also be annotated with - @RelationshipEntity. Relationship entities can't be instantiated directly but are rather accessed via - node entities, either by @RelatedToVia fields or by the relateTo or - getRelationshipTo methods. - Relationship entities may contain fields that are mapped to properties and two special fields that are - annotated with @StartNode and @EndNode which point to the start and end node entities respectively. These - fields are treated as read only fields. - - -
-
- Fields with @GraphProperty - It is not necessary to annotate fields as they are persisted by default; all fields that contain primitive - values are persisted directly to the graph. All fields - convertible to String using the Spring conversion services will be stored as a string. Transient fields are - not persisted. - This annotation is mainly used for cross-store persistence. - -
-
- Fields with @RelatedTo pointing to other NodeEntities + @RelatedTo: Connecting NodeEntities Relationships to other NodeEntities are mapped to graph relationships. Those can either be single - relationships (1:1) or multiple relationships (1:n). In most cases single relationships to other + relationships (1:1) or multiple relationships (1:N). In most cases single relationships to other node entities don't have to be annotated as Spring Data Graph can extract all necessary information from the field using reflection. In the case of multiple relationships, the elementClass parameter of @RelatedTo must be specified because of type erasure. The direction (default OUTGOING) and type (inferred from field name) parameters of the annotation are optional. - Relationships to single node entities are created when setting the field and deleted when setting it to + + Relationships to single node entities are created when setting the field and deleted when setting it to null. For multi-relationships the field provides a managed collection (Set) that handles addition and removal of node entities and reflects those in the graph relationships. @@ -87,9 +61,33 @@ public class Actor { } ]]>
+
- Fields with @RelatedToVia pointing to RelationshipEntities - To provide easy programmatic access to the richer relationship entities of the data model a different + @RelationshipEntity: Rich relationships + + To access the full data model of graph relationships, POJOs can also be annotated with + @RelationshipEntity. Relationship entities can't be instantiated directly but are rather accessed via + node entities, either by @RelatedToVia fields or by the relateTo or + getRelationshipTo methods. + Relationship entities may contain fields that are mapped to properties and two special fields that are + annotated with @StartNode and @EndNode which point to the start and end node entities respectively. These + fields are treated as read only fields. + + +
+ +
+ @RelatedToVia: Connecting NodeEntitites via RelationshipEntities + + To provide easy programmatic access to the richer relationship entities of the data model a different annotation @RelatedToVia can be declared on fields of Iterables of the relationship entity type. These Iterables then provide read only access to instances of the entity that backs the relationship of this relationship type. Those instances are initialized with the properties of the relationship and the start @@ -104,15 +102,16 @@ public class Actor { ]]>
- @StartNode + @StartNode: Starting NodeEntity of RelationshipEntity Annotation for the start node of a relationship entity, read only.
- @EndNode + @EndNode: Ending NodeEntity of RelationshipEntity Annotation for the end node of a relationship entity, read only.
+
- @Indexed + @Indexed: Making entities searchable by field value The @Indexed annotation can be declared on fields that are intended to be indexed by the Neo4j IndexManager, triggered by value modification. The resulting index can be used to later retrieve nodes or relationships that contain a certain property @@ -128,6 +127,7 @@ public class Actor { it defaults to the one configured with Neo4j ("node" and "relationship").
+
@GraphTraversal The @GraphTraversal annotation leverages the delegation infrastructure used by the Spring Data Graph @@ -138,4 +138,15 @@ public class Actor { elementClass attribute.
+ +
+ @GraphProperty: Cross-store persisted fields + It is not necessary to annotate fields as they are persisted by default; all fields that contain primitive + values are persisted directly to the graph. All fields + convertible to String using the Spring conversion services will be stored as a string. Transient fields are + not persisted. + This annotation is mainly used for cross-store persistence. + +
+ \ No newline at end of file From b28dbf2fc3ae972fbec4ce772e5a38a52be57e83 Mon Sep 17 00:00:00 2001 From: David Montag Date: Tue, 22 Mar 2011 15:08:54 -0700 Subject: [PATCH 10/20] Made test pass. --- .../support/IndexingNodeTypeStrategyTest.java | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java index 3dda6dc42..29b7764e4 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategyTest.java @@ -24,12 +24,11 @@ import java.util.HashSet; import java.util.Set; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNull; @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 @@ -65,28 +64,44 @@ public class IndexingNodeTypeStrategyTest { } @Test - @Ignore // TODO: Enable when indexing works properly. - @Transactional public void testPreEntityRemoval() throws Exception { + manualCleanDb(); + createThings(); Index typesIndex = graphDatabaseService.index().forNodes("__types__"); IndexHits thingHits; IndexHits subThingHits; - nodeTypeStrategy.preEntityRemoval(thing); + Transaction tx = graphDatabaseService.beginTx(); + try + { + nodeTypeStrategy.preEntityRemoval(thing); + tx.success(); + } + finally + { + tx.finish(); + } thingHits = typesIndex.get("className", thing.getClass().getName()); -// assertEquals(node(subThing), thingHits.getSingle()); // TODO: enable this when Neo4j indexing bug is fixed. - assertEquals(1, thingHits.size()); + assertEquals(node(subThing), thingHits.getSingle()); subThingHits = typesIndex.get("className", subThing.getClass().getName()); assertEquals(node(subThing), subThingHits.getSingle()); - nodeTypeStrategy.preEntityRemoval(subThing); + tx = graphDatabaseService.beginTx(); + try + { + nodeTypeStrategy.preEntityRemoval(subThing); + tx.success(); + } + finally + { + tx.finish(); + } thingHits = typesIndex.get("className", thing.getClass().getName()); - assertEquals( 0, thingHits.size()); + assertNull(thingHits.getSingle()); subThingHits = typesIndex.get("className", subThing.getClass().getName()); -// assertEquals( 0, subThingHits.size()); // TODO: enable this when Neo4j indexing bug is fixed. - assertTrue(subThingHits.size() <= 0); + assertNull(subThingHits.getSingle()); } @Test From 186a910c3f94fd8e34f562884e405e819cd62793 Mon Sep 17 00:00:00 2001 From: David Montag Date: Tue, 22 Mar 2011 15:49:44 -0700 Subject: [PATCH 11/20] Extracted node type strategy selection to a factory bean. --- .../jpa/Neo4jEntityManagerTest-context.xml | 2 +- .../neo4j/config/Neo4jConfiguration.java | 5 +-- .../support/NodeTypeStrategyFactoryBean.java | 33 +++++++++++++++++++ .../Neo4jGraphRecommendationTest-context.xml | 2 +- .../Neo4jGraphPersistenceTest-context.xml | 7 +--- 5 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java diff --git a/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml b/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml index e24b5865d..dddb3438c 100644 --- a/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml +++ b/spring-data-neo4j-roo/src/test/resources/org/springframework/data/graph/neo4j/jpa/Neo4jEntityManagerTest-context.xml @@ -100,7 +100,7 @@
- + diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java index 027d3c70d..32f8e6ba7 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java @@ -31,7 +31,7 @@ import org.springframework.data.graph.neo4j.fieldaccess.NodeEntityStateFactory; import org.springframework.data.graph.neo4j.fieldaccess.RelationshipEntityStateFactory; import org.springframework.data.graph.neo4j.finder.FinderFactory; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import org.springframework.data.graph.neo4j.support.SubReferenceNodeTypeStrategy; +import org.springframework.data.graph.neo4j.support.NodeTypeStrategyFactoryBean; import org.springframework.data.graph.neo4j.support.node.Neo4jConstructorGraphEntityInstantiator; import org.springframework.data.graph.neo4j.support.node.Neo4jNodeBacking; import org.springframework.data.graph.neo4j.support.node.PartialNeo4jEntityInstantiator; @@ -93,7 +93,8 @@ public class Neo4jConfiguration { EntityInstantiator graphEntityInstantiator = getGraphEntityInstantiator(); gdc.setGraphEntityInstantiator(graphEntityInstantiator); gdc.setConversionService(new Neo4jConversionServiceFactoryBean().getObject()); - gdc.setNodeTypeStrategy(new SubReferenceNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator)); + NodeTypeStrategyFactoryBean nodeTypeStrategyFactoryBean = new NodeTypeStrategyFactoryBean(graphDatabaseService, graphEntityInstantiator); + gdc.setNodeTypeStrategy(nodeTypeStrategyFactoryBean.getObject()); if (validator!=null) { gdc.setValidator(validator); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java new file mode 100644 index 000000000..ec4c95a93 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java @@ -0,0 +1,33 @@ +package org.springframework.data.graph.neo4j.support; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Node; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.data.graph.core.NodeBacked; +import org.springframework.data.graph.core.NodeTypeStrategy; +import org.springframework.persistence.support.EntityInstantiator; + +public class NodeTypeStrategyFactoryBean implements FactoryBean { + private GraphDatabaseService graphDatabaseService; + private EntityInstantiator graphEntityInstantiator; + + public NodeTypeStrategyFactoryBean(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { + this.graphDatabaseService = graphDatabaseService; + this.graphEntityInstantiator = graphEntityInstantiator; + } + + @Override + public NodeTypeStrategy getObject() throws Exception { + return new SubReferenceNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator); + } + + @Override + public Class getObjectType() { + return SubReferenceNodeTypeStrategy.class; + } + + @Override + public boolean isSingleton() { + return false; + } +} diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml index 40d380a6c..2a444b96d 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/partial/Neo4jGraphRecommendationTest-context.xml @@ -103,7 +103,7 @@ - + diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml index 14873ec46..83e78ba9e 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml @@ -100,16 +100,11 @@ - + - - - - - From af25f4435f94473387317609ea0cdaf3448a6c93 Mon Sep 17 00:00:00 2001 From: David Montag Date: Tue, 22 Mar 2011 16:24:02 -0700 Subject: [PATCH 12/20] Added auto config to factory bean. For a pre-existing store, it will use the strategy used when that store was created. Otherwise it defaults to Indexed. Also made count() implementation of IndexingNodeTypeStrategy iterate the results instead of use size(). --- .../support/IndexingNodeTypeStrategy.java | 21 ++++-- .../support/NodeTypeStrategyFactoryBean.java | 64 ++++++++++++++++++- 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java index ae6c78270..eac2afc1e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java @@ -15,7 +15,10 @@ import org.springframework.persistence.support.EntityInstantiator; public class IndexingNodeTypeStrategy implements NodeTypeStrategy { - private EntityInstantiator graphEntityInstantiator; + public static final String NODE_INDEX_NAME = "__types__"; + public static final String TYPE_PROPERTY_NAME = "__type__"; + public static final String INDEX_KEY = "className"; + private EntityInstantiator graphEntityInstantiator; private GraphDatabaseService graphDb; public IndexingNodeTypeStrategy(GraphDatabaseService graphDb, EntityInstantiator graphEntityInstantiator) { @@ -24,7 +27,7 @@ public class IndexingNodeTypeStrategy implements NodeTypeStrategy { } private Index getTypesIndex() { - return graphDb.index().forNodes("__types__"); + return graphDb.index().forNodes(NODE_INDEX_NAME); } @Override @@ -32,20 +35,20 @@ public class IndexingNodeTypeStrategy implements NodeTypeStrategy { Node node = entity.getPersistentState(); Class entityClass = entity.getClass(); addToTypesIndex(node, entityClass); - node.setProperty("__type__", entityClass.getName()); + node.setProperty(TYPE_PROPERTY_NAME, entityClass.getName()); } private void addToTypesIndex(Node node, Class entityClass) { Class klass = entityClass; while (klass.getAnnotation(NodeEntity.class) != null) { - getTypesIndex().add(node, "className", klass.getName()); + getTypesIndex().add(node, INDEX_KEY, klass.getName()); klass = klass.getSuperclass(); } } @Override public Iterable findAll(Class clazz) { - final IndexHits allEntitiesOfType = getTypesIndex().get("className", clazz.getName()); + final IndexHits allEntitiesOfType = getTypesIndex().get(INDEX_KEY, clazz.getName()); return new FilteringIterable(new IterableWrapper(allEntitiesOfType) { @Override @SuppressWarnings("unchecked") @@ -64,7 +67,11 @@ public class IndexingNodeTypeStrategy implements NodeTypeStrategy { @Override public long count(Class entityClass) { - return getTypesIndex().get("className", entityClass.getName()).size(); + long count = 0; + for (Node node : getTypesIndex().get(INDEX_KEY, entityClass.getName())) { + count += 1; + } + return count; } @Override @@ -72,7 +79,7 @@ public class IndexingNodeTypeStrategy implements NodeTypeStrategy { public Class getJavaType(Node node) { if (node == null) throw new IllegalArgumentException("Node is null"); try { - return (Class) Class.forName((String) node.getProperty("__type__")); + return (Class) Class.forName((String) node.getProperty(TYPE_PROPERTY_NAME)); } catch (NotFoundException e) { return null; } catch (ClassNotFoundException e) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java index ec4c95a93..0810258c4 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java @@ -2,6 +2,7 @@ package org.springframework.data.graph.neo4j.support; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; import org.springframework.beans.factory.FactoryBean; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; @@ -10,24 +11,83 @@ import org.springframework.persistence.support.EntityInstantiator; public class NodeTypeStrategyFactoryBean implements FactoryBean { private GraphDatabaseService graphDatabaseService; private EntityInstantiator graphEntityInstantiator; + private Strategy strategy; public NodeTypeStrategyFactoryBean(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { this.graphDatabaseService = graphDatabaseService; this.graphEntityInstantiator = graphEntityInstantiator; + strategy = chooseStrategy(); + } + + private Strategy chooseStrategy() { + if (isAlreadyIndexed()) return Strategy.Indexed; + if (isAlreadySubRef()) return Strategy.SubRef; + return Strategy.Indexed; + } + + private boolean isAlreadyIndexed() { + return graphDatabaseService.index().existsForNodes(IndexingNodeTypeStrategy.NODE_INDEX_NAME); + } + + private boolean isAlreadySubRef() { + for (Relationship rel : graphDatabaseService.getReferenceNode().getRelationships()) { + if (rel.getType().name().startsWith(SubReferenceNodeTypeStrategy.SUBREF_PREFIX)) { + return true; + } + } + return false; } @Override public NodeTypeStrategy getObject() throws Exception { - return new SubReferenceNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator); + return strategy.getObject(graphDatabaseService, graphEntityInstantiator); } @Override public Class getObjectType() { - return SubReferenceNodeTypeStrategy.class; + return strategy.getObjectType(); } @Override public boolean isSingleton() { return false; } + + private enum Strategy { + SubRef { + @Override + NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { + return new SubReferenceNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator); + } + + @Override + Class getObjectType() { + return SubReferenceNodeTypeStrategy.class; + } + }, + Indexed { + @Override + NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { + return new IndexingNodeTypeStrategy(graphDatabaseService, graphEntityInstantiator); + } + + @Override + Class getObjectType() { + return IndexingNodeTypeStrategy.class; + } + }, + Noop { + @Override + NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { + return new NoopNodeTypeStrategy(); + } + + @Override + Class getObjectType() { + return NoopNodeTypeStrategy.class; + } + }; + abstract NodeTypeStrategy getObject(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator); + abstract Class getObjectType(); + } } From 00d2ed8c04b6e9a779861d80f88aa6dff13f5fd8 Mon Sep 17 00:00:00 2001 From: David Montag Date: Tue, 22 Mar 2011 17:30:23 -0700 Subject: [PATCH 13/20] Updated docs for node type strategy --- .../programming-model/nodetypestrategy.xml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/docbkx/reference/programming-model/nodetypestrategy.xml b/src/docbkx/reference/programming-model/nodetypestrategy.xml index 87492e71e..796f5d763 100644 --- a/src/docbkx/reference/programming-model/nodetypestrategy.xml +++ b/src/docbkx/reference/programming-model/nodetypestrategy.xml @@ -15,14 +15,6 @@ There are three available implementations to choose from. - - SubReferenceNodeTypeStrategy - - Stores entity types in a tree in the graph representing the type hierarchy. Each entity - has a INSTANCE_OF relationship to a type node representing that entity's type. The type may or - may not have a SUBCLASS_OF relationship to another type node. - - IndexingNodeTypeStrategy @@ -32,6 +24,14 @@ node has a property __type__ with the type of that entity. + + SubReferenceNodeTypeStrategy + + Stores entity types in a tree in the graph representing the type hierarchy. Each entity + has a INSTANCE_OF relationship to a type node representing that entity's type. The type may or + may not have a SUBCLASS_OF relationship to another type node. + + NoopNodeTypeStrategy @@ -42,6 +42,7 @@ - The default implementation is SubReferenceNodeTypeStrategy. + The default implementation is IndexingNodeTypeStrategy for new graphs. If using an existing + graph, Spring Data Graph will default to the strategy first used when the graph was created. \ No newline at end of file From 54e5ca16de906d5d4d6ba3b5c5e0a43b292185dc Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Wed, 23 Mar 2011 11:55:09 +0100 Subject: [PATCH 14/20] Editorial changes --- src/docbkx/tutorial/annotations.xml | 2 +- src/docbkx/tutorial/domain.xml | 5 ++++- src/docbkx/tutorial/neo4j.xml | 10 +++++----- src/docbkx/tutorial/security.xml | 2 +- src/docbkx/tutorial/setup.xml | 15 +++++++-------- src/docbkx/tutorial/spring-data-graph.xml | 15 ++++++++------- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/docbkx/tutorial/annotations.xml b/src/docbkx/tutorial/annotations.xml index 3967d3520..59908fe3d 100644 --- a/src/docbkx/tutorial/annotations.xml +++ b/src/docbkx/tutorial/annotations.xml @@ -9,7 +9,7 @@ It's time to put this to a test. How can we be assured that a field is persisted to the graph store? There seemed to be two possibilities. First was to get a GraphDatabaseContext injected and use its getById() method. The other one was a Finder approach. But let's try to keep things simple. - How can we persist an entity and how to get its id? No idea, so time to hit the documentation again, revealing that there are a bunch of methods introduced to the + How can we persist an entity and how to get its id? Looking at the documentation revealed that there are a bunch of methods introduced to the entities by the aspects. That's not obvious, but we found the two that would help here - entity.persist() and entity.getNodeId(). So our test looked like this. diff --git a/src/docbkx/tutorial/domain.xml b/src/docbkx/tutorial/domain.xml index f875b49dc..c53eb01d6 100644 --- a/src/docbkx/tutorial/domain.xml +++ b/src/docbkx/tutorial/domain.xml @@ -3,7 +3,7 @@ Setting the Stage - Movies Domain - The domain model was the next thing we planned to work on. We wanted to sketch it out first before diving into library details. We also looked at the datamodel of core themoviedb data to + The domain model was the next thing we planned to work on. We wanted to sketch it out first before diving into library details. We also looked at the datamodel of core themoviedb data to confirm that it matched our expectations. @@ -84,8 +83,8 @@ With this setup we were ready for the first spike: creating a simple MovieController showing a static view. Check. Next was the setup for Spring Data Graph. - We looked at the README at github and then checked it with the manual. Quite a lot of maven setup for aspectj but otherwise not so much to add. - Time to add a few lines to our spring configuration. + We looked at the README at github and then checked it with the manual. Quite a lot of Maven setup for AspectJ but otherwise not so much to add. + Time to add a few lines to our Spring configuration. @@ -129,7 +128,7 @@ - We spun up jetty to see if there were any obvious issues with the config. Check. + We spun up Jetty to see if there were any obvious issues with the config. It all seemed to work just fine. Check. diff --git a/src/docbkx/tutorial/spring-data-graph.xml b/src/docbkx/tutorial/spring-data-graph.xml index 77c61f4cf..15a61e809 100644 --- a/src/docbkx/tutorial/spring-data-graph.xml +++ b/src/docbkx/tutorial/spring-data-graph.xml @@ -1,16 +1,17 @@ - +x Conjuring Magic - Spring Data Graph - But that was the pure graph database. Using this in our domain would pollute my classes with lots of graph + That was the pure graph database. Using this in our domain would pollute our classes with lots of graph database details. We don't want that. Spring Data Graph - promised to do the heavy lifting for us. So we checked that next. Obviously it heavily depended on aspectj magic. - So there would be certain behavior that was - just observable without being visible in our code, but we were going to give it a try. + promised to do the heavy lifting for us. So we checked that next. + + Spring Data Graph depends heavily on AspectJ magic. Some parts of our classes would behave differently, + but it would not be visible in our code. We were going to give it a try. - First step was lots of maven configuration. + First step was lots of Maven configuration. @@ -71,7 +72,7 @@ ]]> - The spring configuration was much easier, thanks to a provided namespace. + The Spring configuration was much easier, thanks to a provided namespace. Date: Wed, 23 Mar 2011 11:26:58 -0400 Subject: [PATCH 15/20] adjusted to package chamges in data-commons --- .../data/graph/neo4j/config/Neo4jConfiguration.java | 2 +- .../data/graph/neo4j/fieldaccess/NodeEntityState.java | 2 +- .../data/graph/neo4j/fieldaccess/PartialNodeEntityState.java | 2 +- .../data/graph/neo4j/support/GraphDatabaseContext.java | 2 +- .../data/graph/neo4j/support/IndexingNodeTypeStrategy.java | 2 +- .../data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java | 2 +- .../data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java | 2 +- .../support/node/Neo4jConstructorGraphEntityInstantiator.java | 2 +- .../neo4j/support/node/PartialNeo4jEntityInstantiator.java | 2 +- .../ConstructorBypassingGraphRelationshipInstantiator.java | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java index 32f8e6ba7..1adffa251 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java @@ -39,7 +39,7 @@ import org.springframework.data.graph.neo4j.support.relationship.ConstructorBypa import org.springframework.data.graph.neo4j.support.relationship.Neo4jRelationshipBacking; import org.springframework.data.graph.neo4j.transaction.ChainedTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java index 4f32951ac..bbd5ee7e5 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java @@ -21,7 +21,7 @@ import org.neo4j.graphdb.NotInTransactionException; import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import org.springframework.persistence.support.StateProvider; +import org.springframework.data.persistence.StateProvider; /** * @author Michael Hunger diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java index bb680595e..424f2400a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java @@ -26,7 +26,7 @@ import org.springframework.data.graph.annotation.RelatedTo; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.finder.FinderFactory; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import org.springframework.persistence.support.StateProvider; +import org.springframework.data.persistence.StateProvider; import javax.persistence.Id; import java.lang.reflect.Field; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java index 9f0fa655a..ac24b6925 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java @@ -29,7 +29,7 @@ import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; import org.springframework.data.graph.core.RelationshipBacked; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import javax.transaction.Status; import javax.transaction.SystemException; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java index eac2afc1e..2978c0203 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java @@ -11,7 +11,7 @@ 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; +import org.springframework.data.persistence.EntityInstantiator; public class IndexingNodeTypeStrategy implements NodeTypeStrategy { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java index 0810258c4..e3d97b7b0 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java @@ -6,7 +6,7 @@ import org.neo4j.graphdb.Relationship; import org.springframework.beans.factory.FactoryBean; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; public class NodeTypeStrategyFactoryBean implements FactoryBean { private GraphDatabaseService graphDatabaseService; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java index 5ad527504..9cfc3728b 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java @@ -25,7 +25,7 @@ import org.neo4j.helpers.collection.IterableWrapper; import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import java.util.*; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java index ba3e4f421..8212d35a8 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java @@ -18,7 +18,7 @@ package org.springframework.data.graph.neo4j.support.node; import org.neo4j.graphdb.Node; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.persistence.support.AbstractConstructorEntityInstantiator; +import org.springframework.data.persistence.AbstractConstructorEntityInstantiator; /** * Implementation of an entity instantiator for neo4j graphdb nodes, binding the entity type to a NodeBacked and the diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java index 3a511de90..59f2409ab 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java @@ -20,7 +20,7 @@ import org.neo4j.graphdb.Node; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.fieldaccess.PartialNodeEntityState; import org.springframework.orm.jpa.EntityManagerFactoryUtils; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java index 5ef171ee8..e471d4e7b 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java @@ -20,7 +20,7 @@ import java.lang.reflect.Constructor; import org.neo4j.graphdb.Relationship; import org.springframework.data.graph.core.RelationshipBacked; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import sun.reflect.ReflectionFactory; From f7ddde14a0b82678d603d86daf88dbd751f8d85b Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Wed, 23 Mar 2011 22:20:19 +0100 Subject: [PATCH 16/20] support for rest-server-addon --- spring-data-graph-parent/pom.xml | 12 ++- spring-data-neo4j/pom.xml | 10 +++ .../config/DataGraphBeanDefinitionParser.java | 23 ++++- ...gPropertyFieldAccessorListenerFactory.java | 2 +- .../graph/neo4j/finder/AbstractFinder.java | 1 - ...rovidedClassPathXmlApplicationContext.java | 29 +++++++ .../neo4j/server/SpringPluginInitializer.java | 84 +++++++++++++++++++ 7 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/ProvidedClassPathXmlApplicationContext.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/SpringPluginInitializer.java diff --git a/spring-data-graph-parent/pom.xml b/spring-data-graph-parent/pom.xml index dbedc3d67..9d4a26f09 100644 --- a/spring-data-graph-parent/pom.xml +++ b/spring-data-graph-parent/pom.xml @@ -16,7 +16,7 @@ 1.5.10 3.0.5.RELEASE 1.0.0.BUILD-SNAPSHOT - 1.3.M04 + 1.3-SNAPSHOT 1.6.11.M2 @@ -229,6 +229,16 @@ tests test + + org.neo4j + server-api + ${neo4j.version} + + + commons-configuration + commons-configuration + 1.6 + org.ow2.jotm diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml index 1bb7d7048..e7f147f48 100644 --- a/spring-data-neo4j/pom.xml +++ b/spring-data-neo4j/pom.xml @@ -132,6 +132,16 @@ test + + org.neo4j + server-api + + + + commons-configuration + commons-configuration + + org.hibernate.javax.persistence diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/DataGraphBeanDefinitionParser.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/DataGraphBeanDefinitionParser.java index eebb1bbf2..614ba28c5 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/DataGraphBeanDefinitionParser.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/DataGraphBeanDefinitionParser.java @@ -1,10 +1,14 @@ package org.springframework.data.graph.neo4j.config; import org.neo4j.kernel.EmbeddedGraphDatabase; +import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.w3c.dom.Element; import static org.springframework.util.StringUtils.hasText; @@ -15,12 +19,29 @@ public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser @Override protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) { - BeanDefinitionBuilder configBuilder = BeanDefinitionBuilder.rootBeanDefinition(Neo4jConfiguration.class); + BeanDefinitionBuilder configBuilder = createConfigurationBeanDefinition(); setupGraphDatabase(element, context, configBuilder); setupEntityManagerFactory(element, configBuilder); + setupConfigurationClassPostProcessor(context); return getSourcedBeanDefinition(configBuilder, element, context); } + private BeanDefinitionBuilder createConfigurationBeanDefinition() { + BeanDefinitionBuilder configBuilder = BeanDefinitionBuilder.rootBeanDefinition(Neo4jConfiguration.class); + configBuilder.setAutowireMode(Autowire.BY_TYPE.value()); + return configBuilder; + } + + private void setupConfigurationClassPostProcessor(final ParserContext parserContext) { + BeanDefinitionRegistry beanDefinitionRegistry = parserContext.getRegistry(); + + BeanDefinitionBuilder configurationClassPostProcessor = BeanDefinitionBuilder.rootBeanDefinition(ConfigurationClassPostProcessor.class); + BeanNameGenerator beanNameGenerator = parserContext.getReaderContext().getReader().getBeanNameGenerator(); + AbstractBeanDefinition configurationClassPostProcessorBeanDefinition = configurationClassPostProcessor.getBeanDefinition(); + String beanName = beanNameGenerator.generateBeanName(configurationClassPostProcessorBeanDefinition, beanDefinitionRegistry); + beanDefinitionRegistry.registerBeanDefinition(beanName, configurationClassPostProcessorBeanDefinition); + } + @Override protected boolean shouldGenerateId() { return true; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java index 85e075b65..a13d689be 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/IndexingPropertyFieldAccessorListenerFactory.java @@ -20,7 +20,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.index.Index; -import org.neo4j.index.impl.lucene.ValueContext; +import org.neo4j.index.lucene.ValueContext; import org.springframework.data.annotation.Indexed; import org.springframework.data.graph.annotation.NodeEntity; import org.springframework.data.graph.core.GraphBacked; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java index 924b351c7..90bd5fe9d 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/finder/AbstractFinder.java @@ -6,7 +6,6 @@ import org.neo4j.graphdb.PropertyContainer; import org.neo4j.graphdb.index.Index; import org.neo4j.graphdb.index.IndexHits; import org.neo4j.helpers.collection.IterableWrapper; -import org.neo4j.index.impl.lucene.ValueContext; import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/ProvidedClassPathXmlApplicationContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/ProvidedClassPathXmlApplicationContext.java new file mode 100644 index 000000000..e44496e98 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/ProvidedClassPathXmlApplicationContext.java @@ -0,0 +1,29 @@ +package org.springframework.data.graph.neo4j.server; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Context that merges the provided graph database service with the given context locations, + * so that spring beans that consume a graph database are populated properly. + */ +public class ProvidedClassPathXmlApplicationContext extends ClassPathXmlApplicationContext { + + private final GraphDatabaseService database; + + public ProvidedClassPathXmlApplicationContext(GraphDatabaseService database, final String[] locations) + throws org.springframework.beans.BeansException { + super(); + setConfigLocations(locations); + this.database = database; + refresh(); + } + + @Override + protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { + super.prepareBeanFactory(beanFactory); + beanFactory.registerResolvableDependency(GraphDatabaseService.class, database); + beanFactory.registerSingleton("graphDatabaseService", database); + } +} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/SpringPluginInitializer.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/SpringPluginInitializer.java new file mode 100644 index 000000000..c67195855 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/server/SpringPluginInitializer.java @@ -0,0 +1,84 @@ +package org.springframework.data.graph.neo4j.server; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.beanutils.BeanFactory; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.server.plugins.PluginLifecycle; +import org.neo4j.server.plugins.Injectable; +import org.springframework.context.ApplicationContext; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Initializer to run Spring Data Graph based Server Plugins in a Neo4j REST-server. It takes the list of + * config locations and a number of spring beans from those contexts that should be exposed + * as injectable dependencies with a Jersey @Context.
+ * For example:
+ *
+ * class MyInitializer extends SpringPluginInitializer {
+ *     public MyInitializer() {
+ *         super(new String[]{"myContext.xml"},"finderFactory","myRepository");
+ *     }
+ * }
+ * 
+ */ +public abstract class SpringPluginInitializer implements PluginLifecycle { + private String[] contextLocations; + private String[] exposedBeans; + protected ProvidedClassPathXmlApplicationContext ctx; + + public SpringPluginInitializer(String[] contextLocations, String... exposedBeans) { + this.contextLocations = contextLocations; + this.exposedBeans = exposedBeans; + } + + /** + * Binds the provided graph database to the spring contexts so that spring beans that consume a + * graph database can be populated.
+ * @param graphDatabaseService of the Neo4j server + * @param config of the Neo4j Server + * @return Exposes the requested Spring beans as @{see Injectable}s + */ + @Override + public Collection> start(GraphDatabaseService graphDatabaseService, Configuration config) { + ctx = new ProvidedClassPathXmlApplicationContext(graphDatabaseService, contextLocations); + Collection> result = new ArrayList>(exposedBeans.length); + for (final String exposedBean : exposedBeans) { + result.add(new SpringBeanInjectable(SpringPluginInitializer.this.ctx, exposedBean)); + } + return result; + } + + /** + * closes the spring context + */ + public void stop() { + if (ctx!=null) { + ctx.close(); + } + } + + /** + * provides access to the Spring bean, proxying the @{see Injectable} + * @param optional type of the bean + */ + private static class SpringBeanInjectable implements Injectable { + private final String exposedBean; + protected ApplicationContext ctx; + + public SpringBeanInjectable(final ApplicationContext ctx, String exposedBean) { + this.exposedBean = exposedBean; + this.ctx = ctx; + } + + public T getValue() { + return (T) ctx.getBean(exposedBean); + + } + + public Class getType() { + return (Class) ctx.getType(exposedBean); + } + } +} From 2765feef6c59922eec7e0d400d86373ed62aacaa Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Wed, 23 Mar 2011 23:29:10 +0100 Subject: [PATCH 17/20] server-api is now provided scope --- spring-data-graph-parent/pom.xml | 1 + spring-data-neo4j/pom.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/spring-data-graph-parent/pom.xml b/spring-data-graph-parent/pom.xml index 9d4a26f09..216547938 100644 --- a/spring-data-graph-parent/pom.xml +++ b/spring-data-graph-parent/pom.xml @@ -233,6 +233,7 @@ org.neo4j server-api ${neo4j.version} + provided
commons-configuration diff --git a/spring-data-neo4j/pom.xml b/spring-data-neo4j/pom.xml index e7f147f48..27e072681 100644 --- a/spring-data-neo4j/pom.xml +++ b/spring-data-neo4j/pom.xml @@ -135,6 +135,7 @@ org.neo4j server-api + provided From 1db03db75c9788757580ddcfa7fb531b00eb3cc4 Mon Sep 17 00:00:00 2001 From: David Montag Date: Wed, 23 Mar 2011 15:39:37 -0700 Subject: [PATCH 18/20] Fixed import statements. --- .../data/graph/neo4j/config/Neo4jConfiguration.java | 2 +- .../data/graph/neo4j/fieldaccess/NodeEntityState.java | 2 +- .../data/graph/neo4j/fieldaccess/PartialNodeEntityState.java | 2 +- .../data/graph/neo4j/support/GraphDatabaseContext.java | 2 +- .../data/graph/neo4j/support/IndexingNodeTypeStrategy.java | 2 +- .../data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java | 2 +- .../data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java | 2 +- .../support/node/Neo4jConstructorGraphEntityInstantiator.java | 2 +- .../neo4j/support/node/PartialNeo4jEntityInstantiator.java | 2 +- .../ConstructorBypassingGraphRelationshipInstantiator.java | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java index 1adffa251..32f8e6ba7 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java @@ -39,7 +39,7 @@ import org.springframework.data.graph.neo4j.support.relationship.ConstructorBypa import org.springframework.data.graph.neo4j.support.relationship.Neo4jRelationshipBacking; import org.springframework.data.graph.neo4j.transaction.ChainedTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager; -import org.springframework.data.persistence.EntityInstantiator; +import org.springframework.persistence.support.EntityInstantiator; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java index bbd5ee7e5..4f32951ac 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java @@ -21,7 +21,7 @@ import org.neo4j.graphdb.NotInTransactionException; import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import org.springframework.data.persistence.StateProvider; +import org.springframework.persistence.support.StateProvider; /** * @author Michael Hunger diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java index 424f2400a..bb680595e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java @@ -26,7 +26,7 @@ import org.springframework.data.graph.annotation.RelatedTo; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.finder.FinderFactory; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import org.springframework.data.persistence.StateProvider; +import org.springframework.persistence.support.StateProvider; import javax.persistence.Id; import java.lang.reflect.Field; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java index ac24b6925..9f0fa655a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java @@ -29,7 +29,7 @@ import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; import org.springframework.data.graph.core.RelationshipBacked; -import org.springframework.data.persistence.EntityInstantiator; +import org.springframework.persistence.support.EntityInstantiator; import javax.transaction.Status; import javax.transaction.SystemException; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java index 2978c0203..eac2afc1e 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java @@ -11,7 +11,7 @@ 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.data.persistence.EntityInstantiator; +import org.springframework.persistence.support.EntityInstantiator; public class IndexingNodeTypeStrategy implements NodeTypeStrategy { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java index e3d97b7b0..0810258c4 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java @@ -6,7 +6,7 @@ import org.neo4j.graphdb.Relationship; import org.springframework.beans.factory.FactoryBean; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; -import org.springframework.data.persistence.EntityInstantiator; +import org.springframework.persistence.support.EntityInstantiator; public class NodeTypeStrategyFactoryBean implements FactoryBean { private GraphDatabaseService graphDatabaseService; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java index 9cfc3728b..5ad527504 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java @@ -25,7 +25,7 @@ import org.neo4j.helpers.collection.IterableWrapper; import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; -import org.springframework.data.persistence.EntityInstantiator; +import org.springframework.persistence.support.EntityInstantiator; import java.util.*; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java index 8212d35a8..ba3e4f421 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java @@ -18,7 +18,7 @@ package org.springframework.data.graph.neo4j.support.node; import org.neo4j.graphdb.Node; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.data.persistence.AbstractConstructorEntityInstantiator; +import org.springframework.persistence.support.AbstractConstructorEntityInstantiator; /** * Implementation of an entity instantiator for neo4j graphdb nodes, binding the entity type to a NodeBacked and the diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java index 59f2409ab..3a511de90 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java @@ -20,7 +20,7 @@ import org.neo4j.graphdb.Node; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.fieldaccess.PartialNodeEntityState; import org.springframework.orm.jpa.EntityManagerFactoryUtils; -import org.springframework.data.persistence.EntityInstantiator; +import org.springframework.persistence.support.EntityInstantiator; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java index e471d4e7b..5ef171ee8 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java @@ -20,7 +20,7 @@ import java.lang.reflect.Constructor; import org.neo4j.graphdb.Relationship; import org.springframework.data.graph.core.RelationshipBacked; -import org.springframework.data.persistence.EntityInstantiator; +import org.springframework.persistence.support.EntityInstantiator; import sun.reflect.ReflectionFactory; From d7cc7a8f8d3329edf190c7851919656f9e693611 Mon Sep 17 00:00:00 2001 From: David Montag Date: Wed, 23 Mar 2011 16:01:09 -0700 Subject: [PATCH 19/20] Revert "Fixed import statements." This reverts commit 1db03db75c9788757580ddcfa7fb531b00eb3cc4. --- .../data/graph/neo4j/config/Neo4jConfiguration.java | 2 +- .../data/graph/neo4j/fieldaccess/NodeEntityState.java | 2 +- .../data/graph/neo4j/fieldaccess/PartialNodeEntityState.java | 2 +- .../data/graph/neo4j/support/GraphDatabaseContext.java | 2 +- .../data/graph/neo4j/support/IndexingNodeTypeStrategy.java | 2 +- .../data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java | 2 +- .../data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java | 2 +- .../support/node/Neo4jConstructorGraphEntityInstantiator.java | 2 +- .../neo4j/support/node/PartialNeo4jEntityInstantiator.java | 2 +- .../ConstructorBypassingGraphRelationshipInstantiator.java | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java index 32f8e6ba7..1adffa251 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java @@ -39,7 +39,7 @@ import org.springframework.data.graph.neo4j.support.relationship.ConstructorBypa import org.springframework.data.graph.neo4j.support.relationship.Neo4jRelationshipBacking; import org.springframework.data.graph.neo4j.transaction.ChainedTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java index 4f32951ac..bbd5ee7e5 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/NodeEntityState.java @@ -21,7 +21,7 @@ import org.neo4j.graphdb.NotInTransactionException; import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import org.springframework.persistence.support.StateProvider; +import org.springframework.data.persistence.StateProvider; /** * @author Michael Hunger diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java index bb680595e..424f2400a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PartialNodeEntityState.java @@ -26,7 +26,7 @@ import org.springframework.data.graph.annotation.RelatedTo; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.finder.FinderFactory; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; -import org.springframework.persistence.support.StateProvider; +import org.springframework.data.persistence.StateProvider; import javax.persistence.Id; import java.lang.reflect.Field; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java index 9f0fa655a..ac24b6925 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java @@ -29,7 +29,7 @@ import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; import org.springframework.data.graph.core.RelationshipBacked; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import javax.transaction.Status; import javax.transaction.SystemException; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java index eac2afc1e..2978c0203 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeStrategy.java @@ -11,7 +11,7 @@ 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; +import org.springframework.data.persistence.EntityInstantiator; public class IndexingNodeTypeStrategy implements NodeTypeStrategy { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java index 0810258c4..e3d97b7b0 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NodeTypeStrategyFactoryBean.java @@ -6,7 +6,7 @@ import org.neo4j.graphdb.Relationship; import org.springframework.beans.factory.FactoryBean; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; public class NodeTypeStrategyFactoryBean implements FactoryBean { private GraphDatabaseService graphDatabaseService; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java index 5ad527504..9cfc3728b 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeStrategy.java @@ -25,7 +25,7 @@ import org.neo4j.helpers.collection.IterableWrapper; import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.core.NodeTypeStrategy; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import java.util.*; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java index ba3e4f421..8212d35a8 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/Neo4jConstructorGraphEntityInstantiator.java @@ -18,7 +18,7 @@ package org.springframework.data.graph.neo4j.support.node; import org.neo4j.graphdb.Node; import org.springframework.data.graph.core.NodeBacked; -import org.springframework.persistence.support.AbstractConstructorEntityInstantiator; +import org.springframework.data.persistence.AbstractConstructorEntityInstantiator; /** * Implementation of an entity instantiator for neo4j graphdb nodes, binding the entity type to a NodeBacked and the diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java index 3a511de90..59f2409ab 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/node/PartialNeo4jEntityInstantiator.java @@ -20,7 +20,7 @@ import org.neo4j.graphdb.Node; import org.springframework.data.graph.core.NodeBacked; import org.springframework.data.graph.neo4j.fieldaccess.PartialNodeEntityState; import org.springframework.orm.jpa.EntityManagerFactoryUtils; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java index 5ef171ee8..e471d4e7b 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/relationship/ConstructorBypassingGraphRelationshipInstantiator.java @@ -20,7 +20,7 @@ import java.lang.reflect.Constructor; import org.neo4j.graphdb.Relationship; import org.springframework.data.graph.core.RelationshipBacked; -import org.springframework.persistence.support.EntityInstantiator; +import org.springframework.data.persistence.EntityInstantiator; import sun.reflect.ReflectionFactory; From 948e1dfd473755c83f9099ed6ba8fcf78b36f76c Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Thu, 24 Mar 2011 02:22:23 +0100 Subject: [PATCH 20/20] added configuration check --- .../neo4j/config/ConfigurationCheck.java | 67 +++++++++++++++++++ .../neo4j/config/Neo4jConfiguration.java | 5 ++ .../config/ConfigurationConfirmationTest.java | 16 +++++ .../ConfigurationCofirmationTest-context.xml | 25 +++++++ 4 files changed, 113 insertions(+) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/ConfigurationCheck.java create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/config/ConfigurationConfirmationTest.java create mode 100644 spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/config/ConfigurationCofirmationTest-context.xml diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/ConfigurationCheck.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/ConfigurationCheck.java new file mode 100644 index 000000000..c7d0be8d3 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/ConfigurationCheck.java @@ -0,0 +1,67 @@ +package org.springframework.data.graph.neo4j.config; + +import org.neo4j.graphdb.Transaction; +import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; + +import javax.annotation.PostConstruct; + +/** + * Validates correct configuration of Neo4j and Spring, especially transaction-managers + */ +public class ConfigurationCheck { + GraphDatabaseContext graphDatabaseContext; + PlatformTransactionManager transactionManager; + + public ConfigurationCheck(GraphDatabaseContext graphDatabaseContext, PlatformTransactionManager transactionManager) { + this.graphDatabaseContext = graphDatabaseContext; + this.transactionManager = transactionManager; + } + + @PostConstruct + private void checkConfiguration() { + checkInjection(); + checkSpringTransactionManager(); + checkNeo4jTransactionManager(); + } + + private void checkInjection() { + assert graphDatabaseContext.getGraphDatabaseService()!=null : "graphDatabaseService not correctly configured, please refer to the manual, setup section"; + } + + private void checkSpringTransactionManager() { + try { + TransactionStatus transaction = transactionManager.getTransaction(null); + updateStartTime(); + transactionManager.commit(transaction); + } catch(Exception e) { + AssertionError error = new AssertionError("transactionManager not correctly configured, please refer to the manual, setup section"); + error.initCause(e); + throw error; + } + } + + private void checkNeo4jTransactionManager() { + Transaction tx = null; + try { + tx = graphDatabaseContext.beginTx(); + updateStartTime(); + tx.success(); + } catch (Exception e) { + AssertionError error = new AssertionError("transactionManager not correctly configured, please refer to the manual, setup section"); + error.initCause(e); + throw error; + } finally { + try { + if (tx != null) tx.finish(); + } catch(Exception e) { + // ignore + } + } + } + + private void updateStartTime() { + graphDatabaseContext.getReferenceNode().setProperty("startTime", System.currentTimeMillis()); + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java index 1adffa251..0a7e33cb4 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/config/Neo4jConfiguration.java @@ -154,4 +154,9 @@ public class Neo4jConfiguration { return transactionManager; } } + + @Bean + public ConfigurationCheck configurationCheck() throws Exception { + return new ConfigurationCheck(graphDatabaseContext(),transactionManager()); + } } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/config/ConfigurationConfirmationTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/config/ConfigurationConfirmationTest.java new file mode 100644 index 000000000..99bc799f5 --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/config/ConfigurationConfirmationTest.java @@ -0,0 +1,16 @@ +package org.springframework.data.graph.neo4j.config; + +import org.junit.Test; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author mh + * @since 23.03.11 + */ +public class ConfigurationConfirmationTest { + @Test(expected = BeanCreationException.class) + public void testInvalidTransactionManagerFails() { + ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("classpath:org/springframework/data/graph/neo4j/config/ConfigurationCofirmationTest-context.xml"); + } +} diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/config/ConfigurationCofirmationTest-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/config/ConfigurationCofirmationTest-context.xml new file mode 100644 index 000000000..149f0f9c0 --- /dev/null +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/config/ConfigurationCofirmationTest-context.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file