added rest-wrapper

This commit is contained in:
Michael Hunger
2011-03-28 12:11:09 +02:00
parent 0decb9e371
commit e79071b37c
33 changed files with 2521 additions and 0 deletions

View File

@@ -12,6 +12,7 @@
<module>spring-data-graph-core</module>
<module>spring-data-neo4j</module>
<module>spring-data-neo4j-roo</module>
<module>spring-data-neo4j-rest</module>
</modules>
<developers>

View File

@@ -0,0 +1,133 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-graph-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<relativePath>../spring-data-graph-parent/pom.xml</relativePath>
</parent>
<groupId>org.neo4j</groupId>
<artifactId>spring-data-neo4j-rest</artifactId>
<packaging>jar</packaging>
<version>1.0.0.BUILD-SNAPSHOT</version>
<name>Spring Data Graph REST Wrapper</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.slf4j.version>1.5.10</org.slf4j.version>
<jersey.version>1.4</jersey.version>
<neo4j.version>1.3.M05</neo4j.version>
</properties>
<repositories>
<repository>
<id>neo4j</id>
<url>http://m2.neo4j.org</url>
</repository>
<repository>
<id>Sun</id>
<url>http://download.java.net/maven/2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>${neo4j.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.tinkerpop</groupId>
<artifactId>gremlin</artifactId>
</exclusion>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</exclusion>
<exclusion>
<groupId>de.huxhorn.lilith</groupId>
<artifactId>de.huxhorn.lilith.3rdparty.rrd4j</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.main</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.fileinstall</artifactId>
</exclusion>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-shell</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.25</version>
<scope>test</scope>
</dependency>
<!-- Server example dependencies -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,133 @@
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<String, String> 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.<String,String>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;
}
}
}

View File

@@ -0,0 +1,39 @@
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);
}
}
}

View File

@@ -0,0 +1,58 @@
package org.neo4j.rest.graphdb;
/**
* @author mh
* @since 13.12.10
*/
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class JsonHelper {
static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@SuppressWarnings("unchecked")
public static Map<String, Object> jsonToMap( String json ) {
return (Map<String, Object>) readJson( json );
}
@SuppressWarnings("unchecked")
public static List<Map<String, Object>> jsonToListOfRelationshipRepresentations( String json ) {
return (List<Map<String, Object>>) readJson( json );
}
private static Object readJson( String json ) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue( json, Object.class );
} catch ( IOException e ) {
throw new RuntimeException( e );
}
}
public static Object jsonToSingleValue( String json ) {
Object jsonObject = readJson( json );
return jsonObject instanceof Collection<?> ? jsonObject :
PropertiesMap.assertSupportedPropertyValue( jsonObject );
}
public static String createJsonFrom( Object data ) {
try {
StringWriter writer = new StringWriter();
JsonGenerator generator = OBJECT_MAPPER.getJsonFactory()
.createJsonGenerator( writer ).useDefaultPrettyPrinter();
OBJECT_MAPPER.writeValue( generator, data );
writer.close();
return writer.getBuffer().toString();
} catch ( IOException e ) {
throw new RuntimeException( e );
}
}
}

View File

@@ -0,0 +1,139 @@
package org.neo4j.rest.graphdb;
/**
* @author mh
* @since 13.12.10
*/
import org.neo4j.graphdb.PropertyContainer;
import java.lang.reflect.Array;
import java.util.*;
public class PropertiesMap {
private final Map<String, Object> values = new HashMap<String, Object>();
public PropertiesMap( PropertyContainer container ) {
for ( String key : container.getPropertyKeys() ) {
values.put( key, container.getProperty( key ) );
}
}
public PropertiesMap( Map<String, Object> map ) {
for ( Map.Entry<String, Object> entry : map.entrySet() ) {
values.put( entry.getKey(), toInternalType( entry.getValue() ) );
}
}
public Object getValue( String key ) {
return values.get( key );
}
public Map<String, Object> serialize() {
// TODO Nice with sorted, but TreeMap the best?
Map<String, Object> result = new TreeMap<String, Object>();
for ( Map.Entry<String, Object> entry : values.entrySet() ) {
result.put( entry.getKey(), toSerializedType( entry.getValue() ) );
}
return result;
}
void storeTo( PropertyContainer container ) {
for ( Map.Entry<String, Object> entry : values.entrySet() ) {
container.setProperty( entry.getKey(), entry.getValue() );
}
}
@SuppressWarnings("unchecked")
private static Object toInternalType( Object value ) {
if ( value instanceof List ) {
List list = (List) value;
if ( list.isEmpty() ) {
return new byte[0];
} else {
Object first = list.get( 0 );
if ( first instanceof String ) {
return stringArray( list );
} else if ( first instanceof Number ) {
return numberArray( list );
} else if ( first instanceof Boolean ) {
return booleanArray( list );
} else {
throw new RuntimeException( "Unsupported array type " + first.getClass() +
". Supported array types are arrays of all java primitives (" +
"byte[], char[], short[], int[], long[], float[], double[]) " +
"and String[]" );
}
}
} else {
return assertSupportedPropertyValue( value );
}
}
public static Object assertSupportedPropertyValue( Object value ) {
if ( value == null ) {
throw new RuntimeException( "null value not supported" );
}
if ( value instanceof String ) {
} else if ( value instanceof Number ) {
} else if ( value instanceof Boolean ) {
} else {
throw new RuntimeException( "Unsupported value type " + value.getClass() + "." +
" Supported value types are all java primitives (byte, char, short, int, " +
"long, float, double) and String, as well as arrays of all those types" );
}
return value;
}
private static Boolean[] booleanArray( List<Boolean> list ) {
return list.toArray( new Boolean[list.size()] );
}
private static Number[] numberArray( List<Number> numbers ) {
Number[] internal = new Number[numbers.size()];
for ( int i = 0; i < internal.length; i++ ) {
Number number = numbers.get( i );
if ( number instanceof Float || number instanceof Double ) {
number = number.doubleValue();
} else {
number = number.longValue();
}
internal[i] = number;
}
final Number[] result;
if ( internal[0] instanceof Double ) {
result = new Double[internal.length];
} else {
result = new Long[internal.length];
}
System.arraycopy( internal, 0, result, 0, internal.length );
return result;
}
private static String[] stringArray( List<String> strings ) {
return strings.toArray( new String[strings.size()] );
}
private Object toSerializedType( Object value ) {
if ( value.getClass().isArray() ) {
if ( value.getClass().getComponentType().isPrimitive() ) {
int size = Array.getLength( value );
List<Object> result = new ArrayList<Object>();
for ( int i = 0; i < size; i++ ) {
result.add( Array.get( value, i ) );
}
return result;
} else {
return Arrays.asList( (Object[]) value );
}
} else {
return value;
}
}
public boolean isEmpty() {
return values.isEmpty();
}
}

View File

