GraphDatabase for RestGraphDatabase

This commit is contained in:
Michael Hunger
2011-03-31 14:08:48 +02:00
parent d606d319fa
commit 2f37ea79f2
11 changed files with 151 additions and 78 deletions

View File

@@ -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<String, Object> 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<String, Object> 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<Node> getAllNodes() {
throw new UnsupportedOperationException();
}
@Override
public Iterable<RelationshipType> getRelationshipTypes() {
throw new UnsupportedOperationException();
}
@Override
public void shutdown() {
}
@Override
public boolean enableRemoteShell() {
return false;
}
@Override
public boolean enableRemoteShell(Map<String, Serializable> initialProperties) {
return false;
}
@Override
public Transaction beginTx() {
return new Transaction() {
@Override
public void failure() {
}
@Override
public void success() {
}
@Override
public void finish() {
}
};
}
@Override
public <T> TransactionEventHandler<T> registerTransactionEventHandler(TransactionEventHandler<T> handler) {
return handler;
}
@Override
public <T> TransactionEventHandler<T> unregisterTransactionEventHandler(TransactionEventHandler<T> 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> T getManagementBean(Class<T> type) {
return null;
}
@Override
public boolean isReadOnly() {
return false;
}
}

View File

@@ -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()

View File

@@ -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;

View File

@@ -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)
* <code>graphDatabase.createNode(PropertyMap._("name","value"));</code>
* <code>graphDatabase.createNode(PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop");</code>
*
* @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<String, Object> 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)
* <code>graphDatabase.createRelationship(from,to,TYPE, PropertyMap._("name","value"));</code>
* <code>graphDatabase.createRelationship(from,to,TYPE, PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop");</code>
*
*
* @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<String, Object> 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();
}

View File

@@ -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<GraphDatabase> {
}
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<GraphDatabase> {
@PreDestroy
public void shutdown() {
if (graphDatabase instanceof LocalGraphDatabase) {
((LocalGraphDatabase)graphDatabase).shutdown();
if (graphDatabase instanceof DelegatingGraphDatabase) {
((DelegatingGraphDatabase)graphDatabase).shutdown();
}
}

View File

@@ -41,12 +41,17 @@ public class DelegatingGraphDatabase implements GraphDatabase {
return setProperties(delegate.createNode(), props);
}
private <T extends PropertyContainer> 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 extends PropertyContainer> 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

View File

@@ -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)
* <code>template.createNode(PropertyMap._("name","value"));</code>
* <code>template.createNode(PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop");</code>
*
*
* @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<String, Object> 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)
* <code>template.createRelationship(from,to,TYPE, PropertyMap._("name","value"));</code>
* <code>template.createRelationship(from,to,TYPE, PropertyMap.props().set("name","value").set("prop","anotherValue").toMap(), "name", "prop");</code>
*
*
* @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<String, Object> 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 extends PropertyContainer> 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 <T> the provided element type
* @return the provided element for convenience
*/
<T extends PropertyContainer> T autoIndex(String indexName, T element, String... indexProperties);
}

View File

@@ -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<String, Object> properties, final String... indexFields) {
public Node createNode(final Property... properties) {
return exec(new GraphCallback<Node>() {
@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 extends PropertyContainer> 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 extends PropertyContainer> 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<String, Object> 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<Relationship>() {
@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 extends PropertyContainer> T setProperties(T primitive, Map<String, Object> properties) {
private <T extends PropertyContainer> T setProperties(T primitive, Property... properties) {
assert primitive != null;
if (properties==null) return primitive;
for (Map.Entry<String, Object> 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;

View File

@@ -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();
}

View File

@@ -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");
}

View File

@@ -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 {