From 291f68dc362bf075ffd4f3469d90c8a11a22627c Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Tue, 29 Mar 2011 14:22:37 +0200 Subject: [PATCH 01/14] GraphDatabase interface --- .../data/graph/core/GraphDatabase.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabase.java 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..96f8abe23 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabase.java @@ -0,0 +1,59 @@ +package org.springframework.data.graph.core; + +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.RelationshipType; + +import java.util.Map; + +/** + * @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 getNode(long id); + + /** + * Transactionally creates the node, sets the properties (if any) and indexes the given fields (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 + * @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); + + /** + * Delegates to the GraphDatabaseService + * @param id relationship id + * @return the requested relationship of the underlying graph database + * @throws org.neo4j.graphdb.NotFoundException + */ + Relationship getRelationship(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 + * @param indexFields optional indexed fields + * @return the newly created relationship + */ + Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props, String... indexFields); + +} From ec035d5ccea3a700abbab9940b71698ec1ab9923 Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Tue, 29 Mar 2011 14:41:59 +0200 Subject: [PATCH 02/14] all necessary methods for GraphDatabase --- .../data/graph/core/GraphDatabase.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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 index 96f8abe23..be4d85185 100644 --- 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 @@ -1,8 +1,10 @@ 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 java.util.Map; @@ -35,7 +37,6 @@ public interface GraphDatabase { Node createNode(Map props, String... indexFields); /** - * Delegates to the GraphDatabaseService * @param id relationship id * @return the requested relationship of the underlying graph database * @throws org.neo4j.graphdb.NotFoundException @@ -56,4 +57,19 @@ public interface GraphDatabase { */ Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props, String... indexFields); + /** + * @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); } From 704163eeaf28b449e662fca65777054a259e1af3 Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Tue, 29 Mar 2011 15:39:21 +0200 Subject: [PATCH 03/14] all necessary methods for GraphDatabase GraphDatabaseFactory and tests for that changed RestGraphDatabase to implement GraphDatabase --- spring-data-neo4j-rest/pom.xml | 1 - .../java/org/neo4j/kernel/RestConfig.java | 133 ------------------ .../rest/graphdb/GraphDatabaseFactory.java | 39 ----- .../neo4j/rest/graphdb/RestGraphDatabase.java | 126 ++++++----------- .../data/graph/core/GraphDatabase.java | 7 + .../data/graph/core/GraphDatabaseFactory.java | 88 ++++++++++++ 6 files changed, 138 insertions(+), 256 deletions(-) delete mode 100644 spring-data-neo4j-rest/src/main/java/org/neo4j/kernel/RestConfig.java delete mode 100644 spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/GraphDatabaseFactory.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabaseFactory.java 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 deleted file mode 100644 index 87a15ac0b..000000000 --- a/spring-data-neo4j-rest/src/main/java/org/neo4j/kernel/RestConfig.java +++ /dev/null @@ -1,133 +0,0 @@ -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; -import org.neo4j.kernel.impl.transaction.LockManager; -import org.neo4j.kernel.impl.transaction.TxModule; -import org.neo4j.kernel.impl.transaction.xaframework.LogBufferFactory; -import org.neo4j.kernel.impl.transaction.xaframework.TxIdGenerator; -import org.neo4j.rest.graphdb.RestGraphDatabase; - -import javax.transaction.*; -import javax.transaction.xa.XAResource; -import java.util.Collections; -import java.util.Map; - -/** -* @author mh -* @since 23.02.11 -*/ -public class RestConfig extends Config { - public RestConfig(GraphDatabaseService graphDb, String storeDir, StoreId storeId, - Map inputParams, KernelPanicEventGenerator kpe, - TxModule txModule, LockManager lockManager, LockReleaser lockReleaser, - IdGeneratorFactory idGeneratorFactory, - TxEventSyncHookFactory txSyncHookFactory, RelationshipTypeCreator relTypeCreator, - TxIdGenerator txIdGenerator, LastCommittedTxIdSetter lastCommittedTxIdSetter, - FileSystemAbstraction fileSystem, LogBufferFactory logBufferFactory) { - super(graphDb, storeDir, storeId, - inputParams, kpe, txModule, lockManager, lockReleaser, idGeneratorFactory, txSyncHookFactory, relTypeCreator, txIdGenerator, lastCommittedTxIdSetter, fileSystem, logBufferFactory); - } - - public RestConfig(RestGraphDatabase restGraphDatabase) { - super(restGraphDatabase, restGraphDatabase.getStoreDir(), null, - Collections.emptyMap(),null, - new TxModule(true,null){ - @Override - public TransactionManager getTxManager() { - return new NullTransactionManager(); - } - }, - null,null, - null,null,null,null,null, - null,null); - } - - private static class NullTransactionManager implements TransactionManager { - private static final Transaction TRANSACTION = new Transaction() { - @Override - public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException, SystemException { - - } - - @Override - public boolean delistResource(XAResource xaResource, int i) throws IllegalStateException, SystemException { - return false; - } - - @Override - public boolean enlistResource(XAResource xaResource) throws IllegalStateException, RollbackException, SystemException { - return false; - } - - @Override - public int getStatus() throws SystemException { - return Status.STATUS_NO_TRANSACTION; - } - - @Override - public void registerSynchronization(Synchronization synchronization) throws IllegalStateException, RollbackException, SystemException { - - } - - @Override - public void rollback() throws IllegalStateException, SystemException { - - } - - @Override - public void setRollbackOnly() throws IllegalStateException, SystemException { - - } - }; - - @Override - public void begin() throws NotSupportedException, SystemException { - - } - - @Override - public void commit() throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException, RollbackException, SecurityException, SystemException { - - } - - @Override - public int getStatus() throws SystemException { - return 0; - } - - @Override - public Transaction getTransaction() throws SystemException { - return TRANSACTION; - } - - @Override - public void resume(Transaction transaction) throws IllegalStateException, InvalidTransactionException, SystemException { - - } - - @Override - public void rollback() throws IllegalStateException, SecurityException, SystemException { - - } - - @Override - public void setRollbackOnly() throws IllegalStateException, SystemException { - - } - - @Override - public void setTransactionTimeout(int i) throws SystemException { - - } - - @Override - public Transaction suspend() throws SystemException { - return TRANSACTION; - } - } -} 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/RestGraphDatabase.java b/spring-data-neo4j-rest/src/main/java/org/neo4j/rest/graphdb/RestGraphDatabase.java index dc11bcbfa..ac96d8a63 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,21 @@ 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.Index; import org.neo4j.graphdb.index.IndexManager; +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 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 implements GraphDatabase { private RestRequest restRequest; private long propertyRefetchTimeInMillis = 1000; @@ -28,74 +31,26 @@ 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 getNode(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 ); + @Override + public Node createNode(Map props, String... indexFields) { + 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 ) { + @Override + public Relationship getRelationship(long id) { ClientResponse response = restRequest.get( "relationship/" + id ); if ( restRequest.statusIs( response, Status.NOT_FOUND ) ) { throw new NotFoundException( "" + id ); @@ -103,11 +58,35 @@ public class RestGraphDatabase extends AbstractGraphDatabase { return new RestRelationship( restRequest.toMap( response ), this ); } - public Iterable getRelationshipTypes() { - throw new UnsupportedOperationException(); + @Override + public Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props, String... indexFields) { + 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(); + } + + private 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,23 +96,4 @@ public class RestGraphDatabase extends AbstractGraphDatabase { public long getPropertyRefetchTimeInMillis() { return propertyRefetchTimeInMillis; } - @Override - public String getStoreDir() { - return restRequest.getUri().toString(); - } - - @Override - public Config getConfig() { - return new RestConfig(this); - } - - @Override - public T getManagementBean(Class type) { - return null; - } - - @Override - public boolean isReadOnly() { - return false; - } } 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 index be4d85185..81e71a67e 100644 --- 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 @@ -5,6 +5,7 @@ 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; import java.util.Map; @@ -72,4 +73,10 @@ public interface GraphDatabase { * @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..166656aee --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/core/GraphDatabaseFactory.java @@ -0,0 +1,88 @@ +package org.springframework.data.graph.core; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.data.graph.neo4j.support.LocalGraphDatabase; + +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 LocalGraphDatabase(file); + } + + 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 LocalGraphDatabase) { + ((LocalGraphDatabase)graphDatabase).shutdown(); + } + } + + @Override + public Class getObjectType() { + return GraphDatabaseService.class; + } + + @Override + public boolean isSingleton() { + return true; + } +} From ef2cdb6c71a320f35fede782af2aba96fb4fb253 Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Tue, 29 Mar 2011 15:47:42 +0200 Subject: [PATCH 04/14] PropertyContainer returns GraphDatabaseService which is bad as it breaks the assumption let it throw UnsupportedOperationException() there is a second getRestGraphDatabase() method for returning the actual RestGraphDatabase --- .../src/main/java/org/neo4j/rest/graphdb/RestEntity.java | 7 ++++++- .../java/org/neo4j/rest/graphdb/RestGraphDatabase.java | 7 ------- .../src/main/java/org/neo4j/rest/graphdb/RestNode.java | 4 ++-- .../java/org/neo4j/rest/graphdb/RestRelationship.java | 2 +- .../test/java/org/neo4j/rest/graphdb/RestTestBase.java | 9 ++------- 5 files changed, 11 insertions(+), 18 deletions(-) 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 ac96d8a63..69345e013 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 @@ -2,19 +2,12 @@ package org.neo4j.rest.graphdb; 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.Index; -import org.neo4j.graphdb.index.IndexManager; 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 javax.ws.rs.core.Response.Status; -import java.io.Serializable; import java.net.URI; import java.util.Map; 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/test/java/org/neo4j/rest/graphdb/RestTestBase.java b/spring-data-neo4j-rest/src/test/java/org/neo4j/rest/graphdb/RestTestBase.java index 03851bc5f..b1e04a5bc 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 @@ -25,7 +25,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 +47,6 @@ public class RestTestBase { neoServer.cleanDb(); } - @After - public void tearDown() throws Exception { - graphDb.shutdown(); - } - @AfterClass public static void shutdownDb() { neoServer.stop(); @@ -61,7 +56,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() { From 3348eec4e6ef1c633446d38985863c61af240cad Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Tue, 29 Mar 2011 22:04:32 +0200 Subject: [PATCH 05/14] Test for GraphDatabaseFactory --- .../graph/core/GraphDatabaseFactoryTest.java | 43 +++++++++++++++++++ .../GraphDatabaseFactory-context.xml | 24 +++++++++++ 2 files changed, 67 insertions(+) create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/graph/core/GraphDatabaseFactoryTest.java create mode 100644 spring-data-neo4j/src/test/resources/GraphDatabaseFactory-context.xml 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..98278f4a8 --- /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.LocalGraphDatabase; + +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(LocalGraphDatabase.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(LocalGraphDatabase.class))); + } finally { + factory.shutdown(); + } + } +} diff --git a/spring-data-neo4j/src/test/resources/GraphDatabaseFactory-context.xml b/spring-data-neo4j/src/test/resources/GraphDatabaseFactory-context.xml new file mode 100644 index 000000000..e1863ed64 --- /dev/null +++ b/spring-data-neo4j/src/test/resources/GraphDatabaseFactory-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + \ No newline at end of file From eaa5b4a672653706d376e7a323e597b20b32cda2 Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Tue, 29 Mar 2011 22:05:14 +0200 Subject: [PATCH 06/14] Implementation of GraphDatabase for EmbeddedGD --- .../neo4j/support/LocalGraphDatabase.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/LocalGraphDatabase.java diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/LocalGraphDatabase.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/LocalGraphDatabase.java new file mode 100644 index 000000000..c61af0fa1 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/LocalGraphDatabase.java @@ -0,0 +1,83 @@ +package org.springframework.data.graph.neo4j.support; + +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.index.IndexManager; +import org.neo4j.graphdb.traversal.TraversalDescription; +import org.neo4j.index.impl.lucene.LuceneIndexImplementation; +import org.neo4j.kernel.EmbeddedGraphDatabase; +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.RelationshipBacked; + +import java.io.File; +import java.util.Map; + +/** + * @author mh + * @since 29.03.11 + */ +public class LocalGraphDatabase implements GraphDatabase { + + protected EmbeddedGraphDatabase delegate; + + public LocalGraphDatabase(File file) { + delegate = new EmbeddedGraphDatabase(file.getAbsolutePath()); + } + + @Override + public Node getReferenceNode() { + return delegate.getReferenceNode(); + } + + @Override + public Node getNode(long id) { + return delegate.getNodeById(id); + } + + @Override + public Node createNode(Map props, String... indexFields) { + return null; + } + + @Override + public Relationship getRelationship(long id) { + return delegate.getRelationshipById(id); + } + + @Override + public Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props, String... indexFields) { + return null; + } + + @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(); + Map config = fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : LuceneIndexImplementation.EXACT_CONFIG; + if (NodeBacked.class.isAssignableFrom(type)) return (Index) indexManager.forNodes(indexName, config); + if (RelationshipBacked.class.isAssignableFrom(type)) return (Index) indexManager.forRelationships(indexName, config); + throw new IllegalArgumentException("Wrong index type supplied "+type); + } + + @Override + public TraversalDescription createTraversalDescription() { + return Traversal.description(); + } + + public void shutdown() { + delegate.shutdown(); + } +} From 561926b4b4561a5c6458b6916663be9edc2188e4 Mon Sep 17 00:00:00 2001 From: David Montag Date: Wed, 30 Mar 2011 11:30:21 -0700 Subject: [PATCH 07/14] Added some finder support for relationship entities. --- .../data/graph/neo4j/rest/RestFinderTest.java | 5 ++-- .../neo4j/support/GraphDatabaseContext.java | 12 +++++--- .../graph/neo4j/FriendshipRepository.java | 6 ++++ ...nderTest.java => GraphRepositoryTest.java} | 28 +++++++++++-------- .../Neo4jGraphPersistenceTest-context.xml | 4 +++ 5 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/FriendshipRepository.java rename spring-data-neo4j/src/test/java/org/springframework/data/graph/neo4j/support/{FinderTest.java => GraphRepositoryTest.java} (83%) 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..93de0d159 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,7 +21,7 @@ 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 { 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..10d0dd2b4 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 @@ -225,8 +225,10 @@ public class GraphDatabaseContext { * 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); + if (checkIsNodeBacked(clazz)) { + return (Iterable) nodeTypeRepresentationStrategy.findAll((Class) clazz); + } + return (Iterable) relationshipTypeRepresentationStrategy.findAll((Class) clazz); } /** @@ -242,8 +244,10 @@ public class GraphDatabaseContext { * @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); + if (checkIsNodeBacked(entityClass)) { + return nodeTypeRepresentationStrategy.count((Class)entityClass); + } + return relationshipTypeRepresentationStrategy.count((Class) entityClass); } /** 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/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 @@ + + + + From 17ea86b5fd3ce0907e99e7a11c6af605a0c697da Mon Sep 17 00:00:00 2001 From: David Montag Date: Wed, 30 Mar 2011 12:11:43 -0700 Subject: [PATCH 08/14] Refactored GraphDatabaseContext a bit. --- ...AbstractNodeRelationshipFieldAccessor.java | 7 +- .../neo4j/support/GraphDatabaseContext.java | 270 +++++++++--------- 2 files changed, 132 insertions(+), 145 deletions(-) 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/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java index 10d0dd2b4..4c54f8555 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,55 +44,17 @@ 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 NodeTypeRepresentationStrategy nodeTypeRepresentationStrategy; - private RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy; - private Validator validator; + private NodeTypeRepresentationStrategy nodeTypeRepresentationStrategy; - private final static Log log = LogFactory.getLog(GraphDatabaseContext.class); - - public GraphDatabaseService getGraphDatabaseService() { - return graphDatabaseService; - } - - public void setGraphDatabaseService(GraphDatabaseService graphDatabaseService) { - this.graphDatabaseService = graphDatabaseService; - } - - public NodeTypeRepresentationStrategy getNodeTypeRepresentationStrategy() { - return nodeTypeRepresentationStrategy; - } - - public void setNodeTypeRepresentationStrategy(NodeTypeRepresentationStrategy nodeTypeRepresentationStrategy) { - this.nodeTypeRepresentationStrategy = nodeTypeRepresentationStrategy; - } - - public RelationshipTypeRepresentationStrategy getRelationshipTypeRepresentationStrategy() { - return relationshipTypeRepresentationStrategy; - } - - public void setRelationshipTypeRepresentationStrategy(RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy) { - this.relationshipTypeRepresentationStrategy = relationshipTypeRepresentationStrategy; - } - - public ConversionService getConversionService() { - return conversionService; - } - - public void setConversionService(ConversionService conversionService) { - this.conversionService = conversionService; - } - - public Node createNode() { - return graphDatabaseService.createNode(); - } + private RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy; /** * @param relationship to remove from indexes and to delete @@ -147,22 +109,6 @@ public class GraphDatabaseContext { } } - /** - * 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(); } @@ -191,51 +137,15 @@ public class GraphDatabaseContext { 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 entityClass type of entity * @param * @return * TODO inheritance handling */ - public Iterable findAll(final Class clazz) { - if (checkIsNodeBacked(clazz)) { - return (Iterable) nodeTypeRepresentationStrategy.findAll((Class) clazz); - } - return (Iterable) relationshipTypeRepresentationStrategy.findAll((Class) clazz); - } - - /** - * class base check for nodebacked subclasses - */ - private boolean checkIsNodeBacked(Class clazz) { - return NodeBacked.class.isAssignableFrom(clazz); + public Iterable findAll(final Class entityClass) { + return getTypeRepresentationStrategy(entityClass).findAll(entityClass); } /** @@ -243,38 +153,8 @@ public class GraphDatabaseContext { * @param entityClass * @return count of all instances */ - public long count(final Class entityClass) { - if (checkIsNodeBacked(entityClass)) { - return nodeTypeRepresentationStrategy.count((Class)entityClass); - } - return relationshipTypeRepresentationStrategy.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(); + public long count(final Class entityClass) { + return getTypeRepresentationStrategy(entityClass).count(entityClass); } /** @@ -289,35 +169,146 @@ public class GraphDatabaseContext { } } + + + 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 T createEntityFromStoredType(Node node) { + return nodeTypeRepresentationStrategy.createEntity(node); + } + + public > void postEntityCreation(S node, Class entityClass) { + getTypeRepresentationStrategy(node, entityClass).postEntityCreation(node, entityClass); + } + + + + @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."); + } + + + /** - * delegates to @{link GraphDatabaseService} + * @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} + * Delegates to {@link GraphDatabaseService} */ public Transaction beginTx() { return graphDatabaseService.beginTx(); } /** - * delegates to @{link GraphDatabaseService} + * 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 GraphDatabaseService getGraphDatabaseService() { + return graphDatabaseService; + } + + public void setGraphDatabaseService(GraphDatabaseService graphDatabaseService) { + this.graphDatabaseService = graphDatabaseService; + } + + public NodeTypeRepresentationStrategy getNodeTypeRepresentationStrategy() { + return nodeTypeRepresentationStrategy; } + public void setNodeTypeRepresentationStrategy(NodeTypeRepresentationStrategy nodeTypeRepresentationStrategy) { + this.nodeTypeRepresentationStrategy = nodeTypeRepresentationStrategy; + } + + public RelationshipTypeRepresentationStrategy getRelationshipTypeRepresentationStrategy() { + return relationshipTypeRepresentationStrategy; + } + + public void setRelationshipTypeRepresentationStrategy(RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy) { + this.relationshipTypeRepresentationStrategy = relationshipTypeRepresentationStrategy; + } + + public ConversionService getConversionService() { + return conversionService; + } + + public void setConversionService(ConversionService conversionService) { + this.conversionService = conversionService; + } + public Validator getValidator() { return validator; } @@ -326,8 +317,7 @@ public class GraphDatabaseContext { this.validator = validatorFactory; } - public T createEntityFromStoredType(Node node) { - return nodeTypeRepresentationStrategy.createEntity(node); - } + + } From b8707d02c31e8422fb58eebb22d5af170d76d6f4 Mon Sep 17 00:00:00 2001 From: David Montag Date: Wed, 30 Mar 2011 14:15:37 -0700 Subject: [PATCH 09/14] Reshuffled GraphDatabaseContext stuff a bit more. --- .../neo4j/support/GraphDatabaseContext.java | 164 ++++++++---------- 1 file changed, 70 insertions(+), 94 deletions(-) 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 4c54f8555..e59256a93 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 @@ -56,24 +56,66 @@ public class GraphDatabaseContext { private RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy; - /** - * @param relationship to remove from indexes and to delete - */ - private void removeRelationship(Relationship relationship) { - removeFromIndexes(relationship); - relationship.delete(); + + + 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); } /** - * @param relationship to be removed from all indexes, all properties are removed from all indexes + * @return true if a transaction manager is available and a transaction is currently running */ - private void removeFromIndexes(Relationship relationship) { - IndexManager indexManager = graphDatabaseService.index(); - for (String indexName : getIndexManager().relationshipIndexNames()) { - indexManager.forRelationships(indexName).remove(relationship); + 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); + } + + /** * removes the entity by cleaning the relationships first and then removing the node * it removes all of them from all indexes in advance @@ -93,19 +135,29 @@ public class GraphDatabaseContext { node.delete(); } + private void removeFromIndexes(Node node) { + IndexManager indexManager = getIndexManager(); + for (String indexName : indexManager.nodeIndexNames()) { + indexManager.forNodes(indexName).remove(node); + } + } + + // 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); + private void removeRelationship(Relationship relationship) { + removeFromIndexes(relationship); + relationship.delete(); + } + + private void removeFromIndexes(Relationship relationship) { + IndexManager indexManager = getIndexManager(); + for (String indexName : indexManager.relationshipIndexNames()) { + indexManager.forRelationships(indexName).remove(relationship); } } @@ -113,82 +165,6 @@ public class GraphDatabaseContext { 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); - } - - /** - * delegates to the configured @{link TypeRepresentationStrategy} to iterate over all instances of this type - * @param entityClass type of entity - * @param - * @return - * TODO inheritance handling - */ - public Iterable findAll(final Class entityClass) { - return getTypeRepresentationStrategy(entityClass).findAll(entityClass); - } - - /** - * 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) { - return getTypeRepresentationStrategy(entityClass).count(entityClass); - } - - /** - * @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 > 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 T createEntityFromStoredType(Node node) { - return nodeTypeRepresentationStrategy.createEntity(node); - } - - public > void postEntityCreation(S node, Class entityClass) { - getTypeRepresentationStrategy(node, entityClass).postEntityCreation(node, entityClass); - } - @SuppressWarnings("unchecked") From 632afae487220460b7e4109d97b14fd030f2f8af Mon Sep 17 00:00:00 2001 From: David Montag Date: Wed, 30 Mar 2011 15:56:28 -0700 Subject: [PATCH 10/14] Added proper removal of relationship entities. --- .../graphdb/index/RestRelationshipIndex.java | 14 ++-- .../RestEntityPropertyValidationTest.java | 26 +++---- .../data/graph/neo4j/rest/RestFinderTest.java | 26 +++---- .../rest/RestNodeEntityRelationshipTest.java | 26 +++---- .../graph/neo4j/rest/RestProjectionTest.java | 27 ++++---- .../graph/neo4j/rest/RestPropertyTest.java | 26 +++---- .../rest/RestRelationshipEntityTest.java | 26 +++---- .../core/TypeRepresentationStrategy.java | 15 +++-- .../neo4j/support/GraphDatabaseContext.java | 36 ++++------ ...ndexingNodeTypeRepresentationStrategy.java | 5 +- ...elationshipTypeRepresentationStrategy.java | 7 +- .../NoopTypeRepresentationStrategy.java | 32 ++++----- ...ferenceNodeTypeRepresentationStrategy.java | 47 +++++-------- ...ingNodeTypeRepresentationStrategyTest.java | 7 +- ...ionshipTypeRepresentationStrategyTest.java | 2 +- .../neo4j/support/RelationshipEntityTest.java | 67 ++++++++++++++++++- ...nceNodeTypeRepresentationStrategyTest.java | 4 +- 17 files changed, 220 insertions(+), 173 deletions(-) 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/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 93de0d159..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 @@ -23,20 +23,20 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi @TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) 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/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/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/GraphDatabaseContext.java index e59256a93..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 @@ -116,18 +116,10 @@ public class GraphDatabaseContext { } - /** - * 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); + if (node == null) return; + nodeTypeRepresentationStrategy.preEntityRemoval(node); for (Relationship relationship : node.getRelationships()) { removeRelationship(relationship); } @@ -135,6 +127,18 @@ public class GraphDatabaseContext { 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()) { @@ -142,18 +146,6 @@ public class GraphDatabaseContext { } } - // - public void removeRelationshipEntity(RelationshipBacked entity) { - Relationship relationship = entity.getPersistentState(); - if (relationship==null) return; - removeRelationship(relationship); - } - - private void removeRelationship(Relationship relationship) { - removeFromIndexes(relationship); - relationship.delete(); - } - private void removeFromIndexes(Relationship relationship) { IndexManager indexManager = getIndexManager(); for (String indexName : indexManager.relationshipIndexNames()) { 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/NoopTypeRepresentationStrategy.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategy.java index 55d1025b0..e37f28af9 100644 --- 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 @@ -16,26 +16,26 @@ public class NoopTypeRepresentationStrategy { @Override public Iterable findAll(Class clazz) { - throw new UnsupportedOperationException("findAll not supported by NoopTypeRepresentationStrategy."); + throw new UnsupportedOperationException("findAll not supported."); } @Override public long count(Class entityClass) { - throw new UnsupportedOperationException("count not supported by NoopTypeRepresentationStrategy."); + throw new UnsupportedOperationException("count not supported."); + } + + @Override + public void preEntityRemoval(Node state) { } @Override public Class getJavaType(Node state) { - throw new UnsupportedOperationException("getJavaType not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public void preEntityRemoval(NodeBacked entity) { + throw new UnsupportedOperationException("getJavaType not supported."); } @Override public U createEntity(Node state) { - throw new UnsupportedOperationException("Creation with stored type not supported by NoopTypeRepresentationStrategy."); + throw new UnsupportedOperationException("Creation with stored type not supported."); } @Override @@ -57,26 +57,26 @@ public class NoopTypeRepresentationStrategy { @Override public Iterable findAll(Class clazz) { - throw new UnsupportedOperationException("findAll not supported by NoopTypeRepresentationStrategy."); + throw new UnsupportedOperationException("findAll not supported."); } @Override public long count(Class entityClass) { - throw new UnsupportedOperationException("count not supported by NoopTypeRepresentationStrategy."); + throw new UnsupportedOperationException("count not supported."); + } + + @Override + public void preEntityRemoval(Relationship state) { } @Override public Class getJavaType(Relationship state) { - throw new UnsupportedOperationException("getJavaType not supported by NoopTypeRepresentationStrategy."); - } - - @Override - public void preEntityRemoval(RelationshipBacked entity) { + throw new UnsupportedOperationException("getJavaType not supported."); } @Override public U createEntity(Relationship state) { - throw new UnsupportedOperationException("Creation with stored type not supported by NoopTypeRepresentationStrategy."); + throw new UnsupportedOperationException("Creation with stored type not supported."); } @Override 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/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/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)); From 098a61646e1e1c942eb21be5144a36efd79b9c41 Mon Sep 17 00:00:00 2001 From: David Montag Date: Wed, 30 Mar 2011 22:51:09 -0700 Subject: [PATCH 11/14] Added docs for typerepresentationstrategies. Added tests for noop strategies. --- .../NoopNodeTypeRepresentationStrategy.java | 46 +++++ ...elationshipTypeRepresentationStrategy.java | 46 +++++ .../NoopTypeRepresentationStrategy.java | 92 --------- .../TypeRepresentationStrategyFactory.java | 6 +- .../NoopTypeRepresentationStrategyTest.java | 174 +++++++++++------- ...epresentationStrategyOverride-context.xml} | 3 +- src/docbkx/reference/cross-store.xml | 9 +- .../reference/programming-model/finders.xml | 12 +- .../programming-model/nodetypestrategy.xml | 48 ----- .../programming-model/programming-model.xml | 2 +- .../typerepresentationstrategy.xml | 78 ++++++++ src/docbkx/reference/setup.xml | 3 +- 12 files changed, 293 insertions(+), 226 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopNodeTypeRepresentationStrategy.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopRelationshipTypeRepresentationStrategy.java delete mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategy.java rename spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/{NoopNodeTypeStrategyOverride-context.xml => NoopTypeRepresentationStrategyOverride-context.xml} (81%) delete mode 100644 src/docbkx/reference/programming-model/nodetypestrategy.xml create mode 100644 src/docbkx/reference/programming-model/typerepresentationstrategy.xml 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 e37f28af9..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."); - } - - @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; - } - } - - 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."); - } - - @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/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/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/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyOverride-context.xml similarity index 81% 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/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyOverride-context.xml index 5a7624d3c..17e8c9de6 100644 --- a/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml +++ b/spring-data-neo4j/src/test/resources/org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyOverride-context.xml @@ -14,5 +14,6 @@ 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/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 From d606d319fa24d5035c90e86469ea5466533a119a Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Thu, 31 Mar 2011 14:08:26 +0200 Subject: [PATCH 12/14] GraphDatabase for RestGraphDatabase --- .../java/org/neo4j/kernel/RestConfig.java | 131 ++++++++++++++++++ .../data/graph/core/Property.java | 48 +++++++ .../support/DelegatingGraphDatabase.java | 110 +++++++++++++++ .../neo4j/support/LocalGraphDatabase.java | 83 ----------- 4 files changed, 289 insertions(+), 83 deletions(-) create mode 100644 spring-data-neo4j-rest/src/main/java/org/neo4j/kernel/RestConfig.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/core/Property.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/DelegatingGraphDatabase.java delete mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/LocalGraphDatabase.java 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 new file mode 100644 index 000000000..e8008799a --- /dev/null +++ b/spring-data-neo4j-rest/src/main/java/org/neo4j/kernel/RestConfig.java @@ -0,0 +1,131 @@ +package org.neo4j.kernel; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.kernel.impl.core.*; +import org.neo4j.kernel.impl.nioneo.store.FileSystemAbstraction; +import org.neo4j.kernel.impl.nioneo.store.StoreId; +import org.neo4j.kernel.impl.transaction.LockManager; +import org.neo4j.kernel.impl.transaction.TxModule; +import org.neo4j.kernel.impl.transaction.xaframework.LogBufferFactory; +import org.neo4j.kernel.impl.transaction.xaframework.TxIdGenerator; +import org.neo4j.rest.graphdb.RestGraphDatabase; + +import javax.transaction.*; +import javax.transaction.xa.XAResource; +import java.util.Collections; +import java.util.Map; + +/** +* @author mh +* @since 23.02.11 +*/ +public class RestConfig extends Config { + public RestConfig(GraphDatabaseService graphDb, String storeDir, StoreId storeId, + Map inputParams, KernelPanicEventGenerator kpe, + TxModule txModule, LockManager lockManager, LockReleaser lockReleaser, + IdGeneratorFactory idGeneratorFactory, + TxEventSyncHookFactory txSyncHookFactory, RelationshipTypeCreator relTypeCreator, + TxIdGenerator txIdGenerator, LastCommittedTxIdSetter lastCommittedTxIdSetter, + FileSystemAbstraction fileSystem, LogBufferFactory logBufferFactory) { + super(graphDb, storeDir, storeId, + inputParams, kpe, txModule, lockManager, lockReleaser, idGeneratorFactory, txSyncHookFactory, relTypeCreator, txIdGenerator, lastCommittedTxIdSetter, fileSystem, logBufferFactory); + } + + public RestConfig(RestGraphDatabase restGraphDatabase) { + super(restGraphDatabase, restGraphDatabase.getStoreDir(), null, + Collections.emptyMap(),null, + new TxModule(true,null){ + @Override + public TransactionManager getTxManager() { + return new NullTransactionManager(); + } + }, + null,null, + null,null,null,null,null, + null,null); + } + + private static class NullTransactionManager implements TransactionManager { + private static final Transaction NULL_JAVA_TRANSACTION = new Transaction() { + @Override + public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException, SystemException { + + } + + @Override + public boolean delistResource(XAResource xaResource, int i) throws IllegalStateException, SystemException { + return false; + } + + @Override + public boolean enlistResource(XAResource xaResource) throws IllegalStateException, RollbackException, SystemException { + return false; + } + + @Override + public int getStatus() throws SystemException { + return Status.STATUS_NO_TRANSACTION; + } + + @Override + public void registerSynchronization(Synchronization synchronization) throws IllegalStateException, RollbackException, SystemException { + + } + + @Override + public void rollback() throws IllegalStateException, SystemException { + + } + + @Override + public void setRollbackOnly() throws IllegalStateException, SystemException { + + } + }; + + @Override + public void begin() throws NotSupportedException, SystemException { + + } + + @Override + public void commit() throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException, RollbackException, SecurityException, SystemException { + + } + + @Override + public int getStatus() throws SystemException { + return 0; + } + + @Override + public Transaction getTransaction() throws SystemException { + return NULL_JAVA_TRANSACTION; + } + + @Override + public void resume(Transaction transaction) throws IllegalStateException, InvalidTransactionException, SystemException { + + } + + @Override + public void rollback() throws IllegalStateException, SecurityException, SystemException { + + } + + @Override + public void setRollbackOnly() throws IllegalStateException, SystemException { + + } + + @Override + public void setTransactionTimeout(int i) throws SystemException { + + } + + @Override + public Transaction suspend() throws SystemException { + return NULL_JAVA_TRANSACTION; + } + } +} \ No newline at end of file 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/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..e2d9a4e4d --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/DelegatingGraphDatabase.java @@ -0,0 +1,110 @@ +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 element, Property[] props) { + if (props==null || props.length==0) return element; + for (Property prop : props) { + element.setProperty(prop.name, prop.value); + } + return element; + } + + @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/LocalGraphDatabase.java b/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/LocalGraphDatabase.java deleted file mode 100644 index c61af0fa1..000000000 --- a/spring-data-neo4j/src/main/java/org/springframework/data/graph/neo4j/support/LocalGraphDatabase.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.springframework.data.graph.neo4j.support; - -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.index.IndexManager; -import org.neo4j.graphdb.traversal.TraversalDescription; -import org.neo4j.index.impl.lucene.LuceneIndexImplementation; -import org.neo4j.kernel.EmbeddedGraphDatabase; -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.RelationshipBacked; - -import java.io.File; -import java.util.Map; - -/** - * @author mh - * @since 29.03.11 - */ -public class LocalGraphDatabase implements GraphDatabase { - - protected EmbeddedGraphDatabase delegate; - - public LocalGraphDatabase(File file) { - delegate = new EmbeddedGraphDatabase(file.getAbsolutePath()); - } - - @Override - public Node getReferenceNode() { - return delegate.getReferenceNode(); - } - - @Override - public Node getNode(long id) { - return delegate.getNodeById(id); - } - - @Override - public Node createNode(Map props, String... indexFields) { - return null; - } - - @Override - public Relationship getRelationship(long id) { - return delegate.getRelationshipById(id); - } - - @Override - public Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props, String... indexFields) { - return null; - } - - @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(); - Map config = fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : LuceneIndexImplementation.EXACT_CONFIG; - if (NodeBacked.class.isAssignableFrom(type)) return (Index) indexManager.forNodes(indexName, config); - if (RelationshipBacked.class.isAssignableFrom(type)) return (Index) indexManager.forRelationships(indexName, config); - throw new IllegalArgumentException("Wrong index type supplied "+type); - } - - @Override - public TraversalDescription createTraversalDescription() { - return Traversal.description(); - } - - public void shutdown() { - delegate.shutdown(); - } -} From 2f37ea79f2c5f839fa612b37ab30e2156531dc12 Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Thu, 31 Mar 2011 14:08:48 +0200 Subject: [PATCH 13/14] GraphDatabase for RestGraphDatabase --- .../neo4j/rest/graphdb/RestGraphDatabase.java | 111 ++++++++++++++++-- .../org/neo4j/rest/graphdb/RestTraversal.java | 2 +- .../org/neo4j/rest/graphdb/RestTestBase.java | 10 -- .../data/graph/core/GraphDatabase.java | 18 +-- .../data/graph/core/GraphDatabaseFactory.java | 9 +- .../support/DelegatingGraphDatabase.java | 15 ++- .../graph/neo4j/template/Neo4jOperations.java | 21 ++-- .../graph/neo4j/template/Neo4jTemplate.java | 30 ++--- .../graph/core/GraphDatabaseFactoryTest.java | 6 +- .../neo4j/template/Neo4jTemplateApiTest.java | 5 +- .../neo4j/template/NeoTraversalTest.java | 2 +- 11 files changed, 151 insertions(+), 78 deletions(-) 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 69345e013..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 @@ -2,16 +2,24 @@ package org.neo4j.rest.graphdb; 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.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 implements GraphDatabase { +public class RestGraphDatabase extends AbstractGraphDatabase implements GraphDatabase { + private RestRequest restRequest; private long propertyRefetchTimeInMillis = 1000; @@ -25,7 +33,7 @@ public class RestGraphDatabase implements GraphDatabase { } @Override - public Node getNode(long id) { + public Node getNodeById(long id) { ClientResponse response = restRequest.get("node/" + id); if ( restRequest.statusIs(response, Status.NOT_FOUND) ) { throw new NotFoundException( "" + id ); @@ -34,17 +42,17 @@ public class RestGraphDatabase implements GraphDatabase { } @Override - public Node createNode(Map props, String... indexFields) { + public Node createNode(Property... props) { ClientResponse response = restRequest.post("node", null); - if ( restRequest.statusOtherThan( response, Status.CREATED ) ) { + if ( restRequest.statusOtherThan(response, Status.CREATED) ) { throw new RuntimeException( "" + response.getStatus() ); } return new RestNode( response.getLocation(), this ); } @Override - public Relationship getRelationship(long id) { - ClientResponse response = restRequest.get( "relationship/" + id ); + public Relationship getRelationshipById(long id) { + ClientResponse response = restRequest.get("relationship/" + id); if ( restRequest.statusIs( response, Status.NOT_FOUND ) ) { throw new NotFoundException( "" + id ); } @@ -52,7 +60,7 @@ public class RestGraphDatabase implements GraphDatabase { } @Override - public Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props, String... indexFields) { + public Relationship createRelationship(Node startNode, Node endNode, RelationshipType type, Property... props) { Relationship relationship = startNode.createRelationshipTo(endNode, type); return relationship; } @@ -72,7 +80,7 @@ public class RestGraphDatabase implements GraphDatabase { return new RestTraversal(); } - private RestIndexManager index() { + public RestIndexManager index() { return new RestIndexManager( restRequest, this ); } @@ -89,4 +97,91 @@ public class RestGraphDatabase implements GraphDatabase { 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 getRestRequest().getUri().toString(); + } + + @Override + public Config getConfig() { + return new RestConfig(this); + } + + @Override + public T getManagementBean(Class type) { + return null; + } + + @Override + public boolean isReadOnly() { + return false; + } } 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/test/java/org/neo4j/rest/graphdb/RestTestBase.java b/spring-data-neo4j-rest/src/test/java/org/neo4j/rest/graphdb/RestTestBase.java index b1e04a5bc..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; 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 index 81e71a67e..d73b2ec94 100644 --- 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 @@ -7,8 +7,6 @@ import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.index.Index; import org.neo4j.graphdb.traversal.TraversalDescription; -import java.util.Map; - /** * @author mh * @since 29.03.11 @@ -24,39 +22,40 @@ public interface GraphDatabase { * @return the requested node of the underlying graph database * @throws org.neo4j.graphdb.NotFoundException */ - Node getNode(long id); + Node getNodeById(long id); /** - * Transactionally creates the node, sets the properties (if any) and indexes the given fields (if any). + * 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 - * @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); /** * @param id relationship id * @return the requested relationship of the underlying graph database * @throws org.neo4j.graphdb.NotFoundException */ - Relationship getRelationship(long id); + 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 - * @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); /** * @param indexName existing index name, not null @@ -79,4 +78,5 @@ public interface GraphDatabase { * @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 index 166656aee..f2d3a6740 100644 --- 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 @@ -1,8 +1,9 @@ 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.LocalGraphDatabase; +import org.springframework.data.graph.neo4j.support.DelegatingGraphDatabase; import javax.annotation.PreDestroy; import java.io.File; @@ -54,7 +55,7 @@ public class GraphDatabaseFactory implements FactoryBean { } File file = new File( path ); // if (!file.isDirectory()) file=file.getParentFile(); - return new LocalGraphDatabase(file); + return new DelegatingGraphDatabase(new EmbeddedGraphDatabase(file.getAbsolutePath())); } private GraphDatabase createRestGraphDatabase(String url, String username, String password) throws Exception { @@ -71,8 +72,8 @@ public class GraphDatabaseFactory implements FactoryBean { @PreDestroy public void shutdown() { - if (graphDatabase instanceof LocalGraphDatabase) { - ((LocalGraphDatabase)graphDatabase).shutdown(); + if (graphDatabase instanceof DelegatingGraphDatabase) { + ((DelegatingGraphDatabase)graphDatabase).shutdown(); } } 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 index e2d9a4e4d..9ac73e436 100644 --- 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 @@ -41,12 +41,17 @@ public class DelegatingGraphDatabase implements GraphDatabase { return setProperties(delegate.createNode(), props); } - private T setProperties(T element, Property[] props) { - if (props==null || props.length==0) return element; - for (Property prop : props) { - element.setProperty(prop.name, prop.value); + 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 element; + return primitive; } @Override 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 index 98278f4a8..7c7a4065b 100644 --- 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 @@ -2,7 +2,7 @@ package org.springframework.data.graph.core; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.data.graph.neo4j.support.LocalGraphDatabase; +import org.springframework.data.graph.neo4j.support.DelegatingGraphDatabase; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsInstanceOf.instanceOf; @@ -22,7 +22,7 @@ public class GraphDatabaseFactoryTest { try { GraphDatabase graphDatabase = ctx.getBean("graphDatabase", GraphDatabase.class); assertThat(graphDatabase, is(not(nullValue()))); - assertThat(graphDatabase, is(instanceOf(LocalGraphDatabase.class))); + assertThat(graphDatabase, is(instanceOf(DelegatingGraphDatabase.class))); } finally { ctx.close(); } @@ -35,7 +35,7 @@ public class GraphDatabaseFactoryTest { factory.setStoreLocation("target/test-db"); GraphDatabase graphDatabase = factory.getObject(); assertThat(graphDatabase, is(not(nullValue()))); - assertThat(graphDatabase,is(instanceOf(LocalGraphDatabase.class))); + assertThat(graphDatabase,is(instanceOf(DelegatingGraphDatabase.class))); } finally { factory.shutdown(); } 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 { From 29a9d64834a4945789ecfd04b42bc8a8d134fb0f Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Thu, 31 Mar 2011 14:29:02 +0200 Subject: [PATCH 14/14] caching field-reflection in PropertyFieldAccessors --- ...rtingNodePropertyFieldAccessorFactory.java | 8 ++--- .../PropertyFieldAccessorFactory.java | 33 ++++++++++--------- 2 files changed, 21 insertions(+), 20 deletions(-) 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) {