@@ -0,0 +1,169 @@
package org.neo4j.rest.graphdb;
import com.sun.jersey.api.client.ClientResponse;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.helpers.collection.IterableWrapper;
import org.neo4j.rest.graphdb.util.ArrayConverter;
import javax.ws.rs.core.Response.Status;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
public class RestEntity implements PropertyContainer {
private Map<?, ?> structuralData;
private Map<String, Object> propertyData;
private long lastTimeFetchedPropertyData;
private RestGraphDatabase graphDatabase;
protected RestRequest restRequest;
private final ArrayConverter arrayConverter=new ArrayConverter();
public RestEntity( URI uri, RestGraphDatabase graphDatabase ) {
this( uri.toString(), graphDatabase );
}
public RestEntity( String uri, RestGraphDatabase graphDatabase ) {
this.restRequest = graphDatabase.getRestRequest().with( uri );
this.graphDatabase = graphDatabase;
}
public RestEntity( Map<?, ?> data, RestGraphDatabase graphDatabase ) {
this.structuralData = data;
this.graphDatabase = graphDatabase;
this.propertyData = (Map<String, Object>) data.get( "data" );
this.lastTimeFetchedPropertyData = System.currentTimeMillis();
String uri = (String) data.get( "self" );
this.restRequest = graphDatabase.getRestRequest().with( uri );
}
public String getUri() {
return this.restRequest.getUri().toString();
}
Map<?, ?> getStructuralData() {
if ( this.structuralData == null ) {
this.structuralData = restRequest.toMap( restRequest.get( "" ) );
}
return this.structuralData;
}
Map<String, Object> getPropertyData() {
if ( this.propertyData == null || timeElapsed( this.lastTimeFetchedPropertyData, graphDatabase.getPropertyRefetchTimeInMillis() ) ) {
ClientResponse response = restRequest.get( "properties" );
boolean ok = restRequest.statusIs( response, Status.OK );
if ( ok ) {
this.propertyData = (Map<String, Object>) restRequest.toMap( response );
} else {
this.propertyData = Collections.emptyMap();
}
this.lastTimeFetchedPropertyData = System.currentTimeMillis();
}
return this.propertyData;
}
private boolean timeElapsed( long since, long isItGreaterThanThis ) {
return System.currentTimeMillis() - since > isItGreaterThanThis;
}
public Object getProperty( String key ) {
Object value = getPropertyValue( key );
if ( value == null ) {
throw new NotFoundException( "'" + key + "' on " + this );
}
return value;
}
private Object getPropertyValue( String key ) {
Map<String, Object> properties = getPropertyData();
Object value = properties.get( key );
if ( value == null) return null;
if ( value instanceof Collection ) {
Collection col= (Collection) value;
if (col.isEmpty()) return new String[0]; // todo concrete value type ?
Object result = arrayConverter.toArray( col );
if (result == null) throw new IllegalStateException( "Could not determine type of property "+key );
properties.put(key,result);
return result;
}
return PropertiesMap.assertSupportedPropertyValue( value );
}
public Object getProperty( String key, Object defaultValue ) {
Object value = getPropertyValue( key );
return value != null ? value : defaultValue;
}
@SuppressWarnings("unchecked")
public Iterable<String> getPropertyKeys() {
return new IterableWrapper( getPropertyData().keySet() ) {
@Override
protected String underlyingObjectToObject( Object key ) {
return key.toString();
}
};
}
@SuppressWarnings("unchecked")
public Iterable<Object> getPropertyValues() {
return (Iterable<Object>) getPropertyData().values();
}
public boolean hasProperty( String key ) {
return getPropertyData().containsKey( key );
}
public Object removeProperty( String key ) {
Object value = getProperty( key, null );
restRequest.delete( "properties/" + key );
invalidatePropertyData();
return value;
}
public void setProperty( String key, Object value ) {
restRequest.put( "properties/" + key, JsonHelper.createJsonFrom( value ) );
invalidatePropertyData();
}
private void invalidatePropertyData() {
this.propertyData = null;
}
static long getEntityId( String uri ) {
return Long.parseLong( uri.substring( uri.lastIndexOf( '/' ) + 1 ) );
}
public long getId() {
return getEntityId( getUri() );
}
public void delete() {
restRequest.delete( "" );
}
@Override
public int hashCode() {
return (int) getId();
}
@Override
public boolean equals( Object o ) {
if (o == null) return false;
return getClass().equals( o.getClass() ) && getId() == ( (RestEntity) o ).getId();
}
public RestGraphDatabase getGraphDatabase() {
return graphDatabase;
}
public RestRequest getRestRequest() {
return restRequest;
}
@Override
public String toString() {
return getUri();
}
}

View File

