added rest-wrapper
This commit is contained in:
1
pom.xml
1
pom.xml
@@ -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>
|
||||
|
||||
133
spring-data-neo4j-rest/pom.xml
Normal file
133
spring-data-neo4j-rest/pom.xml
Normal 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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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" ) );
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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" );
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
26
spring-data-neo4j-rest/src/test/resources/log4j.properties
Normal file
26
spring-data-neo4j-rest/src/test/resources/log4j.properties
Normal 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
|
||||
@@ -0,0 +1 @@
|
||||
org.neo4j.server.database.location=target/test-db
|
||||
Reference in New Issue
Block a user