diff --git a/spring-data-neo4j-rest/pom.xml b/spring-data-neo4j-rest/pom.xml index a16d22487..82ef9d30a 100644 --- a/spring-data-neo4j-rest/pom.xml +++ b/spring-data-neo4j-rest/pom.xml @@ -42,7 +42,6 @@ org.springframework.data spring-data-neo4j 1.0.0.BUILD-SNAPSHOT - test org.hibernate diff --git a/spring-data-neo4j-rest/src/main/java/org/neo4j/kernel/RestConfig.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/kernel/RestConfig.java index 87a15ac0b..e8008799a 100644 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/kernel/RestConfig.java +++ b/spring-data-neo4j-rest/src/main/java/org/neo4j/kernel/RestConfig.java @@ -1,8 +1,6 @@ package org.neo4j.kernel; import org.neo4j.graphdb.GraphDatabaseService; -import org.neo4j.kernel.Config; -import org.neo4j.kernel.IdGeneratorFactory; import org.neo4j.kernel.impl.core.*; import org.neo4j.kernel.impl.nioneo.store.FileSystemAbstraction; import org.neo4j.kernel.impl.nioneo.store.StoreId; @@ -48,7 +46,7 @@ public class RestConfig extends Config { } private static class NullTransactionManager implements TransactionManager { - private static final Transaction TRANSACTION = new Transaction() { + private static final Transaction NULL_JAVA_TRANSACTION = new Transaction() { @Override public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException, SystemException { @@ -102,7 +100,7 @@ public class RestConfig extends Config { @Override public Transaction getTransaction() throws SystemException { - return TRANSACTION; + return NULL_JAVA_TRANSACTION; } @Override @@ -127,7 +125,7 @@ public class RestConfig extends Config { @Override public Transaction suspend() throws SystemException { - return TRANSACTION; + return NULL_JAVA_TRANSACTION; } } -} +} \ No newline at end of file diff --git a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/GraphDatabaseFactory.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/GraphDatabaseFactory.java deleted file mode 100644 index 497c61737..000000000 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/GraphDatabaseFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.neo4j.rest.graphdb; - -import org.neo4j.graphdb.GraphDatabaseService; -import org.neo4j.kernel.EmbeddedGraphDatabase; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; - -/** - * @author mh - * @since 25.01.11 - */ -public class GraphDatabaseFactory { - public static GraphDatabaseService databaseFor(String url) { - return databaseFor( url, null,null ); - } - - public static GraphDatabaseService databaseFor(String url, String username, String password) { - if (url.startsWith( "http://" ) || url.startsWith( "https://" )) { - return new RestGraphDatabase( toURI( url ), username,password ); - } - String path=url; - if (url.startsWith( "file:" )) { - path = toURI( url ).getPath(); - } - File file = new File( path ); - if (!file.isDirectory()) file=file.getParentFile(); - return new EmbeddedGraphDatabase( file.getAbsolutePath() ); - } - - private static URI toURI( String uri ) { - try { - return new URI(uri); - } catch ( URISyntaxException e ) { - throw new RuntimeException( "Error using URI "+uri, e); - } - } -} diff --git a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestEntity.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestEntity.java index 2b9c201a9..aa06cb93a 100644 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestEntity.java +++ b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestEntity.java @@ -1,6 +1,7 @@ package org.neo4j.rest.graphdb; import com.sun.jersey.api.client.ClientResponse; +import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.NotFoundException; import org.neo4j.graphdb.PropertyContainer; import org.neo4j.helpers.collection.IterableWrapper; @@ -154,7 +155,11 @@ public class RestEntity implements PropertyContainer { return getClass().equals( o.getClass() ) && getId() == ( (RestEntity) o ).getId(); } - public RestGraphDatabase getGraphDatabase() { + public GraphDatabaseService getGraphDatabase() { + throw new UnsupportedOperationException("No GraphDatabaseService semantics for the REST-API"); + } + + public RestGraphDatabase getRestGraphDatabase() { return graphDatabase; } diff --git a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestGraphDatabase.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestGraphDatabase.java index dc11bcbfa..eaca8e9f2 100644 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestGraphDatabase.java +++ b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestGraphDatabase.java @@ -4,18 +4,22 @@ import com.sun.jersey.api.client.ClientResponse; import org.neo4j.graphdb.*; import org.neo4j.graphdb.event.KernelEventHandler; import org.neo4j.graphdb.event.TransactionEventHandler; -import org.neo4j.graphdb.index.IndexManager; +import org.neo4j.graphdb.index.Index; +import org.neo4j.graphdb.traversal.TraversalDescription; import org.neo4j.kernel.AbstractGraphDatabase; import org.neo4j.kernel.Config; import org.neo4j.kernel.RestConfig; import org.neo4j.rest.graphdb.index.RestIndexManager; +import org.springframework.data.graph.core.GraphDatabase; +import org.springframework.data.graph.core.Property; import javax.ws.rs.core.Response.Status; import java.io.Serializable; import java.net.URI; import java.util.Map; -public class RestGraphDatabase extends AbstractGraphDatabase { +public class RestGraphDatabase extends AbstractGraphDatabase implements GraphDatabase { + private RestRequest restRequest; private long propertyRefetchTimeInMillis = 1000; @@ -28,86 +32,62 @@ public class RestGraphDatabase extends AbstractGraphDatabase { restRequest = new RestRequest( uri, user, password ); } - public Transaction beginTx() { - return new Transaction() { - public void success() { - } - - public void finish() { - - } - - public void failure() { - } - }; + @Override + public Node getNodeById(long id) { + ClientResponse response = restRequest.get("node/" + id); + if ( restRequest.statusIs(response, Status.NOT_FOUND) ) { + throw new NotFoundException( "" + id ); + } + return new RestNode( restRequest.toMap(response), this ); } - public TransactionEventHandler registerTransactionEventHandler( TransactionEventHandler tTransactionEventHandler ) { - throw new UnsupportedOperationException(); - } - - public TransactionEventHandler unregisterTransactionEventHandler( TransactionEventHandler tTransactionEventHandler ) { - throw new UnsupportedOperationException(); - } - - public KernelEventHandler registerKernelEventHandler( KernelEventHandler kernelEventHandler ) { - throw new UnsupportedOperationException(); - } - - public KernelEventHandler unregisterKernelEventHandler( KernelEventHandler kernelEventHandler ) { - throw new UnsupportedOperationException(); - } - - public IndexManager index() { - return new RestIndexManager( restRequest, this ); - } - - public Node createNode() { - ClientResponse response = restRequest.post( "node", null ); - if ( restRequest.statusOtherThan( response, Status.CREATED ) ) { + @Override + public Node createNode(Property... props) { + ClientResponse response = restRequest.post("node", null); + if ( restRequest.statusOtherThan(response, Status.CREATED) ) { throw new RuntimeException( "" + response.getStatus() ); } return new RestNode( response.getLocation(), this ); } - public boolean enableRemoteShell() { - throw new UnsupportedOperationException(); - } - - public boolean enableRemoteShell( Map config ) { - throw new UnsupportedOperationException(); - } - - public Iterable getAllNodes() { - throw new UnsupportedOperationException(); - } - - public Node getNodeById( long id ) { - ClientResponse response = restRequest.get( "node/" + id ); - if ( restRequest.statusIs( response, Status.NOT_FOUND ) ) { - throw new NotFoundException( "" + id ); - } - return new RestNode( restRequest.toMap( response ), this ); - } - - public Node getReferenceNode() { - Map map = restRequest.toMap( restRequest.get( "" ) ); - return new RestNode( (String) map.get( "reference_node" ), this ); - } - - public Relationship getRelationshipById( long id ) { - ClientResponse response = restRequest.get( "relationship/" + id ); + @Override + public Relationship getRelationshipById(long id) { + ClientResponse response = restRequest.get("relationship/" + id); if ( restRequest.statusIs( response, Status.NOT_FOUND ) ) { throw new NotFoundException( "" + id ); } return new RestRelationship( restRequest.toMap( response ), this ); } - public Iterable getRelationshipTypes() { - throw new UnsupportedOperationException(); + @Override + public Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Property... props) { + Relationship relationship = startNode.createRelationshipTo(endNode, type); + return relationship; } - public void shutdown() { + @Override + public Index getIndex(String indexName) { + return (Index) index().forNodes(indexName); // todo + } + + @Override + public Index createIndex(Class type, String indexName, boolean fullText) { + return (Index) index().forNodes(indexName); // todo + } + + @Override + public TraversalDescription createTraversalDescription() { + return new RestTraversal(); + } + + public RestIndexManager index() { + return new RestIndexManager( restRequest, this ); + } + + @Override + public Node getReferenceNode() { + Map map = restRequest.toMap( restRequest.get( "" ) ); + return new RestNode( (String) map.get( "reference_node" ), this ); } public RestRequest getRestRequest() { @@ -117,9 +97,77 @@ public class RestGraphDatabase extends AbstractGraphDatabase { public long getPropertyRefetchTimeInMillis() { return propertyRefetchTimeInMillis; } + + @Override + public Node createNode() { + return createNode((Property[])null); + } + + @Override + public Iterable getAllNodes() { + throw new UnsupportedOperationException(); + } + + @Override + public Iterable getRelationshipTypes() { + throw new UnsupportedOperationException(); + } + + @Override + public void shutdown() { + + } + + @Override + public boolean enableRemoteShell() { + return false; + } + + @Override + public boolean enableRemoteShell(Map initialProperties) { + return false; + } + + @Override + public Transaction beginTx() { + return new Transaction() { + @Override + public void failure() { + } + + @Override + public void success() { + } + + @Override + public void finish() { + } + }; + } + + @Override + public TransactionEventHandler registerTransactionEventHandler(TransactionEventHandler handler) { + return handler; + } + + @Override + public TransactionEventHandler unregisterTransactionEventHandler(TransactionEventHandler handler) { + return handler; + } + + @Override + public KernelEventHandler registerKernelEventHandler(KernelEventHandler handler) { + return handler; + } + + @Override + public KernelEventHandler unregisterKernelEventHandler(KernelEventHandler handler) { + return handler; + } + @Override public String getStoreDir() { - return restRequest.getUri().toString(); + return getRestRequest().getUri().toString(); } @Override diff --git a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestNode.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestNode.java index 27bdb2a60..b0870e38e 100644 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestNode.java +++ b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestNode.java @@ -35,7 +35,7 @@ public class RestNode extends RestEntity implements Node { if ( restRequest.statusOtherThan( response, Status.CREATED ) ) { throw new RuntimeException( "" + response.getStatus() ); } - return new RestRelationship( response.getLocation(), getGraphDatabase() ); + return new RestRelationship( response.getLocation(), getRestGraphDatabase() ); } public Iterable getRelationships() { @@ -48,7 +48,7 @@ public class RestNode extends RestEntity implements Node { (Collection) restRequest.toEntity( response ) ) { @Override protected Relationship underlyingObjectToObject( Object data ) { - return new RestRelationship( (Map) data, getGraphDatabase() ); + return new RestRelationship( (Map) data, getRestGraphDatabase() ); } }; } diff --git a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestRelationship.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestRelationship.java index 1ec933624..e81600200 100644 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestRelationship.java +++ b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestRelationship.java @@ -44,7 +44,7 @@ public class RestRelationship extends RestEntity implements Relationship { } private RestNode node( String uri ) { - return new RestNode( uri, getGraphDatabase() ); + return new RestNode( uri, getRestGraphDatabase() ); } public Node getStartNode() { diff --git a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestTraversal.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestTraversal.java index ba2a734d1..d7598115a 100644 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestTraversal.java +++ b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestTraversal.java @@ -207,7 +207,7 @@ public class RestTraversal implements RestTraversalDescription { throw new RuntimeException( String.format( "Unexpected traversal result, %s instead of collection", col != null ? col.getClass() : null ) ); } - return new RestTraverser( (Collection)col, restNode.getGraphDatabase() ); + return new RestTraverser( (Collection)col, restNode.getRestGraphDatabase() ); } public static RestTraversalDescription description() diff --git a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/index/RestRelationshipIndex.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/index/RestRelationshipIndex.java index bf817329c..6c10d608b 100644 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/index/RestRelationshipIndex.java +++ b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/index/RestRelationshipIndex.java @@ -22,13 +22,13 @@ public class RestRelationshipIndex extends RestIndex implements Re return Relationship.class; } - public void remove(Relationship entity, String key) { - throw new UnsupportedOperationException(); - } - - public void remove(Relationship entity) { - throw new UnsupportedOperationException(); - } +// public void remove(Relationship entity, String key) { +// throw new UnsupportedOperationException(); +// } +// +// public void remove(Relationship entity) { +// throw new UnsupportedOperationException(); +// } protected Relationship createEntity( Map item ) { return new RestRelationship( (Map) item, restGraphDatabase ); diff --git a/spring-data-neo4j-rest/src/test/java/org/neo4j/rest/graphdb/RestTestBase.java b/spring-data-neo4j-rest/src/test/java/org/neo4j/rest/graphdb/RestTestBase.java index 03851bc5f..d737eb92f 100644 --- a/spring-data-neo4j-rest/src/test/java/org/neo4j/rest/graphdb/RestTestBase.java +++ b/spring-data-neo4j-rest/src/test/java/org/neo4j/rest/graphdb/RestTestBase.java @@ -1,23 +1,13 @@ package org.neo4j.rest.graphdb; -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.ClientResponse; import org.apache.log4j.BasicConfigurator; -import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.neo4j.graphdb.Direction; -import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; -import org.neo4j.server.AddressResolver; -import org.neo4j.server.NeoServerWithEmbeddedWebServer; -import org.neo4j.server.modules.RESTApiModule; -import org.neo4j.server.modules.ThirdPartyJAXRSModule; -import org.neo4j.server.startup.healthcheck.StartupHealthCheck; -import org.neo4j.server.web.Jetty6WebServer; import java.net.URI; import java.net.URISyntaxException; @@ -25,7 +15,7 @@ import java.util.Iterator; public class RestTestBase { - protected GraphDatabaseService graphDb; + protected RestGraphDatabase graphDb; private static final String HOSTNAME = "localhost"; private static final int PORT = 7473; private static LocalTestServer neoServer = new LocalTestServer(HOSTNAME,PORT).withPropertiesFile("test-db.properties"); @@ -47,11 +37,6 @@ public class RestTestBase { neoServer.cleanDb(); } - @After - public void tearDown() throws Exception { - graphDb.shutdown(); - } - @AfterClass public static void shutdownDb() { neoServer.stop(); @@ -61,7 +46,7 @@ public class RestTestBase { protected Relationship relationship() { Iterator it = node().getRelationships(Direction.OUTGOING).iterator(); if (it.hasNext()) return it.next(); - return node().createRelationshipTo(graphDb.createNode(), Type.TEST); + return node().createRelationshipTo(graphDb.createNode(null), Type.TEST); } protected Node node() { diff --git a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestEntityPropertyValidationTest.java b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestEntityPropertyValidationTest.java index cb50843f9..0c3e7760d 100644 --- a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestEntityPropertyValidationTest.java +++ b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestEntityPropertyValidationTest.java @@ -24,20 +24,20 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) public class RestEntityPropertyValidationTest extends EntityPropertyValidationTest { -@BeforeClass -public static void startDb() throws Exception { - RestTestBase.startDb(); -} + @BeforeClass + public static void startDb() throws Exception { + RestTestBase.startDb(); + } -@Before -public void cleanDb() { - RestTestBase.cleanDb(); -} + @Before + public void cleanDb() { + RestTestBase.cleanDb(); + } -@AfterClass -public static void shutdownDb() { - RestTestBase.shutdownDb(); - -} + @AfterClass + public static void shutdownDb() { + RestTestBase.shutdownDb(); + + } } diff --git a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestFinderTest.java b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestFinderTest.java index 1aa1bc306..14c9200c7 100644 --- a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestFinderTest.java +++ b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestFinderTest.java @@ -5,8 +5,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.neo4j.rest.graphdb.RestTestBase; -import org.springframework.data.graph.neo4j.support.FinderTest; -import org.springframework.data.graph.neo4j.support.IndexTest; +import org.springframework.data.graph.neo4j.support.GraphRepositoryTest; import org.springframework.test.context.CleanContextCacheTestExecutionListener; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; @@ -22,22 +21,22 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi @ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml", "classpath:RestTest-context.xml"}) @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) -public class RestFinderTest extends FinderTest { +public class RestFinderTest extends GraphRepositoryTest { -@BeforeClass -public static void startDb() throws Exception { - RestTestBase.startDb(); -} + @BeforeClass + public static void startDb() throws Exception { + RestTestBase.startDb(); + } -@Before -public void cleanDb() { - RestTestBase.cleanDb(); -} + @Before + public void cleanDb() { + RestTestBase.cleanDb(); + } -@AfterClass -public static void shutdownDb() { - RestTestBase.shutdownDb(); - -} + @AfterClass + public static void shutdownDb() { + RestTestBase.shutdownDb(); + + } } diff --git a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestNodeEntityRelationshipTest.java b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestNodeEntityRelationshipTest.java index 9b0e4f934..005eef546 100644 --- a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestNodeEntityRelationshipTest.java +++ b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestNodeEntityRelationshipTest.java @@ -27,20 +27,20 @@ import java.net.NoRouteToHostException; @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) public class RestNodeEntityRelationshipTest extends NodeEntityRelationshipTest { -@BeforeClass -public static void startDb() throws Exception { - RestTestBase.startDb(); -} + @BeforeClass + public static void startDb() throws Exception { + RestTestBase.startDb(); + } -@Before -public void cleanDb() { - RestTestBase.cleanDb(); -} + @Before + public void cleanDb() { + RestTestBase.cleanDb(); + } -@AfterClass -public static void shutdownDb() { - RestTestBase.shutdownDb(); - -} + @AfterClass + public static void shutdownDb() { + RestTestBase.shutdownDb(); + + } } diff --git a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestProjectionTest.java b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestProjectionTest.java index 5fb6117fe..c251b427c 100644 --- a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestProjectionTest.java +++ b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestProjectionTest.java @@ -6,7 +6,6 @@ import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.neo4j.rest.graphdb.RestTestBase; import org.springframework.data.graph.neo4j.support.ProjectionTest; -import org.springframework.data.graph.neo4j.support.RelationshipEntityTest; import org.springframework.test.context.CleanContextCacheTestExecutionListener; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; @@ -24,20 +23,20 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) public class RestProjectionTest extends ProjectionTest { -@BeforeClass -public static void startDb() throws Exception { -RestTestBase.startDb(); -} + @BeforeClass + public static void startDb() throws Exception { + RestTestBase.startDb(); + } -@Before -public void cleanDb() { -RestTestBase.cleanDb(); -} + @Before + public void cleanDb() { + RestTestBase.cleanDb(); + } -@AfterClass -public static void shutdownDb() { -RestTestBase.shutdownDb(); - -} + @AfterClass + public static void shutdownDb() { + RestTestBase.shutdownDb(); + + } } diff --git a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestPropertyTest.java b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestPropertyTest.java index a26152a29..94c78e11b 100644 --- a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestPropertyTest.java +++ b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestPropertyTest.java @@ -24,20 +24,20 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) public class RestPropertyTest extends PropertyTest { -@BeforeClass -public static void startDb() throws Exception { -RestTestBase.startDb(); -} + @BeforeClass + public static void startDb() throws Exception { + RestTestBase.startDb(); + } -@Before -public void cleanDb() { -RestTestBase.cleanDb(); -} + @Before + public void cleanDb() { + RestTestBase.cleanDb(); + } -@AfterClass -public static void shutdownDb() { -RestTestBase.shutdownDb(); - -} + @AfterClass + public static void shutdownDb() { + RestTestBase.shutdownDb(); + + } } diff --git a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestRelationshipEntityTest.java b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestRelationshipEntityTest.java index 43706ddb5..fb69ae869 100644 --- a/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestRelationshipEntityTest.java +++ b/spring-data-neo4j-rest/src/test/java/org/springframework/data/graph/neo4j/rest/RestRelationshipEntityTest.java @@ -24,20 +24,20 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) public class RestRelationshipEntityTest extends RelationshipEntityTest { -@BeforeClass -public static void startDb() throws Exception { -RestTestBase.startDb(); -} + @BeforeClass + public static void startDb() throws Exception { + RestTestBase.startDb(); + } -@Before -public void cleanDb() { -RestTestBase.cleanDb(); -} + @Before + public void cleanDb() { + RestTestBase.cleanDb(); + } -@AfterClass -public static void shutdownDb() { -RestTestBase.shutdownDb(); - -} + @AfterClass + public static void shutdownDb() { + RestTestBase.shutdownDb(); + + } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabase.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabase.java new file mode 100644 index 000000000..d73b2ec94 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabase.java @@ -0,0 +1,82 @@ +package org.springframework.data.graph.core; + +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.PropertyContainer; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.RelationshipType; +import org.neo4j.graphdb.index.Index; +import org.neo4j.graphdb.traversal.TraversalDescription; + +/** + * @author mh + * @since 29.03.11 + */ +public interface GraphDatabase { + /** + * @return the reference node of the underlying graph database + */ + Node getReferenceNode(); + + /** + * @param id node id + * @return the requested node of the underlying graph database + * @throws org.neo4j.graphdb.NotFoundException + */ + Node getNodeById(long id); + + /** + * Transactionally creates the node, sets the properties (if any). + * Two shortcut means of providing the properties (very short with static imports) + * graphDatabase.createNode(PropertyMap._("name","value")); + * graphDatabase.createNode(PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop"); + * + * @param props properties to be set at node creation might be null + * @return the newly created node + */ + Node createNode(Property... props); + + /** + * @param id relationship id + * @return the requested relationship of the underlying graph database + * @throws org.neo4j.graphdb.NotFoundException + */ + Relationship getRelationshipById(long id); + + /** + * Transactionally creates the relationship, sets the properties (if any) and indexes the given fielss (if any) + * Two shortcut means of providing the properties (very short with static imports) + * graphDatabase.createRelationship(from,to,TYPE, PropertyMap._("name","value")); + * graphDatabase.createRelationship(from,to,TYPE, PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop"); + * + * + * @param startNode start-node of relationship + * @param endNode end-node of relationship + * @param type relationship type, might by an enum implementing RelationshipType or a DynamicRelationshipType.withName("name") + * @param props optional initial properties + * @return the newly created relationship + */ + Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Property... props); + + /** + * @param indexName existing index name, not null + * @return existing index {@link Index} + * @throws IllegalArgumentException if the index doesn't exist + */ + Index getIndex(String indexName); + + /** + * creates a index + * @param type type of index requested - either Node.class or Relationship.class + * @param indexName, not null + * @param fullText true if a fulltext queryable index is needed, false for exact match + * @return node index {@link Index} + */ + Index createIndex(Class type, String indexName, boolean fullText); + + + /** + * @return a TraversalDescription as starting point for defining a traversal + */ + TraversalDescription createTraversalDescription(); + +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabaseFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabaseFactory.java new file mode 100644 index 000000000..f2d3a6740 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabaseFactory.java @@ -0,0 +1,89 @@ +package org.springframework.data.graph.core; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.kernel.EmbeddedGraphDatabase; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.data.graph.neo4j.support.DelegatingGraphDatabase; + +import javax.annotation.PreDestroy; +import java.io.File; +import java.lang.reflect.Constructor; +import java.net.URI; + +/** + * @author mh + * @since 25.01.11 + */ +public class GraphDatabaseFactory implements FactoryBean { + + private String storeLocation; + private String userName; + private String password; + protected GraphDatabase graphDatabase; + + public String getStoreLocation() { + return storeLocation; + } + + public void setStoreLocation(String storeLocation) { + this.storeLocation = storeLocation; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + private GraphDatabase databaseFor(String url, String username, String password) throws Exception { + if (url.startsWith( "http://" ) || url.startsWith( "https://" )) { + return createRestGraphDatabase(url, username, password); + } + String path=url; + if (url.startsWith( "file:" )) { + path = new URI(url).getPath(); + } + File file = new File( path ); + // if (!file.isDirectory()) file=file.getParentFile(); + return new DelegatingGraphDatabase(new EmbeddedGraphDatabase(file.getAbsolutePath())); + } + + private GraphDatabase createRestGraphDatabase(String url, String username, String password) throws Exception { + Class restGraphDatabaseClass = Class.forName("org.neo4j.rest.graphdb.RestGraphDatabase"); + Constructor constructor = restGraphDatabaseClass.getConstructor(URI.class, String.class, String.class); + return (GraphDatabase) constructor.newInstance(new URI(url), username,password ); + } + + @Override + public GraphDatabase getObject() throws Exception { + if (graphDatabase==null) graphDatabase = databaseFor(storeLocation, userName, password); + return graphDatabase; + } + + @PreDestroy + public void shutdown() { + if (graphDatabase instanceof DelegatingGraphDatabase) { + ((DelegatingGraphDatabase)graphDatabase).shutdown(); + } + } + + @Override + public Class getObjectType() { + return GraphDatabaseService.class; + } + + @Override + public boolean isSingleton() { + return true; + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/Property.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/Property.java new file mode 100644 index 000000000..06f0de6af --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/Property.java @@ -0,0 +1,48 @@ +package org.springframework.data.graph.core; + +import java.util.Map; + +/** + * @author mh + * @since 31.03.11 + */ +public class Property { + public final String name; + public final Object value; + + public Property(String name, Object value) { + this.name = name; + this.value = value; + } + + public static Property _(String name, Object value) { + return new Property(name, value); + } + + public static Property[] _(String name1, Object value1, String name2, Object value2) { + return new Property[]{new Property(name1, value1), new Property(name2, value2)}; + } + + public static Property[] _(String name1, Object value1, String name2, Object value2, String name3, Object value3) { + return new Property[]{new Property(name1, value1), new Property(name2, value2), new Property(name3, value3)}; + } + + public static Property[] _(Object... nameValuePairs) { + if (nameValuePairs.length % 2 != 0) + throw new IllegalArgumentException("there must be an even number of name value pairs"); + Property[] result = new Property[nameValuePairs.length / 2]; + for (int i = 0; i < result.length; i++) { + result[i] = new Property(nameValuePairs[i * 2].toString(), nameValuePairs[i * 2 + 1]); + } + return result; + } + + public static Property[] _(Map properties) { + Property[] result = new Property[properties.size()]; + int i = 0; + for (Map.Entry entry : properties.entrySet()) { + result[i++] = new Property(entry.getKey(), entry.getValue()); + } + return result; + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/TypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/TypeRepresentationStrategy.java index 861ad5c9a..2cb502d65 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/TypeRepresentationStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/TypeRepresentationStrategy.java @@ -31,9 +31,10 @@ import org.neo4j.graphdb.PropertyContainer; */ public interface TypeRepresentationStrategy> { /** - * callback on entity creation for setting up type representation - * @param state - * @param type + * Callback for setting up and/or storing type information after creation. + * + * @param state Backing state of entity being created + * @param type Type of entity being created */ void postEntityCreation(S state, Class type); @@ -57,10 +58,12 @@ public interface TypeRepresentationStrategy Class getJavaType(S state); /** - * callback for lifecycle management before node entity removal - * @param entity + * Callback for cleaning up type information before removal. If state does not have any + * state associated, doesn't do anything. + * + * @param state Backing state of entity being removed */ - void preEntityRemoval(T entity); + void preEntityRemoval(S state); /** * Instantiate the entity given its state. The type of the entity is inferred by the strategy diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java index 7c2b95a25..1fc71af85 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/AbstractNodeRelationshipFieldAccessor.java @@ -16,10 +16,7 @@ package org.springframework.data.graph.neo4j.fieldaccess; -import org.neo4j.graphdb.Direction; -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.Relationship; -import org.neo4j.graphdb.RelationshipType; +import org.neo4j.graphdb.*; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.graph.core.GraphBacked; import org.springframework.data.graph.neo4j.support.GraphDatabaseContext; @@ -31,7 +28,7 @@ import java.util.Set; * @author Michael Hunger * @since 11.09.2010 */ -public abstract class AbstractNodeRelationshipFieldAccessor implements FieldAccessor { +public abstract class AbstractNodeRelationshipFieldAccessor implements FieldAccessor { protected final RelationshipType type; protected final Direction direction; protected final Class relatedType; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java index a9fe581a9..d3387a1d6 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/ConvertingNodePropertyFieldAccessorFactory.java @@ -46,7 +46,7 @@ public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessor @Override public FieldAccessor> forField(final Field field) { - return new ConvertingNodePropertyFieldAccessor(field, conversionService); + return new ConvertingNodePropertyFieldAccessor(conversionService, DelegatingFieldAccessorFactory.getNeo4jPropertyName(field),field.getType()); } private boolean isSerializableField(final Field field) { @@ -67,8 +67,8 @@ public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessor public static class ConvertingNodePropertyFieldAccessor extends PropertyFieldAccessorFactory.PropertyFieldAccessor { private final ConversionService conversionService; - public ConvertingNodePropertyFieldAccessor(final Field field, final ConversionService conversionService) { - super(field, conversionService); + public ConvertingNodePropertyFieldAccessor(ConversionService conversionService, String propertyName, Class fieldType) { + super(conversionService,propertyName,fieldType); this.conversionService = conversionService; } @@ -88,7 +88,7 @@ public class ConvertingNodePropertyFieldAccessorFactory implements FieldAccessor } private Object deserializePropertyValue(final Object value) { - return conversionService.convert(value, field.getType()); + return conversionService.convert(value, fieldType); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PropertyFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PropertyFieldAccessorFactory.java index 568455f38..ff9e02a6c 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PropertyFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/fieldaccess/PropertyFieldAccessorFactory.java @@ -43,7 +43,7 @@ public class PropertyFieldAccessorFactory implements FieldAccessorFactory> forField(final Field field) { - return new PropertyFieldAccessor(field,conversionService); + return new PropertyFieldAccessor(conversionService,DelegatingFieldAccessorFactory.getNeo4jPropertyName(field),field.getType()); } private boolean isNeo4jPropertyType(final Class fieldType) { @@ -57,12 +57,14 @@ public class PropertyFieldAccessorFactory implements FieldAccessorFactory> { - protected final Field field; private final ConversionService conversionService; + protected final String propertyName; + protected final Class fieldType; - public PropertyFieldAccessor(final Field field, ConversionService conversionService) { - this.field = field; + public PropertyFieldAccessor(ConversionService conversionService, String propertyName, Class fieldType) { this.conversionService = conversionService; + this.propertyName = propertyName; + this.fieldType = fieldType; } @Override @@ -74,9 +76,9 @@ public class PropertyFieldAccessorFactory implements FieldAccessorFactory graphBacked, final Object newVal) { final PropertyContainer propertyContainer = graphBacked.getPersistentState(); if (newVal==null) { - propertyContainer.removeProperty(getPropertyName()); + propertyContainer.removeProperty(propertyName); } else { - propertyContainer.setProperty(getPropertyName(), newVal); + propertyContainer.setProperty(propertyName, newVal); } return newVal; } @@ -87,17 +89,16 @@ public class PropertyFieldAccessorFactory implements FieldAccessorFactory graphBacked) { - Class type = field.getType(); - Object value = graphBacked.getPersistentState().getProperty(getPropertyName(), getDefaultValue(type)); - if (value == null || type.isInstance(value)) return value; - if (conversionService!=null) { - return conversionService.convert(value,type); + PropertyContainer element = graphBacked.getPersistentState(); + if (element.hasProperty(propertyName)) { + Object value = element.getProperty(propertyName); + if (value == null || fieldType.isInstance(value)) return value; + if (conversionService!=null) { + return conversionService.convert(value, fieldType); + } + return value; } - return value; - } - - private String getPropertyName() { - return DelegatingFieldAccessorFactory.getNeo4jPropertyName(field); + return getDefaultValue(fieldType); } private Object getDefaultValue(final Class type) { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/DelegatingGraphDatabase.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/DelegatingGraphDatabase.java new file mode 100644 index 000000000..9ac73e436 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/DelegatingGraphDatabase.java @@ -0,0 +1,115 @@ +package org.springframework.data.graph.neo4j.support; + +import org.neo4j.graphdb.*; +import org.neo4j.graphdb.index.Index; +import org.neo4j.graphdb.index.IndexManager; +import org.neo4j.graphdb.traversal.TraversalDescription; +import org.neo4j.index.impl.lucene.LuceneIndexImplementation; +import org.neo4j.kernel.AbstractGraphDatabase; +import org.neo4j.kernel.Traversal; +import org.springframework.data.graph.core.GraphDatabase; +import org.springframework.data.graph.core.NodeBacked; +import org.springframework.data.graph.core.Property; +import org.springframework.data.graph.core.RelationshipBacked; + +import java.util.Map; + +/** + * @author mh + * @since 29.03.11 + */ +public class DelegatingGraphDatabase implements GraphDatabase { + + protected AbstractGraphDatabase delegate; + + public DelegatingGraphDatabase(final AbstractGraphDatabase delegate) { + this.delegate = delegate; + } + + @Override + public Node getReferenceNode() { + return delegate.getReferenceNode(); + } + + @Override + public Node getNodeById(long id) { + return delegate.getNodeById(id); + } + + @Override + public Node createNode(Property... props) { + return setProperties(delegate.createNode(), props); + } + + private T setProperties(T primitive, Property... properties) { + assert primitive != null; + if (properties==null || properties.length==0) return primitive; + for (Property prop : properties) { + if (prop.value==null) { + primitive.removeProperty(prop.name); + } else { + primitive.setProperty(prop.name, prop.value); + } + } + return primitive; + } + + @Override + public Relationship getRelationshipById(long id) { + return delegate.getRelationshipById(id); + } + + @Override + public Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Property... props) { + return setProperties(startNode.createRelationshipTo(endNode,type),props); + } + + @Override + public Index getIndex(String indexName) { + IndexManager indexManager = delegate.index(); + if (indexManager.existsForNodes(indexName)) return (Index) indexManager.forNodes(indexName); + if (indexManager.existsForRelationships(indexName)) return (Index) indexManager.forRelationships(indexName); + throw new IllegalArgumentException("Index "+indexName+" does not exist."); + } + + // TODO handle existing indexes + @Override + public Index createIndex(Class type, String indexName, boolean fullText) { + IndexManager indexManager = delegate.index(); + if (isNode(type)) { + if (indexManager.existsForNodes(indexName)) + return (Index) checkAndGetExistingIndex(indexName, fullText, indexManager.forNodes(indexName)); + return (Index) indexManager.forNodes(indexName, indexConfigFor(fullText)); + } else { + if (indexManager.existsForRelationships(indexName)) + return (Index) checkAndGetExistingIndex(indexName, fullText, indexManager.forRelationships(indexName)); + return (Index) indexManager.forRelationships(indexName, indexConfigFor(fullText)); + } + } + + public boolean isNode(Class type) { + if (type.equals(Node.class)) return true; + if (type.equals(Relationship.class)) return false; + throw new IllegalArgumentException("Unknown Graph Primitive, neither Node nor Relationship"+type); + } + + private Index checkAndGetExistingIndex(final String indexName, boolean fullText, final Index index) { + Map existingConfig = delegate.index().getConfiguration(index); + Map config = indexConfigFor(fullText); + if (config.equals(existingConfig)) return index; + throw new IllegalArgumentException("Setup for index "+indexName+" does not match "+(fullText ? "fulltext":"exact")); + } + + private Map indexConfigFor(boolean fullText) { + return fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : LuceneIndexImplementation.EXACT_CONFIG; + } + + @Override + public TraversalDescription createTraversalDescription() { + return Traversal.description(); + } + + public void shutdown() { + delegate.shutdown(); + } +} 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 95a6e1316..3fcfd3e1d 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 @@ -44,19 +44,206 @@ import java.util.Map; */ public class GraphDatabaseContext { + private static final Log log = LogFactory.getLog(GraphDatabaseContext.class); public static final String DEFAULT_NODE_INDEX_NAME = "node"; public static final String DEFAULT_RELATIONSHIP_INDEX_NAME = "relationship"; private GraphDatabaseService graphDatabaseService; - private ConversionService conversionService; + private Validator validator; private NodeTypeRepresentationStrategy nodeTypeRepresentationStrategy; + private RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy; - private Validator validator; - private final static Log log = LogFactory.getLog(GraphDatabaseContext.class); + + public > Index getIndex(Class type) { + return getIndex(type, null); + } + + public > Index getIndex(Class type, String indexName) { + return getIndex(type, indexName, false); + } + + + public > Index getIndex(Class type, String indexName, boolean fullText) { + if (indexName==null) indexName = Indexed.Name.get(type); + Map config = fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : null; + if (NodeBacked.class.isAssignableFrom(type)) return (Index) getIndexManager().forNodes(indexName, config); + if (RelationshipBacked.class.isAssignableFrom(type)) return (Index) getIndexManager().forRelationships(indexName, config); + throw new IllegalArgumentException("Wrong index type supplied: " + type); + } + + /** + * @return true if a transaction manager is available and a transaction is currently running + */ + public boolean transactionIsRunning() { + try { + return getTxManager().getStatus() != Status.STATUS_NO_TRANSACTION; + } catch (SystemException e) { + log.error("Error accessing TransactionManager", e); + return false; + } + } + + public > Iterable findAll(final Class entityClass) { + return getTypeRepresentationStrategy(entityClass).findAll(entityClass); + } + + public > long count(final Class entityClass) { + return getTypeRepresentationStrategy(entityClass).count(entityClass); + } + + + + public > T createEntityFromStoredType(S state) { + return getTypeRepresentationStrategy(state).createEntity(state); + } + + public > T createEntityFromState(S state, Class type) { + if (state==null) throw new IllegalArgumentException("state has to be either a Node or Relationship, not null"); + return getTypeRepresentationStrategy(state, type).createEntity(state, type); + } + + public > T projectTo(GraphBacked entity, Class targetType) { + S state = entity.getPersistentState(); + return getTypeRepresentationStrategy(state, targetType).projectEntity(state, targetType); + } + + public > void postEntityCreation(S node, Class entityClass) { + getTypeRepresentationStrategy(node, entityClass).postEntityCreation(node, entityClass); + } + + + public void removeNodeEntity(NodeBacked entity) { + Node node = entity.getPersistentState(); + if (node == null) return; + nodeTypeRepresentationStrategy.preEntityRemoval(node); + for (Relationship relationship : node.getRelationships()) { + removeRelationship(relationship); + } + removeFromIndexes(node); + node.delete(); + } + + public void removeRelationshipEntity(RelationshipBacked entity) { + Relationship relationship = entity.getPersistentState(); + if (relationship == null) return; + removeRelationship(relationship); + } + + private void removeRelationship(Relationship relationship) { + relationshipTypeRepresentationStrategy.preEntityRemoval(relationship); + removeFromIndexes(relationship); + relationship.delete(); + } + + private void removeFromIndexes(Node node) { + IndexManager indexManager = getIndexManager(); + for (String indexName : indexManager.nodeIndexNames()) { + indexManager.forNodes(indexName).remove(node); + } + } + + private void removeFromIndexes(Relationship relationship) { + IndexManager indexManager = getIndexManager(); + for (String indexName : indexManager.relationshipIndexNames()) { + indexManager.forRelationships(indexName).remove(relationship); + } + } + + private IndexManager getIndexManager() { + return graphDatabaseService.index(); + } + + + + @SuppressWarnings("unchecked") + private > + TypeRepresentationStrategy getTypeRepresentationStrategy(Class type) { + if (NodeBacked.class.isAssignableFrom(type)) { + return (TypeRepresentationStrategy) nodeTypeRepresentationStrategy; + } else if (RelationshipBacked.class.isAssignableFrom(type)) { + return (TypeRepresentationStrategy) relationshipTypeRepresentationStrategy; + } + throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked."); + } + + @SuppressWarnings("unchecked") + private > + TypeRepresentationStrategy getTypeRepresentationStrategy(S state, Class type) { + if (state instanceof Node && NodeBacked.class.isAssignableFrom(type)) { + return (TypeRepresentationStrategy) nodeTypeRepresentationStrategy; + } else if (state instanceof Relationship && RelationshipBacked.class.isAssignableFrom(type)) { + return (TypeRepresentationStrategy) relationshipTypeRepresentationStrategy; + } + throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked."); + } + + @SuppressWarnings("unchecked") + private > + TypeRepresentationStrategy getTypeRepresentationStrategy(S state) { + if (state instanceof Node) { + return (TypeRepresentationStrategy) nodeTypeRepresentationStrategy; + } else if (state instanceof Relationship) { + return (TypeRepresentationStrategy) relationshipTypeRepresentationStrategy; + } + throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked."); + } + + + + /** + * @return Neo4j Transaction manager + */ + public TransactionManager getTxManager() { + return ((AbstractGraphDatabase) graphDatabaseService).getConfig().getTxModule().getTxManager(); + } + + /** + * Delegates to {@link GraphDatabaseService} + */ + public Node createNode() { + return graphDatabaseService.createNode(); + } + + /** + * Delegates to {@link GraphDatabaseService} + */ + public Node getNodeById(final long nodeId) { + return graphDatabaseService.getNodeById(nodeId); + } + + /** + * Delegates to {@link GraphDatabaseService} + */ + public Node getReferenceNode() { + return graphDatabaseService.getReferenceNode(); + } + + /** + * Delegates to {@link GraphDatabaseService} + */ + public Iterable getAllNodes() { + return graphDatabaseService.getAllNodes(); + } + + /** + * Delegates to {@link GraphDatabaseService} + */ + public Transaction beginTx() { + return graphDatabaseService.beginTx(); + } + + /** + * Delegates to {@link GraphDatabaseService} + */ + public Relationship getRelationshipById(final long id) { + return graphDatabaseService.getRelationshipById(id); + } + + public GraphDatabaseService getGraphDatabaseService() { return graphDatabaseService; @@ -90,230 +277,6 @@ public class GraphDatabaseContext { this.conversionService = conversionService; } - public Node createNode() { - return graphDatabaseService.createNode(); - } - - /** - * @param relationship to remove from indexes and to delete - */ - private void removeRelationship(Relationship relationship) { - removeFromIndexes(relationship); - relationship.delete(); - } - - /** - * @param relationship to be removed from all indexes, all properties are removed from all indexes - */ - private void removeFromIndexes(Relationship relationship) { - IndexManager indexManager = graphDatabaseService.index(); - for (String indexName : getIndexManager().relationshipIndexNames()) { - indexManager.forRelationships(indexName).remove(relationship); - } - } - - /** - * removes the entity by cleaning the relationships first and then removing the node - * it removes all of them from all indexes in advance - * the entity and relationship are still accessible after removal but before transaction commit - * but all modifications will throw an exception - * @param entity to remove - */ - // TODO: What about connected relationship entities? - public void removeNodeEntity(NodeBacked entity) { - Node node = entity.getPersistentState(); - if (node==null) return; - nodeTypeRepresentationStrategy.preEntityRemoval(entity); - for (Relationship relationship : node.getRelationships()) { - removeRelationship(relationship); - } - removeFromIndexes(node); - node.delete(); - } - - public void removeRelationshipEntity(RelationshipBacked entity) { - Relationship relationship = entity.getPersistentState(); - if (relationship==null) return; - removeRelationship(relationship); - } - - /** - * @param node to be removed from all indexes, all properties of the node are removed from all indexes - */ - private void removeFromIndexes(Node node) { - IndexManager indexManager = graphDatabaseService.index(); - for (String indexName : getIndexManager().nodeIndexNames()) { - indexManager.forNodes(indexName).remove(node); - } - } - - /** - * Creates either a node or relationship entity by delegating the creation to the appropriate @{link EntityInstantiator} - * @param state Node or Relationship - * @param type target entity type - * @return an instance of the entity type - */ - public T createEntityFromState(final S state, final Class type) { - if (state==null) throw new IllegalArgumentException("state has to be either a Node or Relationship, not null"); - if (state instanceof Node && NodeBacked.class.isAssignableFrom(type)) - return (T) nodeTypeRepresentationStrategy.createEntity((Node) state, (Class) type); -// return (T) graphEntityInstantiator.createEntityFromState((Node) state, typeRepresentationStrategy.confirmType((Node)state, (Class)type)); - else - return (T) relationshipTypeRepresentationStrategy.createEntity((Relationship) state, (Class) type); -// return (T) relationshipEntityInstantiator.createEntityFromState((Relationship) state, (Class) type); - } - - private IndexManager getIndexManager() { - return graphDatabaseService.index(); - } - - /** - * @param indexName or null, "node" is assumed if null - * @return node index {@link Index} - */ - public > Index getIndex(Class type, String indexName) { - if (indexName==null) indexName = Indexed.Name.get(type); - if (NodeBacked.class.isAssignableFrom(type)) return (Index) getIndexManager().forNodes(indexName); - if (RelationshipBacked.class.isAssignableFrom(type)) return (Index) getIndexManager().forRelationships(indexName); - throw new IllegalArgumentException("Wrong index type supplied "+type); - } - /** - * @param type type of index requested - either Node.class or Relationship.class - * @param indexName or null, "node" is assumed if null - * @param fullText true if a fulltext queryable index is needed, false for exact match - * @return node index {@link Index} - */ - public > Index getIndex(Class type, String indexName, boolean fullText) { - if (indexName==null) indexName = Indexed.Name.get(type); - Map config = fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : LuceneIndexImplementation.EXACT_CONFIG; - if (NodeBacked.class.isAssignableFrom(type)) return (Index) getIndexManager().forNodes(indexName, config); - if (RelationshipBacked.class.isAssignableFrom(type)) return (Index) getIndexManager().forRelationships(indexName, config); - throw new IllegalArgumentException("Wrong index type supplied "+type); - } - - /** - * @param nodeId - * @return Node - * @throws NotFoundException - */ - public Node getNodeById(final long nodeId) { - return graphDatabaseService.getNodeById(nodeId); - } - - /** - * delegates to the configured @{link TypeRepresentationStrategy} for after entity creation operations - * @param node - * @param entityClass - */ - public void postEntityCreation(Node node, final Class entityClass) { - nodeTypeRepresentationStrategy.postEntityCreation(node, entityClass); - } - /** - * delegates to the configured @{link TypeRepresentationStrategy} for after entity creation operations - * @param relationship - * @param entityClass - */ - public void postEntityCreation(Relationship relationship, final Class entityClass) { - relationshipTypeRepresentationStrategy.postEntityCreation(relationship, entityClass); - } - - /** - * delegates to the configured @{link TypeRepresentationStrategy} to iterate over all instances of this type - * @param clazz type of entity - * @param - * @return - * TODO inheritance handling - */ - public Iterable findAll(final Class clazz) { - if (!checkIsNodeBacked(clazz)) throw new UnsupportedOperationException("No support for relationships"); - return (Iterable) nodeTypeRepresentationStrategy.findAll((Class)clazz); - } - - /** - * class base check for nodebacked subclasses - */ - private boolean checkIsNodeBacked(Class clazz) { - return NodeBacked.class.isAssignableFrom(clazz); - } - - /** - * delegates to the configured @{link TypeRepresentationStrategy} for a count of all instances of this type - * @param entityClass - * @return count of all instances - */ - public long count(final Class entityClass) { - if (!checkIsNodeBacked(entityClass)) throw new UnsupportedOperationException("No support for relationships"); - return nodeTypeRepresentationStrategy.count((Class)entityClass); - } - - /** - * delegates to the configured @{link TypeRepresentationStrategy} to lookup the type information for the given node - * @param node - * @param - * @return entity type of the node - * @throws IllegalStateException for nodes that are not instance backing nodes of a known type - */ - public Class getJavaType(final Node node) { - return nodeTypeRepresentationStrategy.getJavaType(node); - } - - /** - * @return reference node of the graph database - */ - public Node getReferenceNode() { - return graphDatabaseService.getReferenceNode(); - } - - - /** - * @return Neo4j Transaction manager - */ - public TransactionManager getTxManager() { - - return ((AbstractGraphDatabase) graphDatabaseService).getConfig().getTxModule().getTxManager(); - } - - /** - * @return true if a transaction manager is available and a transaction is currently running - */ - public boolean transactionIsRunning() { - try { - return getTxManager().getStatus() != Status.STATUS_NO_TRANSACTION; - } catch (SystemException e) { - log.error("Error accessing TransactionManager", e); - return false; - } - } - - /** - * delegates to @{link GraphDatabaseService} - */ - public Iterable getAllNodes() { - return graphDatabaseService.getAllNodes(); - } - - /** - * delegates to @{link GraphDatabaseService} - */ - public Transaction beginTx() { - return graphDatabaseService.beginTx(); - } - - /** - * delegates to @{link GraphDatabaseService} - */ - public Relationship getRelationshipById(final long id) { - return graphDatabaseService.getRelationshipById(id); - } - - public T projectTo(GraphBacked entity, Class targetType) { - final Object state = entity.getPersistentState(); - if (state instanceof Node) - return (T) nodeTypeRepresentationStrategy.projectEntity((Node) state, (Class) targetType); - else - return (T) relationshipTypeRepresentationStrategy.projectEntity((Relationship) state, (Class) targetType); - } - public Validator getValidator() { return validator; } @@ -322,8 +285,7 @@ public class GraphDatabaseContext { this.validator = validatorFactory; } - public T createEntityFromStoredType(Node node) { - return nodeTypeRepresentationStrategy.createEntity(node); - } + + } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeRepresentationStrategy.java index f1af715f5..6e6bd9fd3 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeRepresentationStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeRepresentationStrategy.java @@ -84,7 +84,6 @@ public class IndexingNodeTypeRepresentationStrategy implements NodeTypeRepresent return count; } - @Override public Class getJavaType(Node node) { if (node == null) throw new IllegalArgumentException("Node is null"); @@ -112,8 +111,8 @@ public class IndexingNodeTypeRepresentationStrategy implements NodeTypeRepresent } @Override - public void preEntityRemoval(NodeBacked entity) { - getNodeTypesIndex().remove(entity.getPersistentState()); + public void preEntityRemoval(Node state) { + getNodeTypesIndex().remove(state); } @Override diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingRelationshipTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingRelationshipTypeRepresentationStrategy.java index 2cd60b633..3134d2216 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingRelationshipTypeRepresentationStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/IndexingRelationshipTypeRepresentationStrategy.java @@ -116,10 +116,11 @@ public class IndexingRelationshipTypeRepresentationStrategy implements Relations } } + @Override - public void preEntityRemoval(RelationshipBacked entity) { - getRelTypesIndex().remove(entity.getPersistentState()); - } + public void preEntityRemoval(Relationship state) { + getRelTypesIndex().remove(state); + } @Override @SuppressWarnings("unchecked") diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeRepresentationStrategy.java new file mode 100644 index 000000000..32fd2fa7a --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeRepresentationStrategy.java @@ -0,0 +1,46 @@ +package org.springframework.data.graph.neo4j.support; + +import org.neo4j.graphdb.Node; +import org.springframework.data.graph.core.NodeBacked; +import org.springframework.data.graph.core.NodeTypeRepresentationStrategy; + +public class NoopNodeTypeRepresentationStrategy implements NodeTypeRepresentationStrategy { + + @Override + public void postEntityCreation(Node state, Class type) { + } + + @Override + public Iterable findAll(Class clazz) { + throw new UnsupportedOperationException("findAll not supported."); + } + + @Override + public long count(Class entityClass) { + throw new UnsupportedOperationException("count not supported."); + } + + @Override + public void preEntityRemoval(Node state) { + } + + @Override + public Class getJavaType(Node state) { + throw new UnsupportedOperationException("getJavaType not supported."); + } + + @Override + public U createEntity(Node state) { + throw new UnsupportedOperationException("Creation with stored type not supported."); + } + + @Override + public U createEntity(Node state, Class type) { + return projectEntity(state, type); + } + + @Override + public U projectEntity(Node state, Class type) { + return null; + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopRelationshipTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopRelationshipTypeRepresentationStrategy.java new file mode 100644 index 000000000..88167297d --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopRelationshipTypeRepresentationStrategy.java @@ -0,0 +1,46 @@ +package org.springframework.data.graph.neo4j.support; + +import org.neo4j.graphdb.Relationship; +import org.springframework.data.graph.core.RelationshipBacked; +import org.springframework.data.graph.core.RelationshipTypeRepresentationStrategy; + +public class NoopRelationshipTypeRepresentationStrategy implements RelationshipTypeRepresentationStrategy { + + @Override + public void postEntityCreation(Relationship state, Class type) { + } + + @Override + public Iterable findAll(Class clazz) { + throw new UnsupportedOperationException("findAll not supported."); + } + + @Override + public long count(Class entityClass) { + throw new UnsupportedOperationException("count not supported."); + } + + @Override + public void preEntityRemoval(Relationship state) { + } + + @Override + public Class getJavaType(Relationship state) { + throw new UnsupportedOperationException("getJavaType not supported."); + } + + @Override + public U createEntity(Relationship state) { + throw new UnsupportedOperationException("Creation with stored type not supported."); + } + + @Override + public U createEntity(Relationship state, Class type) { + return projectEntity(state, type); + } + + @Override + public U projectEntity(Relationship state, Class type) { + return null; + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategy.java deleted file mode 100644 index 55d1025b0..000000000 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategy.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.springframework.data.graph.neo4j.support; - -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.Relationship; -import org.springframework.data.graph.core.NodeBacked; -import org.springframework.data.graph.core.NodeTypeRepresentationStrategy; -import org.springframework.data.graph.core.RelationshipBacked; -import org.springframework.data.graph.core.RelationshipTypeRepresentationStrategy; - -public class NoopTypeRepresentationStrategy { - public static class NoopNodeStrategy implements NodeTypeRepresentationStrategy { - - @Override - public void postEntityCreation(Node state, Class type) { - } - - @Override - public Iterable findAll(Class clazz) { - throw new UnsupportedOperationException("findAll not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public long count(Class entityClass) { - throw new UnsupportedOperationException("count not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public Class getJavaType(Node state) { - throw new UnsupportedOperationException("getJavaType not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public void preEntityRemoval(NodeBacked entity) { - } - - @Override - public U createEntity(Node state) { - throw new UnsupportedOperationException("Creation with stored type not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public U createEntity(Node state, Class type) { - return projectEntity(state, type); - } - - @Override - public U projectEntity(Node state, Class type) { - return null; - } - } - - public static class NoopRelationshipStrategy implements RelationshipTypeRepresentationStrategy { - - @Override - public void postEntityCreation(Relationship state, Class type) { - } - - @Override - public Iterable findAll(Class clazz) { - throw new UnsupportedOperationException("findAll not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public long count(Class entityClass) { - throw new UnsupportedOperationException("count not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public Class getJavaType(Relationship state) { - throw new UnsupportedOperationException("getJavaType not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public void preEntityRemoval(RelationshipBacked entity) { - } - - @Override - public U createEntity(Relationship state) { - throw new UnsupportedOperationException("Creation with stored type not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public U createEntity(Relationship state, Class type) { - return projectEntity(state, type); - } - - @Override - public U projectEntity(Relationship state, Class type) { - return null; - } - } -} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeRepresentationStrategy.java index 1125a4817..edc507edc 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeRepresentationStrategy.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeRepresentationStrategy.java @@ -100,34 +100,6 @@ public class SubReferenceNodeTypeRepresentationStrategy implements NodeTypeRepre updateSuperClassSubrefs(type, subReference); } - /** - * removes instanceof relationship and decrements instance counters for type nodes - * @param entity - */ - @Override - public void preEntityRemoval(NodeBacked entity) { - Class clazz = entity.getClass(); - - final Node subReference = obtainSubreferenceNode(clazz); - Node subRefNode = entity.getPersistentState(); - Relationship instanceOf = subRefNode.getSingleRelationship(INSTANCE_OF_RELATIONSHIP_TYPE, Direction.OUTGOING); - instanceOf.delete(); - if (log.isDebugEnabled()) log.debug("Removed link to subref node: " + subReference + " with type: " + clazz.getName()); - TraversalDescription traversal = Traversal.description().depthFirst().relationships(SUBCLASS_OF_RELATIONSHIP_TYPE, Direction.OUTGOING); - for (Node node : traversal.traverse(subReference).nodes()) { - Integer count = (Integer) node.getProperty(SUBREFERENCE_NODE_COUNTER_KEY); - Integer newCount = decrementAndGetCounter(node, SUBREFERENCE_NODE_COUNTER_KEY, 0); - if (log.isDebugEnabled()) log.debug("count on ref " + node + " was " + count + " new " + newCount); - } - } - -// @Override -// public Class confirmType(Node node, Class type) { -// Class nodeType = this.getJavaType(node); -// if (type.isAssignableFrom(nodeType)) return nodeType; -// throw new IllegalArgumentException(String.format("%s does not correspond to the node type %s of node %s",type,nodeType,node)); -// } - private void updateSuperClassSubrefs(Class clazz, Node subReference) { Class superClass = clazz.getSuperclass(); if (superClass != null) { @@ -165,7 +137,24 @@ public class SubReferenceNodeTypeRepresentationStrategy implements NodeTypeRepre } } - @Override + @Override + public void preEntityRemoval(Node state) { + Class clazz = getJavaType(state); + if (clazz == null) return; + final Node subReference = obtainSubreferenceNode(clazz); + Relationship instanceOf = state.getSingleRelationship(INSTANCE_OF_RELATIONSHIP_TYPE, Direction.OUTGOING); + instanceOf.delete(); + if (log.isDebugEnabled()) + log.debug("Removed link to subref node: " + subReference + " with type: " + clazz.getName()); + TraversalDescription traversal = Traversal.description().depthFirst().relationships(SUBCLASS_OF_RELATIONSHIP_TYPE, Direction.OUTGOING); + for (Node node : traversal.traverse(subReference).nodes()) { + Integer count = (Integer) node.getProperty(SUBREFERENCE_NODE_COUNTER_KEY); + Integer newCount = decrementAndGetCounter(node, SUBREFERENCE_NODE_COUNTER_KEY, 0); + if (log.isDebugEnabled()) log.debug("count on ref " + node + " was " + count + " new " + newCount); + } + } + + @Override public Iterable findAll(final Class clazz) { final Node subrefNode = findSubreferenceNode(clazz); if (log.isDebugEnabled()) log.debug("Subref: " + subrefNode); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/TypeRepresentationStrategyFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/TypeRepresentationStrategyFactory.java index 83e285282..e00c22243 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/TypeRepresentationStrategyFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/TypeRepresentationStrategyFactory.java @@ -57,7 +57,7 @@ public class TypeRepresentationStrategyFactory { @Override public RelationshipTypeRepresentationStrategy getRelationshipTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator relationshipEntityInstantiator) { - return new NoopTypeRepresentationStrategy.NoopRelationshipStrategy(); + return new NoopRelationshipTypeRepresentationStrategy(); } }, Indexed { @@ -74,12 +74,12 @@ public class TypeRepresentationStrategyFactory { Noop { @Override public NodeTypeRepresentationStrategy getNodeTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator graphEntityInstantiator) { - return new NoopTypeRepresentationStrategy.NoopNodeStrategy(); + return new NoopNodeTypeRepresentationStrategy(); } @Override public RelationshipTypeRepresentationStrategy getRelationshipTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator relationshipEntityInstantiator) { - return new NoopTypeRepresentationStrategy.NoopRelationshipStrategy(); + return new NoopRelationshipTypeRepresentationStrategy(); } }; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jOperations.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jOperations.java index 6636c9b7a..38b26ac58 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jOperations.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jOperations.java @@ -2,6 +2,7 @@ package org.springframework.data.graph.neo4j.template; import org.neo4j.graphdb.*; import org.neo4j.graphdb.traversal.TraversalDescription; +import org.springframework.data.graph.core.Property; import java.util.Map; @@ -40,11 +41,12 @@ public interface Neo4jOperations { * Two shortcut means of providing the properties (very short with static imports) * template.createNode(PropertyMap._("name","value")); * template.createNode(PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop"); + * + * * @param props properties to be set at node creation might be null - * @param indexFields fields that are automatically indexed from the given properties for the newly created ndoe * @return the newly created node */ - Node createNode(Map props, String... indexFields); + Node createNode(Property... props); /** * Delegates to the GraphDatabaseService @@ -59,14 +61,15 @@ public interface Neo4jOperations { * Two shortcut means of providing the properties (very short with static imports) * template.createRelationship(from,to,TYPE, PropertyMap._("name","value")); * template.createRelationship(from,to,TYPE, PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop"); + * + * * @param startNode start-node of relationship * @param endNode end-node of relationship * @param type relationship type, might by an enum implementing RelationshipType or a DynamicRelationshipType.withName("name") * @param props optional initial properties - * @param indexFields optional indexed fields * @return the newly created relationship */ - Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props, String... indexFields); + Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Property... props); /** * Queries the supplied index with a lucene query string or query object (if the neo4j-index provider is lucene) @@ -144,14 +147,4 @@ public interface Neo4jOperations { * @return the provided element for convenience */ T index(String indexName, T element, String field, Object value); - /** - * Auto-indexes all indexFields for the given element's properties if they exist - * @param indexName Name of the index, will be checked against existing indexes according to the given element - * assumes a "node" node index or "relationship" relationship index for a null value - * @param element node or relationship to auto-index - * @param indexProperties property names to index - * @param the provided element type - * @return the provided element for convenience - */ - T autoIndex(String indexName, T element, String... indexProperties); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jTemplate.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jTemplate.java index f6e90caa7..0281d5e98 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jTemplate.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/template/Neo4jTemplate.java @@ -25,8 +25,7 @@ import org.neo4j.helpers.collection.IterableWrapper; import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.graph.UncategorizedGraphStoreException; - -import java.util.Map; +import org.springframework.data.graph.core.Property; public class Neo4jTemplate implements Neo4jOperations { @@ -117,13 +116,13 @@ public class Neo4jTemplate implements Neo4jOperations { } @Override - public Node createNode(final Map properties, final String... indexFields) { + public Node createNode(final Property... properties) { return exec(new GraphCallback() { @Override public Node doWithGraph(GraphDatabaseService graph) throws Exception { Node node = graphDatabaseService.createNode(); if (properties == null) return node; - return autoIndex(null, setProperties(node, properties), indexFields); + return setProperties(node, properties); } }); } @@ -148,15 +147,6 @@ public class Neo4jTemplate implements Neo4jOperations { } } - @Override - public T autoIndex(String indexName, T element, String... indexFields) { - for (String indexField : indexFields) { - if (!element.hasProperty(indexField)) continue; - index(indexName,element, indexField,element.getProperty(indexField)); - } - return element; - } - @Override public T index(final String indexName, final T element, final String field, final Object value) { notNull(element, "element", field, "field", value, "value"); @@ -290,26 +280,26 @@ public class Neo4jTemplate implements Neo4jOperations { } @Override - public Relationship createRelationship(final Node startNode, final Node endNode, final RelationshipType relationshipType, final Map properties, final String... indexFields) { + public Relationship createRelationship(final Node startNode, final Node endNode, final RelationshipType relationshipType, final Property... properties) { notNull(startNode, "startNode", endNode, "endNode", relationshipType, "relationshipType", properties, "properties"); return exec(new GraphCallback() { @Override public Relationship doWithGraph(GraphDatabaseService graph) throws Exception { Relationship relationship = startNode.createRelationshipTo(endNode, relationshipType); if (properties == null) return relationship; - return autoIndex("relationship", setProperties(relationship, properties), indexFields); + return setProperties(relationship, properties); } }); } - private T setProperties(T primitive, Map properties) { + private T setProperties(T primitive, Property... properties) { assert primitive != null; if (properties==null) return primitive; - for (Map.Entry prop : properties.entrySet()) { - if (prop.getValue()==null) { - primitive.removeProperty(prop.getKey()); + for (Property prop : properties) { + if (prop.value==null) { + primitive.removeProperty(prop.name); } else { - primitive.setProperty(prop.getKey(), prop.getValue()); + primitive.setProperty(prop.name, prop.value); } } return primitive; diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/core/GraphDatabaseFactoryTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/core/GraphDatabaseFactoryTest.java new file mode 100644 index 000000000..7c7a4065b --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/core/GraphDatabaseFactoryTest.java @@ -0,0 +1,43 @@ +package org.springframework.data.graph.core; + +import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.data.graph.neo4j.support.DelegatingGraphDatabase; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.core.IsNull.nullValue; +import static org.junit.Assert.assertThat; + +/** + * @author mh + * @since 29.03.11 + */ +public class GraphDatabaseFactoryTest { + + @Test + public void shouldCreateLocalDatabaseFromContext() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("GraphDatabaseFactory-context.xml"); + try { + GraphDatabase graphDatabase = ctx.getBean("graphDatabase", GraphDatabase.class); + assertThat(graphDatabase, is(not(nullValue()))); + assertThat(graphDatabase, is(instanceOf(DelegatingGraphDatabase.class))); + } finally { + ctx.close(); + } + + } + @Test + public void shouldCreateLocalDatabase() throws Exception { + GraphDatabaseFactory factory = new GraphDatabaseFactory(); + try { + factory.setStoreLocation("target/test-db"); + GraphDatabase graphDatabase = factory.getObject(); + assertThat(graphDatabase, is(not(nullValue()))); + assertThat(graphDatabase,is(instanceOf(DelegatingGraphDatabase.class))); + } finally { + factory.shutdown(); + } + } +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/FriendshipRepository.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/FriendshipRepository.java new file mode 100644 index 000000000..fa9e64a7d --- /dev/null +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/FriendshipRepository.java @@ -0,0 +1,6 @@ +package org.springframework.data.graph.neo4j; + +import org.springframework.data.graph.neo4j.repository.RelationshipGraphRepository; + +public interface FriendshipRepository extends RelationshipGraphRepository { +} diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/FinderTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/GraphRepositoryTest.java similarity index 83% rename from spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/FinderTest.java rename to spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/GraphRepositoryTest.java index bb4c48fe2..52acea8c8 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/FinderTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/GraphRepositoryTest.java @@ -2,26 +2,20 @@ package org.springframework.data.graph.neo4j.support; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.hamcrest.Matcher; import org.junit.Assert; import org.junit.Test; -import org.junit.internal.matchers.IsCollectionContaining; import org.junit.runner.RunWith; import org.neo4j.helpers.collection.IteratorUtil; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; -import org.springframework.data.graph.neo4j.Group; -import org.springframework.data.graph.neo4j.GroupRepository; -import org.springframework.data.graph.neo4j.Person; -import org.springframework.data.graph.neo4j.PersonRepository; +import org.springframework.data.graph.neo4j.*; import org.springframework.data.graph.neo4j.support.node.Neo4jHelper; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.transaction.BeforeTransaction; import org.springframework.transaction.annotation.Transactional; -import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import static java.util.Arrays.asList; @@ -34,8 +28,7 @@ import static org.springframework.data.graph.neo4j.Person.persistedPerson; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml"}) - -public class FinderTest { +public class GraphRepositoryTest { protected final Log log = LogFactory.getLog(getClass()); @@ -46,6 +39,8 @@ public class FinderTest { private PersonRepository personRepository; @Autowired private GroupRepository groupRepository; + @Autowired + private FriendshipRepository friendshipRepository; @BeforeTransaction public void cleanDb() { @@ -78,7 +73,7 @@ public class FinderTest { Person p1 = new Person("Michael", 35); personRepository.save(p1); assertEquals("persisted person",true,p1.hasPersistentState()); - assertThat(personRepository.findOne(p1.getId()),is(p1)); + assertThat(personRepository.findOne(p1.getId()), is(p1)); } @Test public void testDeletePerson() { @@ -94,6 +89,17 @@ public class FinderTest { assertEquals("people deleted", false, personRepository.findAll().iterator().hasNext()); } + @Test + @Transactional + public void testFindRelationshipEntity() { + Person p1 = persistedPerson("Michael", 35); + Person p2 = persistedPerson("David", 27); + Friendship friendship = p1.knows(p2); + assertEquals("Wrong friendship count.", 1L, (long) friendshipRepository.count()); + assertEquals("Did not find friendship.", Collections.singleton(friendship), new HashSet(IteratorUtil.asCollection(friendshipRepository.findAll()))); + assertEquals(friendship, friendshipRepository.findOne(friendship.getRelationshipId())); + } + @Test @Transactional public void testFinderFindById() { diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeRepresentationStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeRepresentationStrategyTest.java index 0ab684bda..17e9fcc29 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeRepresentationStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingNodeTypeRepresentationStrategyTest.java @@ -78,7 +78,7 @@ public class IndexingNodeTypeRepresentationStrategyTest { Transaction tx = graphDatabaseService.beginTx(); try { - nodeTypeRepresentationStrategy.preEntityRemoval(thing); + nodeTypeRepresentationStrategy.preEntityRemoval(node(thing)); tx.success(); } finally @@ -92,9 +92,8 @@ public class IndexingNodeTypeRepresentationStrategyTest { assertEquals(node(subThing), subThingHits.getSingle()); tx = graphDatabaseService.beginTx(); - try - { - nodeTypeRepresentationStrategy.preEntityRemoval(subThing); + try { + nodeTypeRepresentationStrategy.preEntityRemoval(node(subThing)); tx.success(); } finally diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingRelationshipTypeRepresentationStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingRelationshipTypeRepresentationStrategyTest.java index aab76f805..4f2cef42f 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingRelationshipTypeRepresentationStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/IndexingRelationshipTypeRepresentationStrategyTest.java @@ -74,7 +74,7 @@ public class IndexingRelationshipTypeRepresentationStrategyTest { Transaction tx = graphDatabaseService.beginTx(); try { - relationshipTypeRepresentationStrategy.preEntityRemoval(link); + relationshipTypeRepresentationStrategy.preEntityRemoval(rel(link)); tx.success(); } finally diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyTest.java index 3d5a55848..fae7f2125 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyTest.java @@ -1,7 +1,15 @@ package org.springframework.data.graph.neo4j.support; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.neo4j.graphdb.DynamicRelationshipType; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.Transaction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.graph.annotation.NodeEntity; +import org.springframework.data.graph.annotation.RelationshipEntity; import org.springframework.test.context.CleanContextCacheTestExecutionListener; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; @@ -11,77 +19,109 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml", - "classpath:org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml"}) + "classpath:org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyOverride-context.xml"}) @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) public class NoopTypeRepresentationStrategyTest { -// -// @Autowired -// private GraphDatabaseContext graphDatabaseContext; -// @Autowired -// private NoopTypeRepresentationStrategy nodeTypeStrategy; -// -// private Thing thing; -// -// @Before -// public void setUp() throws Exception { -// thing = createThing(); -// } + + @Autowired + private GraphDatabaseContext graphDatabaseContext; + @Autowired + private NoopNodeTypeRepresentationStrategy noopNodeStrategy; + @Autowired + private NoopRelationshipTypeRepresentationStrategy noopRelationshipStrategy; + + private Thing thing; + private Link link; + + @Before + public void setUp() throws Exception { + createThing(); + } @Test public void testPostEntityCreation() throws Exception { } -// -// @Test(expected = UnsupportedOperationException.class) -// public void testFindAll() throws Exception { -// nodeTypeStrategy.findAll(Thing.class); -// } -// -// @Test(expected = UnsupportedOperationException.class) -// public void testCount() throws Exception { -// nodeTypeStrategy.count(Thing.class); -// } -// -// @Test(expected = UnsupportedOperationException.class) -// public void testGetJavaType() throws Exception { -// nodeTypeStrategy.getJavaType(node(thing)); -// } -// -// @Test -// public void testPreEntityRemoval() throws Exception { -// nodeTypeStrategy.preEntityRemoval(thing); -// } -// -// @Test -// public void testConfirmType() throws Exception { -// assertEquals(Thing.class, nodeTypeStrategy.confirmType(node(thing), Thing.class)); -// } -// -// private static Node node(Thing thing) { -// return thing.getPersistentState(); -// } -// -// private Thing createThing() { -// Transaction tx = graphDatabaseContext.beginTx(); -// try { -// Node node = graphDatabaseContext.createNode(); -// Thing thing = new Thing(node); -// nodeTypeStrategy.postEntityCreation(thing); -// tx.success(); -// return thing; -// } finally { -// tx.finish(); -// } -// } -// -// @NodeEntity -// public static class Thing { -// String name; -// -// public Thing() { -// } -// -// public Thing(Node n) { -// setPersistentState(n); -// } -// } + + @Test(expected = UnsupportedOperationException.class) + public void testFindAllForNodeStrategy() throws Exception { + noopNodeStrategy.findAll(Thing.class); + } + + @Test(expected = UnsupportedOperationException.class) + public void testFindAllForRelationshipStrategy() throws Exception { + noopRelationshipStrategy.findAll(Link.class); + } + + @Test(expected = UnsupportedOperationException.class) + public void testCountForNodeStrategy() throws Exception { + noopNodeStrategy.count(Thing.class); + } + + @Test(expected = UnsupportedOperationException.class) + public void testCountForRelationshipStrategy() throws Exception { + noopRelationshipStrategy.count(Link.class); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetJavaTypeOnNodeStrategy() throws Exception { + noopNodeStrategy.getJavaType(null); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetJavaTypeOnRelationshipStrategy() throws Exception { + noopRelationshipStrategy.getJavaType(null); + } + + @Test + public void testPreEntityRemoval() throws Exception { + noopNodeStrategy.preEntityRemoval(node(thing)); + noopRelationshipStrategy.preEntityRemoval(rel(link)); + } + + private static Node node(Thing thing) { + return thing.getPersistentState(); + } + + private static Relationship rel(Link link) { + return link.getPersistentState(); + } + + private Thing createThing() { + Transaction tx = graphDatabaseContext.beginTx(); + try { + Node node = graphDatabaseContext.createNode(); + thing = new Thing(node); + noopNodeStrategy.postEntityCreation(node, Thing.class); + Relationship rel = node.createRelationshipTo(graphDatabaseContext.createNode(), DynamicRelationshipType.withName("link")); + link = new Link(rel); + noopRelationshipStrategy.postEntityCreation(rel, Link.class); + tx.success(); + return thing; + } finally { + tx.finish(); + } + } + + @NodeEntity + public static class Thing { + String name; + + public Thing() { + } + + public Thing(Node n) { + setPersistentState(n); + } + } + + @RelationshipEntity + public static class Link { + + public Link() { + } + + public Link(Relationship rel) { + setPersistentState(rel); + } + } } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/RelationshipEntityTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/RelationshipEntityTest.java index 3f6f537d4..ab712c1f6 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/RelationshipEntityTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/RelationshipEntityTest.java @@ -8,7 +8,10 @@ import org.neo4j.graphdb.*; import org.neo4j.helpers.collection.IteratorUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.graph.neo4j.Friendship; +import org.springframework.data.graph.neo4j.FriendshipRepository; import org.springframework.data.graph.neo4j.Person; + +import static org.junit.Assert.assertFalse; import static org.springframework.data.graph.neo4j.Person.persistedPerson; import org.springframework.data.graph.neo4j.repository.DirectGraphRepositoryFactory; @@ -30,6 +33,10 @@ public class RelationshipEntityTest { @Autowired private GraphDatabaseContext graphDatabaseContext; + @Autowired + private GraphDatabaseService graphDatabaseService; + @Autowired + private FriendshipRepository friendshipRepository; @Autowired private DirectGraphRepositoryFactory graphRepositoryFactory; @@ -97,6 +104,64 @@ public class RelationshipEntityTest { Person p = persistedPerson("Michael", 35); Person p2 = persistedPerson("David", 25); Friendship f = p.knows(p2); - assertEquals(f,p.getRelationshipTo(p2,Friendship.class, "knows")); + assertEquals(f,p.getRelationshipTo(p2, Friendship.class, "knows")); + } + + @Test + public void testRemoveRelationshipEntity() { + cleanDb(); + Friendship f; + Transaction tx = graphDatabaseService.beginTx(); + try + { + Person p = persistedPerson("Michael", 35); + Person p2 = persistedPerson("David", 25); + f = p.knows(p2); + tx.success(); + } + finally + { + tx.finish(); + } + Transaction tx2 = graphDatabaseService.beginTx(); + try + { + f.remove(); + tx2.success(); + } + finally + { + tx2.finish(); + } + assertFalse("Unexpected relationship entity found.", friendshipRepository.findAll().iterator().hasNext()); + } + + @Test + public void testRemoveRelationshipEntityIfNodeEntityIsRemoved() { + cleanDb(); + Person p; + Transaction tx = graphDatabaseService.beginTx(); + try + { + p = persistedPerson("Michael", 35); + Person p2 = persistedPerson("David", 25); + p.knows(p2); + tx.success(); + } + finally + { + tx.finish(); + } + Transaction tx2 = graphDatabaseService.beginTx(); + try + { + p.remove(); + tx2.success(); + } + finally + { + tx2.finish(); + } + assertFalse("Unexpected relationship entity found.", friendshipRepository.findAll().iterator().hasNext()); } } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeRepresentationStrategyTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeRepresentationStrategyTest.java index 99bfaafbc..ead00fcf2 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeRepresentationStrategyTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/SubReferenceNodeTypeRepresentationStrategyTest.java @@ -113,11 +113,11 @@ public class SubReferenceNodeTypeRepresentationStrategyTest { @Transactional public void testPreEntityRemoval() throws Exception { Node typeNode = getInstanceofRelationship(thingNode).getOtherNode(thingNode); - nodeTypeRepresentationStrategy.preEntityRemoval(thing); + nodeTypeRepresentationStrategy.preEntityRemoval(node(thing)); assertNull("instanceof relationship was removed", getInstanceofRelationship(thingNode)); assertNotNull("instanceof relationship was removed", getInstanceofRelationship(subThingNode)); assertEquals("no things left after removal", 1, typeNode.getProperty(SubReferenceNodeTypeRepresentationStrategy.SUBREFERENCE_NODE_COUNTER_KEY)); - nodeTypeRepresentationStrategy.preEntityRemoval(subThing); + nodeTypeRepresentationStrategy.preEntityRemoval(node(subThing)); assertNull("instanceof relationship was removed", getInstanceofRelationship(subThingNode)); assertEquals("no things left after removal", 0, typeNode.getProperty(SubReferenceNodeTypeRepresentationStrategy.SUBREFERENCE_NODE_COUNTER_KEY)); diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/Neo4jTemplateApiTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/Neo4jTemplateApiTest.java index 0374db728..de6c7f1b0 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/Neo4jTemplateApiTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/Neo4jTemplateApiTest.java @@ -19,8 +19,7 @@ import java.util.Iterator; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.*; -import static org.springframework.data.graph.neo4j.template.PropertyMap._; -import static org.springframework.data.graph.neo4j.template.PropertyMap.props; +import static org.springframework.data.graph.core.Property._; /** * @author mh @@ -189,7 +188,7 @@ public class Neo4jTemplateApiTest { @Test public void testCreateNodeWithProperties() throws Exception { - Node node=template.createNode(props().set("test", "testCreateNodeWithProperties").toMap()); + Node node=template.createNode(_("test", "testCreateNodeWithProperties")); assertTestPropertySet(node, "testCreateNodeWithProperties"); } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/NeoTraversalTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/NeoTraversalTest.java index 80d4cfb9a..3fc670fb4 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/NeoTraversalTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/template/NeoTraversalTest.java @@ -13,8 +13,8 @@ import java.util.Set; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.neo4j.kernel.Traversal.returnAllButStartNode; +import static org.springframework.data.graph.core.Property._; import static org.springframework.data.graph.neo4j.template.NeoTraversalTest.Type.HAS; -import static org.springframework.data.graph.neo4j.template.PropertyMap._; public class NeoTraversalTest extends NeoApiTest { diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml b/spring-data-neo4j/src/test/resources/GraphDatabaseFactory-context.xml similarity index 84% rename from spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml rename to spring-data-neo4j/src/test/resources/GraphDatabaseFactory-context.xml index 5a7624d3c..e1863ed64 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml +++ b/spring-data-neo4j/src/test/resources/GraphDatabaseFactory-context.xml @@ -14,5 +14,11 @@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - + + + + + + + \ No newline at end of file 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 6224d3c77..465079929 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 @@ -152,6 +152,10 @@ + + + + diff --git a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyOverride-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyOverride-context.xml new file mode 100644 index 000000000..17e8c9de6 --- /dev/null +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyOverride-context.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/src/docbkx/reference/cross-store.xml b/src/docbkx/reference/cross-store.xml index 3ab1aaa8b..b346de1cc 100644 --- a/src/docbkx/reference/cross-store.xml +++ b/src/docbkx/reference/cross-store.xml @@ -23,10 +23,11 @@ backing graph store afterwards. - The connection between the two entities is kept via a FOREIGN_ID field in the node that contains the JPA id (currently only single - value ids are supported). The entity class can be resolved via the NodeTypeStrategy that preserves the Java type hierarchy within the graph. - With the id and class, you can then retrieve the appropriate JPA entity for a given node. - + The connection between the two entities is kept via a FOREIGN_ID field in the node that contains the JPA id + (currently only single value ids are supported). The entity class can be resolved via the + TypeRepresentationStrategy that manages the Java type hierarchy within the graph. With the id and class, + you can then retrieve the appropriate JPA entity for a given node. + The other direction is handled by indexing the Node with the FOREIGN_ID index which contains a concatenation of the fully qualified class name of the JPA entity and the id. So it is possible on instantiation of a JPA id via the entity manager (or some other means like creating diff --git a/src/docbkx/reference/programming-model/finders.xml b/src/docbkx/reference/programming-model/finders.xml index 4502c538a..a3035ba98 100644 --- a/src/docbkx/reference/programming-model/finders.xml +++ b/src/docbkx/reference/programming-model/finders.xml @@ -2,6 +2,7 @@
Finding nodes with finders + TODO: rewrite to repositories Spring Data Graph also comes with a typed, repository-like Finder implementation that provides methods for locating nodes and relationships. Those methods return instances of the node and relationship entities, not the graph primitives from Neo4j. Finders delegate to the configured NodeTypeStrategy for type @@ -68,15 +69,8 @@ Iterable davesFriends = graphRepository.findAllByTraversal(dave, Internally the mapping from java types to the graph is handled by a NodeTypeStrategy instance that is configured with the GraphDatabaseContext. The strategy is called on entity creation and removal and provides methods for retrieving entities based on type. It also comes with methods confirming or - retrieving java types from the actual graph node. (see also ) - - - The default strategy (IndexingNodeTypeStrategy) - uses indexing (index "__types__") and node properties ("__type__") to store the type information in the graph. - - The second strategy uses an in graph structure to represent the inheritance hierarchy links the actual node - entity nodes to their concrete class nodes. Instance counts are updated on each of the class nodes in the hierarchy. - The last provided strategy is a No-Op strategy that doesn't care about type information. + retrieving java types from the actual graph node. (see also + )
\ No newline at end of file diff --git a/src/docbkx/reference/programming-model/nodetypestrategy.xml b/src/docbkx/reference/programming-model/nodetypestrategy.xml deleted file mode 100644 index ba50c7db6..000000000 --- a/src/docbkx/reference/programming-model/nodetypestrategy.xml +++ /dev/null @@ -1,48 +0,0 @@ - - -
- Storing Type Information in the Graph - - 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. 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. - - - There are three available implementations to choose from. - - - 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. - - - - 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 - - Does not store any type information, and does hence not support finding by type, counting by type, - or retrieving the type of any entity. - - - - - - 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 diff --git a/src/docbkx/reference/programming-model/programming-model.xml b/src/docbkx/reference/programming-model/programming-model.xml index a0c764e90..85af23b1a 100644 --- a/src/docbkx/reference/programming-model/programming-model.xml +++ b/src/docbkx/reference/programming-model/programming-model.xml @@ -14,7 +14,7 @@ - + diff --git a/src/docbkx/reference/programming-model/typerepresentationstrategy.xml b/src/docbkx/reference/programming-model/typerepresentationstrategy.xml new file mode 100644 index 000000000..3fed0354a --- /dev/null +++ b/src/docbkx/reference/programming-model/typerepresentationstrategy.xml @@ -0,0 +1,78 @@ + + +
+ Storing type information in the graph + + 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. Some of + this type information is saved in the graph database. + + + Implementations of + TypeRepresentationStrategy + 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 and count. + + + There are three available implementations for node entities to choose from. + + + + IndexingNodeTypeRepresentationStrategy + + + 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. + + + + + SubReferenceNodeTypeRepresentationStrategy + + + 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. + + + + + NoopNodeTypeRepresentationStrategy + + + Does not store any type information, and does hence not support finding by type, counting by type, + or retrieving the type of any entity. + + + + + + There are two implementations for relationship entities available, same behavior as the corresponding ones + above: + + + + IndexingRelationshipTypeRepresentationStrategy + + + + + NoopRelationshipTypeRepresentationStrategy + + + + + + Spring Data Graph will by default autodetect which are the most suitable strategies for node and relationship + entities. For new data stores, it will always opt for the indexing strategies. If a data store was created + with the olderSubReferenceNodeTypeRepresentationStrategy, then it will continue to use that + strategy for node entities. It will however in that case use the no-op strategy for relationship entities, + which means that the old data stores have no support for searching for relationship entities. The indexing + strategies are recommended for all new users. + +
diff --git a/src/docbkx/reference/setup.xml b/src/docbkx/reference/setup.xml index 73706ef56..51ad95a8c 100644 --- a/src/docbkx/reference/setup.xml +++ b/src/docbkx/reference/setup.xml @@ -98,6 +98,7 @@
Setting Up Spring Data Graph - Spring Configuration + Out of date - should we even have this section? The concrete configuration for Spring Data Graph is quite verbose as there is no autowiring involved. It sets up the following parts. @@ -120,7 +121,7 @@ Finder factory - an appropriate NodeTypeStrategy + TypeRepresentationStrategies