@@ -0,0 +1,140 @@
package org.neo4j.rest.graphdb;
import com.sun.jersey.api.NotFoundException;
import com.sun.jersey.api.client.ClientResponse;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.event.KernelEventHandler;
import org.neo4j.graphdb.event.TransactionEventHandler;
import org.neo4j.graphdb.index.IndexManager;
import org.neo4j.kernel.AbstractGraphDatabase;
import org.neo4j.kernel.Config;
import org.neo4j.kernel.RestConfig;
import org.neo4j.rest.graphdb.index.RestIndexManager;
import javax.ws.rs.core.Response.Status;
import java.io.Serializable;
import java.net.URI;
import java.util.Map;
public class RestGraphDatabase extends AbstractGraphDatabase {
private RestRequest restRequest;
private long propertyRefetchTimeInMillis = 1000;
public RestGraphDatabase( URI uri ) {
restRequest = new RestRequest( uri );
}
public RestGraphDatabase( URI uri, String user, String password ) {
restRequest = new RestRequest( uri, user, password );
}
public Transaction beginTx() {
return new Transaction() {
public void success() {
}
public void finish() {
}
public void failure() {
}
};
}
public <T> TransactionEventHandler<T> registerTransactionEventHandler( TransactionEventHandler<T> tTransactionEventHandler ) {
throw new UnsupportedOperationException();
}
public <T> TransactionEventHandler<T> unregisterTransactionEventHandler( TransactionEventHandler<T> tTransactionEventHandler ) {
throw new UnsupportedOperationException();
}
public KernelEventHandler registerKernelEventHandler( KernelEventHandler kernelEventHandler ) {
throw new UnsupportedOperationException();
}
public KernelEventHandler unregisterKernelEventHandler( KernelEventHandler kernelEventHandler ) {
throw new UnsupportedOperationException();
}
public IndexManager index() {
return new RestIndexManager( restRequest, this );
}
public Node createNode() {
ClientResponse response = restRequest.post( "node", null );
if ( restRequest.statusOtherThan( response, Status.CREATED ) ) {
throw new RuntimeException( "" + response.getStatus() );
}
return new RestNode( response.getLocation(), this );
}
public boolean enableRemoteShell() {
throw new UnsupportedOperationException();
}
public boolean enableRemoteShell( Map<String, Serializable> config ) {
throw new UnsupportedOperationException();
}
public Iterable<Node> getAllNodes() {
throw new UnsupportedOperationException();
}
public Node getNodeById( long id ) {
ClientResponse response = restRequest.get( "node/" + id );
if ( restRequest.statusIs( response, Status.NOT_FOUND ) ) {
throw new NotFoundException( "" + id );
}
return new RestNode( restRequest.toMap( response ), this );
}
public Node getReferenceNode() {
Map<?, ?> map = restRequest.toMap( restRequest.get( "" ) );
return new RestNode( (String) map.get( "reference_node" ), this );
}
public Relationship getRelationshipById( long id ) {
ClientResponse response = restRequest.get( "relationship/" + id );
if ( restRequest.statusIs( response, Status.NOT_FOUND ) ) {
throw new NotFoundException( "" + id );
}
return new RestRelationship( restRequest.toMap( response ), this );
}
public Iterable<RelationshipType> getRelationshipTypes() {
throw new UnsupportedOperationException();
}
public void shutdown() {
}
public RestRequest getRestRequest() {
return restRequest;
}
public long getPropertyRefetchTimeInMillis() {
return propertyRefetchTimeInMillis;
}
@Override
public String getStoreDir() {
return restRequest.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

@@ -0,0 +1,139 @@
package org.neo4j.rest.graphdb;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.Traverser.Order;
import org.neo4j.helpers.collection.IterableWrapper;
import org.neo4j.helpers.collection.IteratorUtil;
import org.neo4j.helpers.collection.MapUtil;
import javax.ws.rs.core.Response.Status;
import java.net.URI;
import java.util.Collection;
import java.util.Map;
public class RestNode extends RestEntity implements Node {
public RestNode( URI uri, RestGraphDatabase graphDatabase ) {
super( uri, graphDatabase );
}
public RestNode( String uri, RestGraphDatabase graphDatabase ) {
super( uri, graphDatabase );
}
public RestNode( Map<?, ?> data, RestGraphDatabase graphDatabase ) {
super( data, graphDatabase );
}
public Relationship createRelationshipTo( Node toNode, RelationshipType type ) {
Map<String, Object> data = MapUtil.map( "to", ( (RestNode) toNode ).getUri(),
"type", type.name() );
ClientResponse response = restRequest.post( "relationships", JsonHelper.createJsonFrom( data ) );
if ( restRequest.statusOtherThan( response, Status.CREATED ) ) {
throw new RuntimeException( "" + response.getStatus() );
}
return new RestRelationship( response.getLocation(), getGraphDatabase() );
}
public Iterable<Relationship> getRelationships() {
return wrapRelationships( restRequest.get( "relationships/all" ) );
}
@SuppressWarnings("unchecked")
private Iterable<Relationship> wrapRelationships( ClientResponse response ) {
return new IterableWrapper<Relationship, Object>(
(Collection<Object>) restRequest.toEntity( response ) ) {
@Override
protected Relationship underlyingObjectToObject( Object data ) {
return new RestRelationship( (Map<?, ?>) data, getGraphDatabase() );
}
};
}
public Iterable<Relationship> getRelationships( RelationshipType... types ) {
String path = getStructuralData().get( "all_relationships" ) + "/";
int counter = 0;
for ( RelationshipType type : types ) {
if ( counter++ > 0 ) {
path += "&";
}
path += type.name();
}
return wrapRelationships( restRequest.get( path ) );
}
enum RestDirection {
INCOMING( Direction.INCOMING, "incoming", "in" ),
OUTGOING( Direction.OUTGOING, "outgoing", "out" ),
BOTH( Direction.BOTH, "all", "all" );
public final Direction direction;
public final String dataName;
public final String pathName;
RestDirection( Direction direction, String dataName, String pathName ) {
this.direction = direction;
this.dataName = dataName;
this.pathName = pathName;
}
static RestDirection from( Direction direction ) {
for ( RestDirection restDirection : values() ) {
if ( restDirection.direction == direction ) return restDirection;
}
throw new RuntimeException( "No Rest-Direction for " + direction );
}
}
public Iterable<Relationship> getRelationships( Direction direction ) {
return wrapRelationships( restRequest.get( "relationships/" + RestDirection.from( direction ).pathName ) );
}
public Iterable<Relationship> getRelationships( RelationshipType type,
Direction direction ) {
String relationshipsKey = RestDirection.from( direction ).dataName + "_relationships";
Object relationship = getStructuralData().get( relationshipsKey );
return wrapRelationships( restRequest.get( relationship + "/" + type.name() ) );
}
public Relationship getSingleRelationship( RelationshipType type,
Direction direction ) {
return IteratorUtil.singleOrNull( getRelationships( type, direction ) );
}
public boolean hasRelationship() {
return getRelationships().iterator().hasNext();
}
public boolean hasRelationship( RelationshipType... types ) {
return getRelationships( types ).iterator().hasNext();
}
public boolean hasRelationship( Direction direction ) {
return getRelationships( direction ).iterator().hasNext();
}
public boolean hasRelationship( RelationshipType type, Direction direction ) {
return getRelationships( type, direction ).iterator().hasNext();
}
public Traverser traverse( Order order, StopEvaluator stopEvaluator,
ReturnableEvaluator returnableEvaluator, Object... rels ) {
throw new UnsupportedOperationException();
}
public Traverser traverse( Order order, StopEvaluator stopEvaluator,
ReturnableEvaluator returnableEvaluator, RelationshipType type, Direction direction ) {
throw new UnsupportedOperationException();
}
public Traverser traverse( Order order, StopEvaluator stopEvaluator,
ReturnableEvaluator returnableEvaluator, RelationshipType type, Direction direction,
RelationshipType secondType, Direction secondDirection ) {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,56 @@
package org.neo4j.rest.graphdb;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.helpers.collection.IterableWrapper;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author Michael Hunger
* @since 03.02.11
*/
public class RestPathParser {
public static Path parse(Map path, final RestGraphDatabase restGraphDatabase) {
final Collection<Map<?, ?>> nodesData = (Collection<Map<?, ?>>) path.get("nodes");
final Collection<Map<?, ?>> relationshipsData = (Collection<Map<?, ?>>) path.get("relationships");
final Map<?, ?> lastRelationshipData = lastElement(relationshipsData);
final Map<?, ?> startData = (Map<?, ?>) path.get("start");
final Map<?, ?> endData = (Map<?, ?>) path.get("end");
final Integer length = (Integer) path.get("length");
return new SimplePath(
new RestNode(startData,restGraphDatabase),
new RestNode(endData,restGraphDatabase),
new RestRelationship(lastRelationshipData,restGraphDatabase),
length,
new IterableWrapper<Node, Map<?,?>>(nodesData) {
@Override
protected Node underlyingObjectToObject(Map<?, ?> data) {
return new RestNode(data,restGraphDatabase);
}
},
new IterableWrapper<Relationship, Map<?,?>>(relationshipsData) {
@Override
protected Relationship underlyingObjectToObject(Map<?, ?> data) {
return new RestRelationship(data,restGraphDatabase);
}
});
}
private static Map<?, ?> lastElement(Collection<Map<?, ?>> collection) {
if (collection.isEmpty()) return null;
if (collection instanceof List) {
List<Map<?,?>> list = (List<Map<?,?>>) collection;
return list.get(list.size()-1);
}
Map<?, ?> result = null;
for (Map<?, ?> value : collection) {
result=value;
}
return result;
}
}

View File

@@ -0,0 +1,61 @@
package org.neo4j.rest.graphdb;
import org.neo4j.graphdb.*;
import java.net.URI;
import java.util.Map;
public class RestRelationship extends RestEntity implements Relationship {
RestRelationship( URI uri, RestGraphDatabase graphDatabaseService ) {
super( uri, graphDatabaseService );
}
RestRelationship( String uri, RestGraphDatabase graphDatabase ) {
super( uri, graphDatabase );
}
public RestRelationship( Map<?, ?> data, RestGraphDatabase graphDatabase ) {
super( data, graphDatabase );
}
public Node getEndNode() {
return node( (String) getStructuralData().get( "end" ) );
}
public Node[] getNodes() {
return new Node[]{
node( (String) getStructuralData().get( "start" ) ),
node( (String) getStructuralData().get( "end" ) )
};
}
public Node getOtherNode( Node node ) {
long nodeId = node.getId();
String startNodeUri = (String) getStructuralData().get( "start" );
String endNodeUri = (String) getStructuralData().get( "end" );
if ( getEntityId( startNodeUri ) == nodeId ) {
return node( endNodeUri );
} else if ( getEntityId( endNodeUri ) == nodeId ) {
return node( startNodeUri );
} else {
throw new NotFoundException( node + " isn't one of start/end for " + this );
}
}
private RestNode node( String uri ) {
return new RestNode( uri, getGraphDatabase() );
}
public Node getStartNode() {
return node( (String) getStructuralData().get( "start" ) );
}
public RelationshipType getType() {
return DynamicRelationshipType.withName( (String) getStructuralData().get( "type" ) );
}
public boolean isType( RelationshipType type ) {
return type.name().equals( getStructuralData().get( "type" ) );
}
}

View File

@@ -0,0 +1,122 @@
package org.neo4j.rest.graphdb;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.WebResource.Builder;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.Map;
public class RestRequest {
private final URI baseUri;
private final Client client;
public RestRequest( URI baseUri ) {
this( baseUri, null, null );
}
public RestRequest( URI baseUri, String username, String password ) {
this.baseUri = uriWithoutSlash( baseUri );
client = Client.create();
if ( username != null ) client.addFilter( new HTTPBasicAuthFilter( username, password ) );
}
private RestRequest( URI uri, Client client ) {
this.baseUri = uriWithoutSlash( uri );
this.client = client;
}
private URI uriWithoutSlash( URI uri ) {
String uriString = uri.toString();
return uriString.endsWith( "/" ) ? uri( uriString.substring( 0, uriString.length() - 1 ) ) : uri;
}
public static String encode( Object value ) {
if ( value == null ) return "";
try {
return URLEncoder.encode( value.toString(), "utf-8" ).replaceAll( "\\+", "%20" );
} catch ( UnsupportedEncodingException e ) {
throw new RuntimeException( e );
}
}
private Builder builder( String path ) {
WebResource resource = client.resource( uri( pathOrAbsolute( path ) ) );
return resource.accept( MediaType.APPLICATION_JSON_TYPE );
}
private String pathOrAbsolute( String path ) {
if ( path.startsWith( "http://" ) ) return path;
return baseUri + "/" + path;
}
public ClientResponse get( String path ) {
return builder( path ).get( ClientResponse.class );
}
public ClientResponse delete( String path ) {
return builder( path ).delete( ClientResponse.class );
}
public ClientResponse post( String path, String data ) {
Builder builder = builder( path );
if ( data != null ) {
builder = builder.entity( data, MediaType.APPLICATION_JSON_TYPE );
}
return builder.post( ClientResponse.class );
}
public ClientResponse put( String path, String data ) {
Builder builder = builder( path );
if ( data != null ) {
builder = builder.entity( data, MediaType.APPLICATION_JSON_TYPE );
}
return builder.put( ClientResponse.class );
}
public Object toEntity( ClientResponse response ) {
return JsonHelper.jsonToSingleValue( entityString( response ) );
}
public Map<?, ?> toMap( ClientResponse response ) {
return JsonHelper.jsonToMap( entityString( response ) );
}
private String entityString( ClientResponse response ) {
return response.getEntity( String.class );
}
public boolean statusIs( ClientResponse response, Response.StatusType status ) {
return response.getStatus() == status.getStatusCode();
}
public boolean statusOtherThan( ClientResponse response, Response.StatusType status ) {
return !statusIs( response, status );
}
public RestRequest with( String uri ) {
return new RestRequest( uri( uri ), client );
}
private URI uri( String uri ) {
try {
return new URI( uri );
} catch ( URISyntaxException e ) {
throw new RuntimeException( e );
}
}
public URI getUri() {
return baseUri;
}
}

View File

@@ -0,0 +1,155 @@
package org.neo4j.rest.graphdb;
import com.sun.jersey.api.client.ClientResponse;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.traversal.*;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.helpers.Predicate;
import org.neo4j.kernel.Traversal;
import org.neo4j.kernel.Uniqueness;
import javax.ws.rs.core.Response;
import java.lang.reflect.Field;
import java.util.*;
/**
* @author Michael Hunger
* @since 02.02.11
*/
public class RestTraversal implements RestTraversalDescription {
private static final String FULLPATH = "fullpath";
private final Map<String, Object> description=new HashMap<String, Object>();
@Override
public String toString() {
return description.toString();
}
public TraversalDescription uniqueness(UniquenessFactory uniquenessFactory) {
return uniqueness(uniquenessFactory,null);
}
public TraversalDescription uniqueness(UniquenessFactory uniquenessFactory, Object value) {
String uniqueness = restify(uniquenessFactory);
add("uniqueness",value==null ? uniqueness : toMap("name",uniqueness, "value", value));
return null;
}
private String restify(UniquenessFactory uniquenessFactory) {
if (uniquenessFactory instanceof Uniqueness) {
return ((Uniqueness)uniquenessFactory).name().toLowerCase().replace("_"," ");
}
throw new UnsupportedOperationException("Only values of "+Uniqueness.class+" are supported");
}
public TraversalDescription prune(PruneEvaluator pruneEvaluator) {
Integer maxDepth= getMaxDepthValueOrNull(pruneEvaluator);
if (maxDepth!=null) {
return maxDepth(maxDepth);
}
throw new UnsupportedOperationException("Only max depth supported");
}
private Integer getMaxDepthValueOrNull(PruneEvaluator pruneEvaluator) {
try {
final Field depthField = pruneEvaluator.getClass().getDeclaredField("val$depth");
depthField.setAccessible(true);
return (Integer) depthField.get(pruneEvaluator);
} catch (Exception e) {
return null;
}
}
public TraversalDescription filter(Predicate<Path> pathPredicate) {
if (pathPredicate == Traversal.returnAll()) return add("return filter",toMap("language","builtin", "name","all"));
if (pathPredicate == Traversal.returnAllButStartNode()) return add("return filter",toMap("language","builtin", "name","all but start node"));
throw new UnsupportedOperationException("Only builtin paths supported");
}
public TraversalDescription evaluator(Evaluator evaluator) {
return null;
}
public TraversalDescription prune(ScriptLanguage language, String code) {
return add("prune evaluator",toMap("language",language.name().toLowerCase(),"body",code ));
}
public TraversalDescription filter(ScriptLanguage language, String code) {
return add("return filter",toMap("language",language.name().toLowerCase(),"body",code ));
}
public TraversalDescription maxDepth(int depth) {
return add("max depth",depth);
}
public TraversalDescription order(BranchOrderingPolicy branchOrderingPolicy) {
throw new UnsupportedOperationException();
}
public TraversalDescription depthFirst() {
return add("order","depth first");
}
public TraversalDescription breadthFirst() {
return add("order", "breadth first");
}
private RestTraversalDescription add(String key, Object value) {
description.put(key,value);
return this;
}
public TraversalDescription relationships(RelationshipType relationshipType) {
return relationships(relationshipType, null);
}
public TraversalDescription relationships(RelationshipType relationshipType, Direction direction) {
if (!description.containsKey("relationships")) {
description.put("relationships",new HashSet<Map<String,Object>>());
}
Set<Map<String,Object>> relationships= (Set<Map<String, Object>>) description.get("relationships");
relationships.add(toMap("type", relationshipType, "direction", directionString(direction)));
return this;
}
private Map<String, Object> toMap(Object...params) {
if (params.length % 2 != 0) throw new IllegalArgumentException("toMap needs an even number of arguments, but was "+Arrays.toString(params));
Map<String, Object> result = new HashMap<String, Object>();
for (int i = 0; i < params.length; i+=2) {
if (params[i+1] == null) continue;
result.put(params[i].toString(), params[i + 1].toString());
}
return result;
}
private String directionString(Direction direction) {
if (direction==Direction.INCOMING) return "in";
if (direction==Direction.OUTGOING) return "out";
return null;
}
public TraversalDescription expand(RelationshipExpander relationshipExpander) {
return null;
}
public Traverser traverse(Node node) {
final RestNode restNode = (RestNode) node;
final RestRequest request = restNode.getRestRequest();
final String traversalJson = JsonHelper.createJsonFrom(description);
final ClientResponse result = request.post("traverse/" + FULLPATH, traversalJson);
if (request.statusOtherThan(result, Response.Status.OK)) throw new RuntimeException(String.format("Error executing traversal: %d %s",result.getStatus(), traversalJson));
final Object col = request.toEntity(result);
if (!(col instanceof Collection)) throw new RuntimeException(String.format("Unexpected traversal result, %s instead of collection", col!=null ? col.getClass() : null));
return new RestTraverser((Collection) col,restNode.getGraphDatabase());
}
public static RestTraversalDescription description() {
return new RestTraversal();
}
public Map<String,Object> getPostData() {
return description;
}
}

View File

@@ -0,0 +1,19 @@
package org.neo4j.rest.graphdb;
import org.neo4j.graphdb.traversal.TraversalDescription;
/**
* @author Michael Hunger
* @since 03.02.11
*/
public interface RestTraversalDescription extends TraversalDescription {
TraversalDescription prune(ScriptLanguage language, String code);
TraversalDescription filter(ScriptLanguage language, String code);
TraversalDescription maxDepth(int depth);
public enum ScriptLanguage {
JAVASCRIPT;
}
}

View File

@@ -0,0 +1,54 @@
package org.neo4j.rest.graphdb;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.helpers.collection.IterableWrapper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/**
* @author Michael Hunger
* @since 03.02.11
*/
public class RestTraverser implements Traverser {
private final Collection<Path> paths;
public RestTraverser(Collection col, RestGraphDatabase restGraphDatabase) {
this.paths = parseToPaths(col,restGraphDatabase);
}
private Collection<Path> parseToPaths(Collection col, RestGraphDatabase restGraphDatabase) {
Collection<Path> result=new ArrayList<Path>(col.size());
for (Object path : col) {
if (!(path instanceof Map)) throw new RuntimeException("Expected Map for Path representation but got: "+(path!=null ? path.getClass() : null));
result.add(RestPathParser.parse((Map) path, restGraphDatabase));
}
return result;
}
public Iterable<Node> nodes() {
return new IterableWrapper<Node, Path>(paths) {
@Override
protected Node underlyingObjectToObject(Path path) {
return path.endNode();
}
};
}
public Iterable<Relationship> relationships() {
return new IterableWrapper<Relationship, Path>(paths) {
@Override
protected Relationship underlyingObjectToObject(Path path) {
return path.lastRelationship();
}
};
}
public Iterator<Path> iterator() {
return paths.iterator();
}
}

View File

@@ -0,0 +1,86 @@
package org.neo4j.rest.graphdb;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import java.util.Iterator;
/**
* @author Michael Hunger
* @since 03.02.11
*/
public class SimplePath implements Path {
Iterable<Relationship> relationships;
Iterable<Node> nodes;
private final Relationship lastRelationship;
private int length;
private Node startNode;
private Node endNode;
public SimplePath(Node startNode, Node endNode, Relationship lastRelationship, int length, Iterable<Node> nodes, Iterable<Relationship> relationships) {
this.startNode = startNode;
this.endNode = endNode;
this.lastRelationship = lastRelationship;
this.length = length;
this.nodes = nodes;
this.relationships = relationships;
}
public Node startNode() {
return startNode;
}
public Node endNode() {
return endNode;
}
public Relationship lastRelationship() {
return lastRelationship;
}
public Iterable<Relationship> relationships() {
return relationships;
}
public Iterable<Node> nodes() {
return nodes;
}
public int length() {
return length;
}
public Iterator<PropertyContainer> iterator() {
return new Iterator<PropertyContainer>()
{
Iterator<? extends PropertyContainer> current = nodes().iterator();
Iterator<? extends PropertyContainer> next = relationships().iterator();
public boolean hasNext()
{
return current.hasNext();
}
public PropertyContainer next()
{
try
{
return current.next();
}
finally
{
Iterator<? extends PropertyContainer> temp = current;
current = next;
next = temp;
}
}
public void remove()
{
next.remove();
}
};
}
}

View File

@@ -0,0 +1,137 @@
package org.neo4j.rest.graphdb.index;
import com.sun.jersey.api.client.ClientResponse;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.rest.graphdb.JsonHelper;
import org.neo4j.rest.graphdb.RestEntity;
import org.neo4j.rest.graphdb.RestGraphDatabase;
import org.neo4j.rest.graphdb.RestRequest;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import javax.ws.rs.core.Response;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
/**
* @author mh
* @since 24.01.11
*/
public abstract class RestIndex<T extends PropertyContainer> implements Index<T> {
private final RestRequest restRequest;
private final String indexName;
protected final RestGraphDatabase restGraphDatabase;
RestIndex( RestRequest restRequest, String indexName, RestGraphDatabase restGraphDatabase ) {
this.restRequest = restRequest;
this.indexName = indexName;
this.restGraphDatabase = restGraphDatabase;
}
public String getName() {
return indexName;
}
private String getTypeName() {
return getEntityType().getSimpleName().toLowerCase();
}
public void add( T entity, String key, Object value ) {
String uri = ( (RestEntity) entity ).getUri();
restRequest.post( indexPath( key, value ), JsonHelper.createJsonFrom( uri ) );
}
private String indexPath( String key, Object value ) {
return "index/" + getTypeName() + "/" + indexName + "/" + RestRequest.encode( key ) + "/" + RestRequest.encode( value );
}
public void remove( T entity, String key, Object value ) {
restRequest.delete( indexPath( key, value ) + "/" + ( (RestEntity) entity ).getId() );
}
public void remove(T entity, String key) {
throw new NotImplementedException();
}
public void remove(T entity) {
throw new NotImplementedException();
}
public void delete() {
throw new NotImplementedException();
}
public org.neo4j.graphdb.index.IndexHits<T> get( String key, Object value ) {
return query( key, value );
}
public IndexHits<T> query( String key, Object value ) {
ClientResponse response = restRequest.get( indexPath( key, value ) );
if ( restRequest.statusIs( response, Response.Status.OK ) ) {
Collection hits = (Collection) restRequest.toEntity( response );
return new SimpleIndexHits<T>( hits, hits.size() );
} else {
return new SimpleIndexHits<T>( Collections.emptyList(), 0 );
}
}
protected abstract T createEntity( Map<?, ?> item );
public org.neo4j.graphdb.index.IndexHits<T> query( Object value ) {
throw new UnsupportedOperationException();
}
private class SimpleIndexHits<T extends PropertyContainer> implements IndexHits<T> {
private Collection<Object> hits;
private int size;
private Iterator<Object> iterator;
public SimpleIndexHits( Collection<Object> hits, int size ) {
this.hits = hits;
this.iterator = this.hits.iterator();
this.size = size;
}
public int size() {
return size;
}
public void close() {
}
public T getSingle() {
Iterator<Object> it = hits.iterator();
return it.hasNext() ? transform( it.next() ) : null;
}
public float currentScore() {
return 0;
}
public Iterator<T> iterator() {
return this;
}
public boolean hasNext() {
return iterator.hasNext();
}
public T next() {
Object value = iterator.next();
return transform( value );
}
private T transform( Object value ) {
return (T) createEntity( (Map<?, ?>) value );
}
public void remove() {
}
}
}

View File

@@ -0,0 +1,77 @@
package org.neo4j.rest.graphdb.index;
import com.sun.jersey.api.client.ClientResponse;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexManager;
import org.neo4j.graphdb.index.RelationshipIndex;
import org.neo4j.rest.graphdb.RestGraphDatabase;
import org.neo4j.rest.graphdb.RestRequest;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
public class RestIndexManager implements IndexManager {
private RestRequest restRequest;
private RestGraphDatabase restGraphDatabase;
public RestIndexManager( RestRequest restRequest, RestGraphDatabase restGraphDatabase ) {
this.restRequest = restRequest;
this.restGraphDatabase = restGraphDatabase;
}
public boolean existsForNodes( String indexName ) {
return indexInfo( "node" ).containsKey( indexName );
}
private Map<String, ?> indexInfo( final String indexType ) {
ClientResponse response = restRequest.get( "index/" + indexType );
if ( restRequest.statusIs( response, ClientResponse.Status.NO_CONTENT ) ) return Collections.emptyMap();
return (Map<String, ?>) restRequest.toMap( response );
}
public Index<Node> forNodes( String indexName ) {
return new RestNodeIndex( restRequest, indexName, restGraphDatabase );
}
public Index<Node> forNodes( String indexName, Map<String, String> stringStringMap ) {
return new RestNodeIndex( restRequest, indexName, restGraphDatabase );
}
public String[] nodeIndexNames() {
Set<String> keys = indexInfo( "node" ).keySet();
return keys.toArray( new String[keys.size()] );
}
public boolean existsForRelationships( String indexName ) {
return indexInfo( "relationship" ).containsKey( indexName );
}
public RelationshipIndex forRelationships( String indexName ) {
return new RestRelationshipIndex( restRequest, indexName, restGraphDatabase );
}
public RelationshipIndex forRelationships( String indexName, Map<String, String> stringStringMap ) {
return new RestRelationshipIndex( restRequest, indexName, restGraphDatabase );
}
public String[] relationshipIndexNames() {
Set<String> keys = indexInfo( "relationship" ).keySet();
return keys.toArray( new String[keys.size()] );
}
public Map<String, String> getConfiguration( Index<? extends PropertyContainer> index ) {
return null;
}
public String setConfiguration( Index<? extends PropertyContainer> index, String s, String s1 ) {
return null;
}
public String removeConfiguration( Index<? extends PropertyContainer> index, String s ) {
return null;
}
}

View File

@@ -0,0 +1,34 @@
package org.neo4j.rest.graphdb.index;
import org.neo4j.graphdb.Node;
import org.neo4j.rest.graphdb.RestGraphDatabase;
import org.neo4j.rest.graphdb.RestNode;
import org.neo4j.rest.graphdb.RestRequest;
import java.util.Map;
/**
* @author mh
* @since 24.01.11
*/
public class RestNodeIndex extends RestIndex<Node> {
public RestNodeIndex( RestRequest restRequest, String indexName, RestGraphDatabase restGraphDatabase ) {
super( restRequest, indexName, restGraphDatabase );
}
public Class<Node> getEntityType() {
return Node.class;
}
public void remove(Node entity, String key) {
throw new UnsupportedOperationException();
}
public void remove(Node entity) {
throw new UnsupportedOperationException();
}
protected Node createEntity(Map<?, ?> item) {
return new RestNode((Map<?, ?>) item, restGraphDatabase);
}
}

View File

@@ -0,0 +1,48 @@
package org.neo4j.rest.graphdb.index;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.RelationshipIndex;
import org.neo4j.rest.graphdb.RestGraphDatabase;
import org.neo4j.rest.graphdb.RestRelationship;
import org.neo4j.rest.graphdb.RestRequest;
import java.util.Map;
/**
* @author mh
* @since 24.01.11
*/
public class RestRelationshipIndex extends RestIndex<Relationship> implements RelationshipIndex {
public RestRelationshipIndex( RestRequest restRequest, String indexName, RestGraphDatabase restGraphDatabase ) {
super( restRequest, indexName, restGraphDatabase );
}
public Class<Relationship> getEntityType() {
return Relationship.class;
}
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 );
}
public org.neo4j.graphdb.index.IndexHits<Relationship> get( String s, Object o, Node node, Node node1 ) {
throw new UnsupportedOperationException();
}
public org.neo4j.graphdb.index.IndexHits<Relationship> query( String s, Object o, Node node, Node node1 ) {
throw new UnsupportedOperationException();
}
public org.neo4j.graphdb.index.IndexHits<Relationship> query( Object o, Node node, Node node1 ) {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,62 @@
package org.neo4j.rest.graphdb.util;
import java.lang.reflect.Array;
import java.util.Collection;
/**
* @author Michael Hunger
* @since 02.02.11
*/
public class ArrayConverter {
public Object toArray(Collection col) {
Object entry = getNonNullEntry(col);
if (entry==null) return null;
Class<? extends Object> elementClass = getArrayElementClass( entry );
Object array = Array.newInstance(elementClass, col.size());
if (Object.class.isAssignableFrom( elementClass)) {
col.toArray( (Object[])array );
} else {
int i=0;
for ( Object value : col ) {
setArrayValue(array,i,value,elementClass);
i+=1;
}
}
return array;
}
private void setArrayValue( Object array, int i, Object value, Class<? extends Object> type ) {
if (value==null) return;
if ( value instanceof Number ) {
Number number = (Number) value;
if (type.equals( int.class )) { Array.setInt( array, i, number.intValue()); return;}
if (type.equals( long.class )) { Array.setLong( array, i, number.longValue()); return;}
if (type.equals( double.class )) { Array.setDouble( array, i, number.doubleValue()); return;}
if (type.equals( float.class )) { Array.setFloat( array, i, number.floatValue()); return;}
if (type.equals( byte.class )) { Array.setByte( array, i, number.byteValue()); return;}
if (type.equals( short.class )) { Array.setShort( array, i, number.shortValue()); return;}
}
if (type.equals( char.class )) { Array.setChar( array, i, (Character)value ); return;}
if (type.equals( boolean.class )) { Array.setBoolean( array, i, (Boolean) value ); return;}
}
private Class<? extends Object> getArrayElementClass( Object entry ) {
Class<? extends Object> type = entry.getClass();
if (type.equals( Integer.class )) return int.class;
if (type.equals( Long.class )) return long.class;
if (type.equals( Double.class )) return double.class;
if (type.equals( Float.class )) return float.class;
if (type.equals( Byte.class )) return byte.class;
if (type.equals( Short.class )) return short.class;
if (type.equals( Character.class )) return char.class;
if (type.equals( Boolean.class )) return boolean.class;
return type;
}
private Object getNonNullEntry(Collection col) {
for ( Object entry : col ) {
if (entry!=null) return entry;
}
return null;
}
}

View File

@@ -0,0 +1,36 @@
package org.neo4j.rest.graphdb;
import org.hamcrest.Description;
import org.junit.internal.matchers.TypeSafeMatcher;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
/**
* @author mh
* @since 24.01.11
*/
class IsRelationshipToNodeMatcher extends TypeSafeMatcher<Iterable<Relationship>> {
private final Node startNode;
private final Node endNode;
public IsRelationshipToNodeMatcher( Node startNode, Node endNode ) {
this.startNode = startNode;
this.endNode = endNode;
}
@Override
public boolean matchesSafely( Iterable<Relationship> relationships ) {
return relationshipFromTo( relationships, startNode, endNode ) != null;
}
public static Relationship relationshipFromTo( Iterable<Relationship> relationships, final Node startNode, final Node endNode ) {
for ( Relationship relationship : relationships ) {
if ( relationship.getOtherNode( startNode ).equals( endNode ) ) return relationship;
}
return null;
}
public void describeTo( Description description ) {
description.appendValue( startNode ).appendText( " to " ).appendValue( endNode ).appendText( "not contained in relationships" );
}
}

View File

@@ -0,0 +1,96 @@
package org.neo4j.rest.graphdb;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.kernel.AbstractGraphDatabase;
import org.neo4j.server.AddressResolver;
import org.neo4j.server.NeoServerWithEmbeddedWebServer;
import org.neo4j.server.database.Database;
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.io.File;
import java.net.URI;
import java.net.URL;
/**
* @author mh
* @since 24.03.11
*/
public class LocalTestServer {
private NeoServerWithEmbeddedWebServer neoServer;
private final int port;
private final String hostname;
protected String propertiesFile = "test-db.properties";
public LocalTestServer() {
this("localhost",7473);
}
public LocalTestServer(String hostname, int port) {
this.port = port;
this.hostname = hostname;
}
public void start() {
if (neoServer!=null) throw new IllegalStateException("Server already running");
URL url = getClass().getResource("/" + propertiesFile);
if (url==null) throw new IllegalArgumentException("Could not resolve properties file "+propertiesFile);
neoServer = new NeoServerWithEmbeddedWebServer(new AddressResolver() {
@Override
public String getHostname() {
return hostname;
}
}, new StartupHealthCheck(), new File(url.getPath()), new Jetty6WebServer()) {
protected void registerServerModules() {
registerModule(RESTApiModule.class);
registerModule(ThirdPartyJAXRSModule.class);
}
@Override
protected int getWebServerPort() {
return port;
}
};
neoServer.start();
}
public void stop() {
try {
neoServer.stop();
} catch(Exception e) {
System.err.println("Error stopping server: "+e.getMessage());
}
neoServer=null;
}
public int getPort() {
return port;
}
public String getHostname() {
return hostname;
}
public LocalTestServer withPropertiesFile(String propertiesFile) {
this.propertiesFile = propertiesFile;
return this;
}
public Database getDatabase() {
return neoServer.getDatabase();
}
public URI baseUri() {
return neoServer.baseUri();
}
public void cleanDb() {
Neo4jDatabaseCleaner cleaner = new Neo4jDatabaseCleaner(getGraphDatabase());
cleaner.cleanDb();
}
public AbstractGraphDatabase getGraphDatabase() {
return getDatabase().graph;
}
}

View File

@@ -0,0 +1,67 @@
package org.neo4j.rest.graphdb;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.IndexManager;
import org.neo4j.kernel.AbstractGraphDatabase;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @author mh
* @since 02.03.11
*/
public class Neo4jDatabaseCleaner {
private AbstractGraphDatabase graph;
public Neo4jDatabaseCleaner(AbstractGraphDatabase graph) {
this.graph = graph;
}
public Map<String, Object> cleanDb() {
Map<String, Object> result = new HashMap<String, Object>();
Transaction tx = graph.beginTx();
try {
removeNodes(result);
clearIndex(result);
tx.success();
} finally {
tx.finish();
}
return result;
}
private void removeNodes(Map<String, Object> result) {
Node refNode = graph.getReferenceNode();
int nodes = 0, relationships = 0;
for (Node node : graph.getAllNodes()) {
for (Relationship rel : node.getRelationships(Direction.OUTGOING)) {
rel.delete();
relationships++;
}
if (!refNode.equals(node)) {
node.delete();
nodes++;
}
}
result.put("nodes", nodes);
result.put("relationships", relationships);
}
private void clearIndex(Map<String, Object> result) {
IndexManager indexManager = graph.index();
result.put("node-indexes", Arrays.asList(indexManager.nodeIndexNames()));
result.put("relationship-indexes", Arrays.asList(indexManager.relationshipIndexNames()));
for (String ix : indexManager.nodeIndexNames()) {
indexManager.forNodes(ix).delete();
}
for (String ix : indexManager.relationshipIndexNames()) {
indexManager.forRelationships(ix).delete();
}
}
}

View File

@@ -0,0 +1,70 @@
package org.neo4j.rest.graphdb;
import org.junit.Assert;
import org.junit.Test;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import java.util.Arrays;
public class RestEntityTest extends RestTestBase {
@Test
public void testSetProperty() {
graphDb.getReferenceNode().setProperty( "name", "test" );
Node node = graphDb.getReferenceNode();
Assert.assertEquals( "test", node.getProperty( "name" ) );
}
@Test
public void testSetStringArrayProperty() {
graphDb.getReferenceNode().setProperty( "name", new String[]{"test"} );
Node node = graphDb.getReferenceNode();
Assert.assertArrayEquals( new String[]{"test"}, (String[])node.getProperty( "name" ) );
}
@Test
public void testSetDoubleArrayProperty() {
double[] data = {0, 1, 2};
graphDb.getReferenceNode().setProperty( "data", data );
Node node = graphDb.getReferenceNode();
Assert.assertTrue("same double array",Arrays.equals( data, (double[])node.getProperty( "data" ) ));
}
@Test
public void testRemoveProperty() {
Node node = graphDb.getReferenceNode();
node.setProperty( "name", "test" );
Assert.assertEquals( "test", node.getProperty( "name" ) );
node.removeProperty( "name" );
Assert.assertEquals( false, node.hasProperty( "name" ) );
}
@Test
public void testSetPropertyOnRelationship() {
Node refNode = graphDb.getReferenceNode();
Node node = graphDb.createNode();
Relationship rel = refNode.createRelationshipTo( node, Type.TEST );
rel.setProperty( "name", "test" );
Assert.assertEquals( "test", rel.getProperty( "name" ) );
Relationship foundRelationship = IsRelationshipToNodeMatcher.relationshipFromTo( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), refNode, node );
Assert.assertEquals( "test", foundRelationship.getProperty( "name" ) );
}
@Test
public void testRemovePropertyOnRelationship() {
Node refNode = graphDb.getReferenceNode();
Node node = graphDb.createNode();
Relationship rel = refNode.createRelationshipTo( node, Type.TEST );
rel.setProperty( "name", "test" );
Assert.assertEquals( "test", rel.getProperty( "name" ) );
Relationship foundRelationship = IsRelationshipToNodeMatcher.relationshipFromTo( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), refNode, node );
Assert.assertEquals( "test", foundRelationship.getProperty( "name" ) );
rel.removeProperty( "name" );
Assert.assertEquals( false, rel.hasProperty( "name" ) );
Relationship foundRelationship2 = IsRelationshipToNodeMatcher.relationshipFromTo( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), refNode, node );
Assert.assertEquals( false, foundRelationship2.hasProperty( "name" ) );
}
}

View File

@@ -0,0 +1,56 @@
package org.neo4j.rest.graphdb;
import org.junit.Assert;
import org.junit.Test;
import org.neo4j.graphdb.*;
import java.util.Date;
public class RestGraphDbTest extends RestTestBase {
@Test
public void testGetRefNode() {
Node refNode = graphDb.getReferenceNode();
Node nodeById = graphDb.getNodeById( 0 );
Assert.assertEquals( refNode, nodeById );
}
@Test
public void testCreateNode() {
Node node = graphDb.createNode();
Assert.assertEquals( node, graphDb.getNodeById( node.getId() ) );
}
@Test
public void testCreateRelationship() {
Node refNode = graphDb.getReferenceNode();
Node node = graphDb.createNode();
Relationship rel = refNode.createRelationshipTo( node, Type.TEST );
Relationship foundRelationship = IsRelationshipToNodeMatcher.relationshipFromTo( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), refNode, node );
Assert.assertNotNull( "found relationship", foundRelationship );
Assert.assertEquals( "same relationship", rel, foundRelationship );
Assert.assertThat( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), new IsRelationshipToNodeMatcher( refNode, node ) );
Assert.assertThat( refNode.getRelationships( Direction.OUTGOING ), new IsRelationshipToNodeMatcher( refNode, node ) );
Assert.assertThat( refNode.getRelationships( Direction.BOTH ), new IsRelationshipToNodeMatcher( refNode, node ) );
Assert.assertThat( refNode.getRelationships( Type.TEST ), new IsRelationshipToNodeMatcher( refNode, node ) );
}
@Test
public void testBasic() {
Node refNode = graphDb.getReferenceNode();
Node node = graphDb.createNode();
Relationship rel = refNode.createRelationshipTo( node,
DynamicRelationshipType.withName( "TEST" ) );
rel.setProperty( "date", new Date().getTime() );
node.setProperty( "name", "Mattias test" );
refNode.createRelationshipTo( node,
DynamicRelationshipType.withName( "TEST" ) );
for ( Relationship relationship : refNode.getRelationships() ) {
System.out.println( "rel prop:" + relationship.getProperty( "date", null ) );
Node endNode = relationship.getEndNode();
System.out.println( "node prop:" + endNode.getProperty( "name", null ) );
}
}
}

View File

@@ -0,0 +1,93 @@
package org.neo4j.rest.graphdb;
import org.junit.Assert;
import org.junit.Test;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.graphdb.index.RelationshipIndex;
import java.util.Arrays;
import java.util.Iterator;
public class RestIndexTest extends RestTestBase {
private static final String NODE_INDEX_NAME = "NODE_INDEX";
private static final String REL_INDEX_NAME = "REL_INDEX";
@Test
public void testAddToNodeIndex() {
nodeIndex().add(node(), "name", "test");
IndexHits<Node> hits = nodeIndex().get("name", "test");
Assert.assertEquals("index results", true, hits.hasNext());
Assert.assertEquals(node(), hits.next());
}
@Test
public void testNotFoundInNodeIndex() {
IndexHits<Node> hits = nodeIndex().get("foo", "bar");
Assert.assertEquals("no index results", false, hits.hasNext());
}
@Test
public void testAddToRelationshipIndex() {
final long value = System.currentTimeMillis();
relationshipIndex().add(relationship(), "name", value);
IndexHits<Relationship> hits = relationshipIndex().get("name", value);
Assert.assertEquals("index results", true, hits.hasNext());
Assert.assertEquals(relationship(), hits.next());
}
@Test
public void testNotFoundInRelationshipIndex() {
IndexHits<Relationship> hits = relationshipIndex().get("foo", "bar");
Assert.assertEquals("no index results", false, hits.hasNext());
}
@Test
public void testDeleteFromNodeIndex() {
String value = String.valueOf(System.currentTimeMillis());
nodeIndex().add(node(), "time", value);
IndexHits<Node> hits = nodeIndex().get("time", value);
Assert.assertEquals("found in index results", true, hits.hasNext());
Assert.assertEquals("found in index results", node(), hits.next());
nodeIndex().remove(node(), "time", value);
IndexHits<Node> hitsAfterRemove = nodeIndex().get("time", value);
Assert.assertEquals("not found in index results", false, hitsAfterRemove.hasNext());
}
@Test
public void testDeleteFromRelationshipIndex() {
String value = String.valueOf(System.currentTimeMillis());
relationshipIndex().add(relationship(), "time", value);
IndexHits<Relationship> hits = relationshipIndex().get("time", value);
Assert.assertEquals("found in index results", true, hits.hasNext());
Assert.assertEquals("found in index results", relationship(), hits.next());
relationshipIndex().remove(relationship(), "time", value);
IndexHits<Relationship> hitsAfterRemove = relationshipIndex().get("time", value);
Assert.assertEquals("not found in index results", false, hitsAfterRemove.hasNext());
}
private Index<Node> nodeIndex() {
return graphDb.index().forNodes(NODE_INDEX_NAME);
}
private RelationshipIndex relationshipIndex() {
return graphDb.index().forRelationships(REL_INDEX_NAME);
}
@Test
public void testNodeIndexIsListed() {
nodeIndex().add(node(), "name", "test");
Assert.assertTrue("node index name listed", Arrays.asList(graphDb.index().nodeIndexNames()).contains(NODE_INDEX_NAME));
}
@Test
public void testRelationshipIndexIsListed() {
relationshipIndex().add(relationship(), "name", "test");
Assert.assertTrue("relationship index name listed", Arrays.asList(graphDb.index().relationshipIndexNames()).contains(REL_INDEX_NAME));
}
}

View File

@@ -0,0 +1,71 @@
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;
import java.util.Iterator;
public class RestTestBase {
protected GraphDatabaseService graphDb;
private static final String HOSTNAME = "localhost";
private static final int PORT = 7474;
private static LocalTestServer neoServer = new LocalTestServer(HOSTNAME,PORT).withPropertiesFile("test-db.properties");
private static final String SERVER_ROOT_URI = "http://" + HOSTNAME + ":" + PORT + "/db/data/";
private static final String SERVER_CLEANDB_URI = "http://" + HOSTNAME + ":" + PORT + "/cleandb/secret-key";
@BeforeClass
public static void startDb() throws Exception {
BasicConfigurator.configure();
neoServer.start();
}
@Before
public void setUp() throws URISyntaxException {
cleanDb();
graphDb = new RestGraphDatabase(new URI(SERVER_ROOT_URI));
}
private void cleanDb() {
neoServer.cleanDb();
}
@After
public void tearDown() throws Exception {
graphDb.shutdown();
}
@AfterClass
public static void shutdownDb() {
neoServer.stop();
}
protected Relationship relationship() {
Iterator<Relationship> it = node().getRelationships(Direction.OUTGOING).iterator();
if (it.hasNext()) return it.next();
return node().createRelationshipTo(graphDb.createNode(), Type.TEST);
}
protected Node node() {
return graphDb.getReferenceNode();
}
}

View File

@@ -0,0 +1,21 @@
package org.neo4j.rest.graphdb;
import org.junit.Assert;
import org.junit.Test;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser;
public class RestTraversalExecutionTest extends RestTestBase {
@Test
public void testTraverseToNeighbour() {
final Relationship rel = relationship();
final TraversalDescription traversalDescription = RestTraversal.description().maxDepth(1).breadthFirst();
System.out.println("traversalDescription = " + traversalDescription);
final Traverser traverser = traversalDescription.traverse(rel.getStartNode());
final Iterable<Node> nodes = traverser.nodes();
Assert.assertEquals(rel.getEndNode(), nodes.iterator().next());
}
}

View File

@@ -0,0 +1,111 @@
package org.neo4j.rest.graphdb;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.kernel.Uniqueness;
import java.util.Map;
/**
* @author Michael Hunger
* @since 03.02.11
*/
public class RestTraversalTest {
private RestTraversal traversalDescription;
@Before
public void setUp() throws Exception {
traversalDescription = (RestTraversal) RestTraversal.description();
}
@Test
public void testUniqueness() throws Exception {
traversalDescription.uniqueness(Uniqueness.NODE_PATH);
Assert.assertEquals("node path", getPostData("uniqueness"));
}
@Test
public void testUniquenessWithValue() throws Exception {
traversalDescription.uniqueness(Uniqueness.NODE_PATH,"test");
String param = "uniqueness";
final Map uniquenessMap = (Map) getPostData(param);
Assert.assertEquals("node path", uniquenessMap.get("name"));
Assert.assertEquals("test", uniquenessMap.get("value"));
}
private Object getPostData(String param) {
return traversalDescription.getPostData().get(param);
}
@Test
public void testPruneScript() throws Exception {
traversalDescription.prune(RestTraversalDescription.ScriptLanguage.JAVASCRIPT, "return true;");
Map pruneEvaluator= (Map) getPostData("prune evaluator");
Assert.assertEquals("javascript", pruneEvaluator.get("language"));
Assert.assertEquals("return true;", pruneEvaluator.get("body"));
}
@Test
public void testFilterScript() throws Exception {
traversalDescription.filter(RestTraversalDescription.ScriptLanguage.JAVASCRIPT, "return true;");
Map pruneEvaluator= (Map) getPostData("return filter");
Assert.assertEquals("javascript", pruneEvaluator.get("language"));
Assert.assertEquals("return true;", pruneEvaluator.get("body"));
}
@Test
public void testEvaluator() throws Exception {
}
@Test
public void testPrune() throws Exception {
}
@Test
public void testFilter() throws Exception {
}
@Test
public void testMaxDepth() throws Exception {
}
@Test
public void testOrder() throws Exception {
}
@Test
public void testDepthFirst() throws Exception {
}
@Test
public void testBreadthFirst() throws Exception {
}
@Test
public void testRelationships() throws Exception {
}
@Test
public void testRelationshipsAndDirection() throws Exception {
}
@Test
public void testExpand() throws Exception {
}
@Test
public void testComplexTraversal() throws Exception {
}
}

View File

@@ -0,0 +1,11 @@
package org.neo4j.rest.graphdb;
import org.neo4j.graphdb.RelationshipType;
/**
* @author mh
* @since 24.01.11
*/
enum Type implements RelationshipType {
TEST
}

View File

@@ -0,0 +1,26 @@
log4j.rootLogger=WARN, stdout, R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Print the date in ISO 8601 format
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=target/application.log
log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
log4j.category.org.springframework=WARN
#log4j.category.org.springframework.data.graph.neo4j.support.SubReferenceNodeTypeStrategy=DEBUG
#log4j.category.org.springframework.data.graph.neo4j.fieldaccess=DEBUG
#log4j.category.org.springframework.data=TRACE
#log4j.category.org.springframework.data.support=TRACE
#log4j.category.org.springframework.persistence=TRACE
#log4j.category.org.springframework.data.graph.neo4j.support=DEBUG

View File

@@ -0,0 +1 @@
org.neo4j.server.database.location=target/test-db