├── .gitignore ├── README.md ├── Roadmap.md ├── pom.xml └── src ├── main └── java │ └── org │ └── neo4j │ ├── kernel │ └── RestConfig.java │ └── rest │ └── graphdb │ ├── AbstractRemoteDatabase.java │ ├── ExecutingRestRequest.java │ ├── GraphDatabaseFactory.java │ ├── PropertiesMap.java │ ├── RequestResult.java │ ├── RestAPI.java │ ├── RestGraphDatabase.java │ ├── RestRequest.java │ ├── RestResultException.java │ ├── UpdatableRestResult.java │ ├── batch │ ├── BatchCallback.java │ ├── BatchIterable.java │ ├── BatchRestAPI.java │ ├── RecordingRestRequest.java │ └── RestOperations.java │ ├── converter │ ├── RelationshipIterableConverter.java │ ├── RestEntityExtractor.java │ ├── RestIndexHitsConverter.java │ ├── RestResultConverter.java │ └── RestTableResultExtractor.java │ ├── entity │ ├── RestEntity.java │ ├── RestNode.java │ └── RestRelationship.java │ ├── index │ ├── IndexInfo.java │ ├── RestIndex.java │ ├── RestIndexManager.java │ ├── RestNodeIndex.java │ ├── RestRelationshipIndex.java │ ├── RetrievedIndexInfo.java │ └── SimpleIndexHits.java │ ├── query │ ├── QueryEngine.java │ ├── RestCypherQueryEngine.java │ └── RestGremlinQueryEngine.java │ ├── traversal │ ├── NodePath.java │ ├── RelationshipPath.java │ ├── RestDirection.java │ ├── RestPathParser.java │ ├── RestTraversal.java │ ├── RestTraversalDescription.java │ ├── RestTraverser.java │ └── SimplePath.java │ └── util │ ├── ArrayConverter.java │ ├── ConvertedResult.java │ ├── DefaultConverter.java │ ├── Handler.java │ ├── JsonHelper.java │ ├── QueryResult.java │ ├── QueryResultBuilder.java │ ├── ResultConverter.java │ └── TestHelper.java └── test ├── java └── org │ └── neo4j │ └── rest │ └── graphdb │ ├── BatchRestAPITest.java │ ├── IsRelationshipToNodeMatcher.java │ ├── LocalTestServer.java │ ├── MatrixDataGraph.java │ ├── MatrixDatabaseRestTest.java │ ├── MatrixDatabaseTest.java │ ├── Neo4jDatabaseCleaner.java │ ├── RecordingRestRequestTest.java │ ├── RelationshipHasMatcher.java │ ├── RestAPITest.java │ ├── RestCypherQueryEngineTest.java │ ├── RestEntityTest.java │ ├── RestGraphDbTest.java │ ├── RestGremlinQueryEngineTest.java │ ├── RestIndexTest.java │ ├── RestNodeTest.java │ ├── RestTestBase.java │ ├── RestTraversalExecutionTest.java │ ├── RestTraversalTest.java │ └── Type.java └── resources └── neo4j-server.properties /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.ipr 3 | *.iws 4 | *.iml 5 | *.zip 6 | target 7 | *.log 8 | tmp 9 | .idea 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository has been deprecated, it has moved to the Neo4j organization. 2 | [Neo4j Github Repositories](http://github.com/neo4j/neo4j-java-rest-binding) 3 | 4 | The Java binding for the Neo4j Server REST API wraps the REST calls behind the well known 5 | [GraphDatabaseService](http://api.neo4j.org/1.2/org/neo4j/graphdb/GraphDatabaseService.html) API. 6 | 7 | Currently supports: 8 | ___________________ 9 | * all the node and relationship operations 10 | * the new Index API 11 | * Basic Http Auth (Digest) 12 | * preliminary traversal support 13 | 14 | Open issues: 15 | ____________ 16 | * full traversal support 17 | * support for exposing server extensions - via an interface based proxy 18 | 19 | Usage: 20 | ------ 21 | 22 | Build it locally. Then use the maven / ivy dependency or copy the jar into your app. 23 | 24 | 25 | org.neo4j 26 | neo4j-rest-graphdb 27 | 0.1-SNAPSHOT 28 | 29 | 30 | GraphDatabaseService gds = new RestGraphDatabase(new URI("http://localhost:7474/db/data")); 31 | GraphDatabaseService gds = new RestGraphDatabase(new URI("http://localhost:7474/db/data"),username,password); 32 | 33 | 34 | 35 | 36 | 37 | 38 | **Please note: Transactions are not supported over this API.** 39 | 40 | Unit Test: 41 | ---------- 42 | to start tests you will need the https://github.com/jexp/neo4j-clean-remote-db-addon to cleanup the database while 43 | 44 | 45 | References / Community: 46 | ----------------------- 47 | 48 | * [Neo4j community site](http://neo4j.org) 49 | * [Neo4j REST API](http://components.neo4j.org/neo4j-server/snapshot/rest.html) 50 | * [Neo4j Wiki](http://wiki.neo4j.org) 51 | * [Neo4j Mailing List](https://lists.neo4j.org/mailman/listinfo/user) 52 | -------------------------------------------------------------------------------- /Roadmap.md: -------------------------------------------------------------------------------- 1 |  2 | - AbstractDatabase Class as Parent for RestGraphDatabase. RGD only holds implemented methods 3 | - Simplify the RestAPI e.g. drop RestIndexManager 4 | - Allow RestTraversal with other Params as FULLPATH 5 | - Allow compact Variant of RestAPI 6 | - Evaluator should not throw UOE, make it more intelligent 7 | - Support other Scriptlanguages (e.g. test with Ruby) 8 | - Implement a Rest URI Class (static description of the neo4j protocol) 9 | - Unique Nodes - get or create 10 | - Complete RestTraversalTests (empty tests at the moment) 11 | - support batch mode via batch-command 12 | - support gremlin, cypher plugins 13 | - support Traverser and Index-Paging 14 | - support arbitrary ServerPlugins and Unmanaged Extensions 15 | - support local caching 16 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.neo4j 5 | neo4j-rest-graphdb 6 | jar 7 | 0.2001-SNAPSHOT 8 | Rest GraphDatabaseService Wrapper 9 | 10 | UTF-8 11 | 1.6.1 12 | 1.4.1 13 | 1.4 14 | 0.8 15 | 1.1 16 | 17 | 18 | 19 | 20 | neo4j 21 | http://m2.neo4j.org 22 | 23 | 24 | Sun 25 | http://download.java.net/maven/2 26 | 27 | 28 | 29 | 30 | junit 31 | junit 32 | 4.8.2 33 | test 34 | 35 | 36 | org.neo4j 37 | neo4j-kernel 38 | ${neo4j.version} 39 | 40 | 41 | org.neo4j 42 | neo4j-kernel 43 | ${neo4j.version} 44 | test 45 | test-jar 46 | 47 | 48 | org.neo4j.app 49 | neo4j-server 50 | ${neo4j.version} 51 | test 52 | 53 | 54 | com.tinkerpop 55 | gremlin 56 | 57 | 58 | org.neo4j 59 | neo4j 60 | 61 | 62 | org.mortbay.jetty 63 | jetty 64 | 65 | 66 | com.sun.jersey 67 | jersey-server 68 | 69 | 70 | org.codehaus.jackson 71 | jackson-jaxrs 72 | 73 | 74 | org.codehaus.jackson 75 | jackson-mapper-asl 76 | 77 | 78 | de.huxhorn.lilith 79 | de.huxhorn.lilith.3rdparty.rrd4j 80 | 81 | 82 | com.sun.jersey.contribs 83 | jersey-multipart 84 | 85 | 86 | org.apache.felix 87 | org.apache.felix.main 88 | 89 | 90 | org.apache.felix 91 | org.apache.felix.fileinstall 92 | 93 | 94 | org.neo4j 95 | neo4j-shell 96 | 97 | 98 | 99 | 100 | org.mortbay.jetty 101 | jetty 102 | 6.1.25 103 | test 104 | 105 | 106 | org.neo4j.server.plugin 107 | neo4j-cypher-plugin 108 | ${neo4j.version} 109 | test 110 | 111 | 112 | org.neo4j.server.plugin 113 | neo4j-gremlin-plugin 114 | ${neo4j.version} 115 | test 116 | 117 | 118 | com.tinkerpop.blueprints 119 | blueprints-core 120 | ${blueprints.version} 121 | true 122 | test 123 | 124 | 125 | com.tinkerpop.blueprints 126 | blueprints-neo4j-graph 127 | ${blueprints.version} 128 | true 129 | test 130 | 131 | 132 | com.tinkerpop 133 | gremlin 134 | ${gremlin.version} 135 | true 136 | 137 | 138 | org.neo4j 139 | neo4j-lucene-index 140 | ${neo4j.version} 141 | 142 | 147 | 148 | 149 | org.codehaus.jackson 150 | jackson-jaxrs 151 | 1.6.1 152 | 153 | 154 | org.codehaus.jackson 155 | jackson-mapper-asl 156 | 1.6.1 157 | 158 | 159 | com.sun.jersey 160 | jersey-server 161 | ${jersey.version} 162 | test 163 | 164 | 165 | com.sun.jersey 166 | jersey-client 167 | ${jersey.version} 168 | 169 | 170 | 171 | 172 | 173 | maven-compiler-plugin 174 | 175 | 1.6 176 | 1.6 177 | 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-eclipse-plugin 182 | 2.8 183 | 184 | 1.5 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/kernel/RestConfig.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.kernel; 2 | 3 | import org.neo4j.graphdb.GraphDatabaseService; 4 | import org.neo4j.kernel.impl.core.*; 5 | import org.neo4j.kernel.impl.nioneo.store.FileSystemAbstraction; 6 | import org.neo4j.kernel.impl.nioneo.store.StoreId; 7 | import org.neo4j.kernel.impl.transaction.LockManager; 8 | import org.neo4j.kernel.impl.transaction.TxModule; 9 | import org.neo4j.kernel.impl.transaction.xaframework.TxIdGenerator; 10 | import org.neo4j.rest.graphdb.RestGraphDatabase; 11 | 12 | import javax.transaction.*; 13 | import javax.transaction.xa.XAResource; 14 | import java.util.Collections; 15 | import java.util.Map; 16 | 17 | /** 18 | * @author mh 19 | * @since 23.02.11 20 | */ 21 | public class RestConfig extends Config { 22 | 23 | private RestConfig(GraphDatabaseService graphDb, String storeDir, StoreId storeId, Map inputParams, KernelPanicEventGenerator kpe, TxModule txModule, LockManager lockManager, LockReleaser lockReleaser, IdGeneratorFactory idGeneratorFactory, TxEventSyncHookFactory txSyncHookFactory, RelationshipTypeCreator relTypeCreator, TxIdGenerator txIdGenerator, LastCommittedTxIdSetter lastCommittedTxIdSetter, FileSystemAbstraction fileSystem) { 24 | super(graphDb, storeDir, storeId, inputParams, kpe, txModule, lockManager, lockReleaser, idGeneratorFactory, txSyncHookFactory, relTypeCreator, txIdGenerator, lastCommittedTxIdSetter, fileSystem); 25 | } 26 | 27 | public RestConfig(RestGraphDatabase restGraphDatabase) { 28 | super(restGraphDatabase, restGraphDatabase.getStoreDir(), null, 29 | Collections.emptyMap(),null, 30 | new TxModule(true,null){ 31 | @Override 32 | public TransactionManager getTxManager() { 33 | return new NullTransactionManager(); 34 | } 35 | }, 36 | null,null, 37 | null,null,null,null,null, 38 | null); 39 | } 40 | 41 | private static class NullTransactionManager implements TransactionManager { 42 | private static final Transaction TRANSACTION = new Transaction() { 43 | @Override 44 | public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException, SystemException { 45 | 46 | } 47 | 48 | @Override 49 | public boolean delistResource(XAResource xaResource, int i) throws IllegalStateException, SystemException { 50 | return false; 51 | } 52 | 53 | @Override 54 | public boolean enlistResource(XAResource xaResource) throws IllegalStateException, RollbackException, SystemException { 55 | return false; 56 | } 57 | 58 | @Override 59 | public int getStatus() throws SystemException { 60 | return Status.STATUS_NO_TRANSACTION; 61 | } 62 | 63 | @Override 64 | public void registerSynchronization(Synchronization synchronization) throws IllegalStateException, RollbackException, SystemException { 65 | 66 | } 67 | 68 | @Override 69 | public void rollback() throws IllegalStateException, SystemException { 70 | 71 | } 72 | 73 | @Override 74 | public void setRollbackOnly() throws IllegalStateException, SystemException { 75 | 76 | } 77 | }; 78 | 79 | @Override 80 | public void begin() throws NotSupportedException, SystemException { 81 | 82 | } 83 | 84 | @Override 85 | public void commit() throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException, RollbackException, SecurityException, SystemException { 86 | 87 | } 88 | 89 | @Override 90 | public int getStatus() throws SystemException { 91 | return 0; 92 | } 93 | 94 | @Override 95 | public Transaction getTransaction() throws SystemException { 96 | return TRANSACTION; 97 | } 98 | 99 | @Override 100 | public void resume(Transaction transaction) throws IllegalStateException, InvalidTransactionException, SystemException { 101 | 102 | } 103 | 104 | @Override 105 | public void rollback() throws IllegalStateException, SecurityException, SystemException { 106 | 107 | } 108 | 109 | @Override 110 | public void setRollbackOnly() throws IllegalStateException, SystemException { 111 | 112 | } 113 | 114 | @Override 115 | public void setTransactionTimeout(int i) throws SystemException { 116 | 117 | } 118 | 119 | @Override 120 | public Transaction suspend() throws SystemException { 121 | return TRANSACTION; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/AbstractRemoteDatabase.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import java.io.Serializable; 4 | import java.util.Map; 5 | 6 | import org.neo4j.graphdb.Node; 7 | import org.neo4j.graphdb.RelationshipType; 8 | import org.neo4j.graphdb.Transaction; 9 | import org.neo4j.graphdb.event.KernelEventHandler; 10 | import org.neo4j.graphdb.event.TransactionEventHandler; 11 | import org.neo4j.kernel.AbstractGraphDatabase; 12 | 13 | abstract class AbstractRemoteDatabase extends AbstractGraphDatabase { 14 | public Transaction beginTx() { 15 | return new Transaction() { 16 | public void success() { 17 | } 18 | 19 | public void finish() { 20 | 21 | } 22 | 23 | public void failure() { 24 | } 25 | }; 26 | } 27 | 28 | public TransactionEventHandler registerTransactionEventHandler( TransactionEventHandler tTransactionEventHandler ) { 29 | throw new UnsupportedOperationException(); 30 | } 31 | 32 | public TransactionEventHandler unregisterTransactionEventHandler( TransactionEventHandler tTransactionEventHandler ) { 33 | throw new UnsupportedOperationException(); 34 | } 35 | 36 | public KernelEventHandler registerKernelEventHandler( KernelEventHandler kernelEventHandler ) { 37 | throw new UnsupportedOperationException(); 38 | } 39 | 40 | public KernelEventHandler unregisterKernelEventHandler( KernelEventHandler kernelEventHandler ) { 41 | throw new UnsupportedOperationException(); 42 | } 43 | 44 | public boolean enableRemoteShell() { 45 | throw new UnsupportedOperationException(); 46 | } 47 | 48 | public boolean enableRemoteShell( Map config ) { 49 | throw new UnsupportedOperationException(); 50 | } 51 | 52 | public Iterable getAllNodes() { 53 | throw new UnsupportedOperationException(); 54 | } 55 | 56 | public Iterable getRelationshipTypes() { 57 | throw new UnsupportedOperationException(); 58 | } 59 | 60 | @Override 61 | public T getManagementBean(Class type) { 62 | return null; 63 | } 64 | 65 | public void shutdown() { 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/ExecutingRestRequest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import com.sun.jersey.api.client.Client; 4 | import com.sun.jersey.api.client.ClientResponse; 5 | import com.sun.jersey.api.client.WebResource; 6 | import com.sun.jersey.api.client.WebResource.Builder; 7 | import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; 8 | 9 | import javax.ws.rs.core.MediaType; 10 | 11 | import org.neo4j.rest.graphdb.RequestResult; 12 | import org.neo4j.rest.graphdb.util.JsonHelper; 13 | 14 | 15 | import java.io.UnsupportedEncodingException; 16 | import java.net.URI; 17 | import java.net.URISyntaxException; 18 | import java.net.URLEncoder; 19 | 20 | import java.util.concurrent.TimeUnit; 21 | 22 | public class ExecutingRestRequest implements RestRequest { 23 | 24 | public static final int CONNECT_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(30); 25 | public static final int READ_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(30); 26 | private final String baseUri; 27 | private final Client client; 28 | 29 | public ExecutingRestRequest( String baseUri ) { 30 | this( baseUri, null, null ); 31 | } 32 | 33 | public ExecutingRestRequest( String baseUri, String username, String password ) { 34 | this.baseUri = uriWithoutSlash( baseUri ); 35 | client = createClient(); 36 | addAuthFilter(username, password); 37 | 38 | } 39 | 40 | protected void addAuthFilter(String username, String password) { 41 | if (username == null) return; 42 | client.addFilter( new HTTPBasicAuthFilter( username, password ) ); 43 | } 44 | 45 | protected Client createClient() { 46 | Client client = Client.create(); 47 | 48 | client.setConnectTimeout(CONNECT_TIMEOUT); 49 | client.setReadTimeout(READ_TIMEOUT); 50 | 51 | return client; 52 | } 53 | 54 | private ExecutingRestRequest( String uri, Client client ) { 55 | this.baseUri = uriWithoutSlash( uri ); 56 | this.client = client; 57 | } 58 | 59 | protected String uriWithoutSlash( String uri ) { 60 | String uriString = uri; 61 | return (uriString.endsWith( "/" ) ? uriString.substring( 0, uriString.length() - 1 ) : uri); 62 | } 63 | 64 | public static String encode( Object value ) { 65 | if ( value == null ) return ""; 66 | try { 67 | return URLEncoder.encode( value.toString(), "utf-8" ).replaceAll( "\\+", "%20" ); 68 | } catch ( UnsupportedEncodingException e ) { 69 | throw new RuntimeException( e ); 70 | } 71 | } 72 | 73 | 74 | private Builder builder( String path ) { 75 | WebResource resource = client.resource( uri( pathOrAbsolute( path ) ) ); 76 | return resource.accept( MediaType.APPLICATION_JSON_TYPE ); 77 | } 78 | 79 | private String pathOrAbsolute( String path ) { 80 | if ( path.startsWith( "http://" ) ) return path; 81 | return baseUri + "/" + path; 82 | } 83 | 84 | 85 | @Override 86 | public RequestResult get( String path ) { 87 | return RequestResult.extractFrom(builder(path).get(ClientResponse.class)); 88 | } 89 | 90 | 91 | @Override 92 | public RequestResult get( String path, Object data ) { 93 | Builder builder = builder(path); 94 | if ( data != null ) { 95 | builder = builder.entity( JsonHelper.createJsonFrom( data ), MediaType.APPLICATION_JSON_TYPE ); 96 | } 97 | return RequestResult.extractFrom(builder.get(ClientResponse.class)); 98 | } 99 | 100 | 101 | @Override 102 | public RequestResult delete(String path) { 103 | return RequestResult.extractFrom(builder(path).delete(ClientResponse.class)); 104 | } 105 | 106 | 107 | @Override 108 | public RequestResult post( String path, Object data ) { 109 | Builder builder = builder( path ); 110 | if ( data != null ) { 111 | builder = builder.entity( JsonHelper.createJsonFrom( data ), MediaType.APPLICATION_JSON_TYPE ); 112 | } 113 | return RequestResult.extractFrom(builder.post(ClientResponse.class)); 114 | } 115 | 116 | 117 | @Override 118 | public RequestResult put( String path, Object data ) { 119 | Builder builder = builder( path ); 120 | if ( data != null ) { 121 | builder = builder.entity( JsonHelper.createJsonFrom( data ), MediaType.APPLICATION_JSON_TYPE ); 122 | } 123 | final ClientResponse response = builder.put(ClientResponse.class); 124 | response.close(); 125 | return RequestResult.extractFrom(builder.put(ClientResponse.class)); 126 | } 127 | 128 | 129 | 130 | @Override 131 | public RestRequest with( String uri ) { 132 | return new ExecutingRestRequest( uri , client ); 133 | } 134 | 135 | private URI uri( String uri ) { 136 | try { 137 | return new URI( uri ); 138 | } catch ( URISyntaxException e ) { 139 | throw new RuntimeException( e ); 140 | } 141 | } 142 | 143 | 144 | @Override 145 | public String getUri() { 146 | return baseUri; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/GraphDatabaseFactory.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.neo4j.graphdb.GraphDatabaseService; 4 | import org.neo4j.kernel.EmbeddedGraphDatabase; 5 | 6 | import java.io.File; 7 | import java.net.URI; 8 | import java.net.URISyntaxException; 9 | 10 | /** 11 | * @author mh 12 | * @since 25.01.11 13 | */ 14 | public class GraphDatabaseFactory { 15 | public static GraphDatabaseService databaseFor(String url) { 16 | return databaseFor( url, null,null ); 17 | } 18 | 19 | public static GraphDatabaseService databaseFor(String url, String username, String password) { 20 | if (url.startsWith( "http://" ) || url.startsWith( "https://" )) { 21 | return new RestGraphDatabase( url , username,password ); 22 | } 23 | String path=url; 24 | if (url.startsWith( "file:" )) { 25 | path = toURI( url ).getPath(); 26 | } 27 | File file = new File( path ); 28 | if (!file.isDirectory()) file=file.getParentFile(); 29 | return new EmbeddedGraphDatabase( file.getAbsolutePath() ); 30 | } 31 | 32 | private static URI toURI( String uri ) { 33 | try { 34 | return new URI(uri); 35 | } catch ( URISyntaxException e ) { 36 | throw new RuntimeException( "Error using URI "+uri, e); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/PropertiesMap.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | /** 4 | * @author mh 5 | * @since 13.12.10 6 | */ 7 | 8 | import org.neo4j.graphdb.PropertyContainer; 9 | 10 | import java.lang.reflect.Array; 11 | import java.util.*; 12 | 13 | public class PropertiesMap { 14 | 15 | private final Map values = new HashMap(); 16 | 17 | public PropertiesMap( PropertyContainer container ) { 18 | for ( String key : container.getPropertyKeys() ) { 19 | values.put( key, container.getProperty( key ) ); 20 | } 21 | } 22 | 23 | public PropertiesMap( Map map ) { 24 | for ( Map.Entry entry : map.entrySet() ) { 25 | values.put( entry.getKey(), toInternalType( entry.getValue() ) ); 26 | } 27 | } 28 | 29 | public Object getValue( String key ) { 30 | return values.get( key ); 31 | } 32 | 33 | public Map serialize() { 34 | // TODO Nice with sorted, but TreeMap the best? 35 | Map result = new TreeMap(); 36 | for ( Map.Entry entry : values.entrySet() ) { 37 | result.put( entry.getKey(), toSerializedType( entry.getValue() ) ); 38 | } 39 | return result; 40 | } 41 | 42 | void storeTo( PropertyContainer container ) { 43 | for ( Map.Entry entry : values.entrySet() ) { 44 | container.setProperty( entry.getKey(), entry.getValue() ); 45 | } 46 | } 47 | 48 | @SuppressWarnings("unchecked") 49 | private static Object toInternalType( Object value ) { 50 | if ( value instanceof List ) { 51 | List list = (List) value; 52 | if ( list.isEmpty() ) { 53 | return new byte[0]; 54 | } else { 55 | Object first = list.get( 0 ); 56 | if ( first instanceof String ) { 57 | return stringArray( list ); 58 | } else if ( first instanceof Number ) { 59 | return numberArray( list ); 60 | } else if ( first instanceof Boolean ) { 61 | return booleanArray( list ); 62 | } else { 63 | throw new RuntimeException( "Unsupported array type " + first.getClass() + 64 | ". Supported array types are arrays of all java primitives (" + 65 | "byte[], char[], short[], int[], long[], float[], double[]) " + 66 | "and String[]" ); 67 | } 68 | } 69 | } else { 70 | return assertSupportedPropertyValue( value ); 71 | } 72 | } 73 | 74 | public static Object assertSupportedPropertyValue( Object value ) { 75 | if ( value == null ) { 76 | throw new RuntimeException( "null value not supported" ); 77 | } 78 | final Class type = value.getClass(); 79 | if (isSupportedType(type) || type.isArray() && isSupportedType(type.getComponentType())) { 80 | return value; 81 | } 82 | throw new RuntimeException( "Unsupported value type " + type + "." + 83 | " Supported value types are all java primitives (byte, char, short, int, " + 84 | "long, float, double) and String, as well as arrays of all those types" ); 85 | } 86 | 87 | private static boolean isSupportedType(Class type) { 88 | return type.isPrimitive() || String.class.isAssignableFrom(type) || Number.class.isAssignableFrom(type) || Boolean.class.isAssignableFrom(type); 89 | } 90 | 91 | private static Boolean[] booleanArray( List list ) { 92 | return list.toArray( new Boolean[list.size()] ); 93 | } 94 | 95 | private static Number[] numberArray( List numbers ) { 96 | Number[] internal = new Number[numbers.size()]; 97 | for ( int i = 0; i < internal.length; i++ ) { 98 | Number number = numbers.get( i ); 99 | if ( number instanceof Float || number instanceof Double ) { 100 | number = number.doubleValue(); 101 | } else { 102 | number = number.longValue(); 103 | } 104 | internal[i] = number; 105 | } 106 | final Number[] result; 107 | if ( internal[0] instanceof Double ) { 108 | result = new Double[internal.length]; 109 | } else { 110 | result = new Long[internal.length]; 111 | } 112 | System.arraycopy( internal, 0, result, 0, internal.length ); 113 | return result; 114 | } 115 | 116 | private static String[] stringArray( List strings ) { 117 | return strings.toArray( new String[strings.size()] ); 118 | } 119 | 120 | private Object toSerializedType( Object value ) { 121 | if ( value.getClass().isArray() ) { 122 | if ( value.getClass().getComponentType().isPrimitive() ) { 123 | int size = Array.getLength( value ); 124 | List result = new ArrayList(); 125 | for ( int i = 0; i < size; i++ ) { 126 | result.add( Array.get( value, i ) ); 127 | } 128 | return result; 129 | } else { 130 | return Arrays.asList( (Object[]) value ); 131 | } 132 | } else { 133 | return value; 134 | } 135 | } 136 | 137 | public boolean isEmpty() { 138 | return values.isEmpty(); 139 | } 140 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/RequestResult.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.neo4j.rest.graphdb; 17 | 18 | import com.sun.jersey.api.client.ClientResponse; 19 | 20 | import org.neo4j.rest.graphdb.batch.RestOperations.RestOperation; 21 | import org.neo4j.rest.graphdb.util.JsonHelper; 22 | 23 | import javax.ws.rs.core.Response; 24 | import javax.ws.rs.core.Response.StatusType; 25 | import java.net.URI; 26 | import java.util.Map; 27 | 28 | 29 | /** 30 | * @author Klemens Burchardi 31 | * @since 03.08.11 32 | */ 33 | public class RequestResult { 34 | private final int status; 35 | private final String location; 36 | private final String entity; 37 | private long batchId; 38 | private boolean batchResult = false; 39 | 40 | 41 | RequestResult(int status, String location, String entity) { 42 | this.status = status; 43 | this.location = location; 44 | this.entity = entity; 45 | } 46 | 47 | RequestResult(long batchId) { 48 | this(0,null,""); 49 | this.batchResult = true; 50 | this.batchId = batchId; 51 | } 52 | 53 | public static RequestResult batchResult(RestOperation restOperation){ 54 | return new RequestResult(restOperation.getBatchId()); 55 | } 56 | 57 | public static RequestResult extractFrom(ClientResponse clientResponse) { 58 | final int status = clientResponse.getStatus(); 59 | final URI location = clientResponse.getLocation(); 60 | final String data = status != Response.Status.NO_CONTENT.getStatusCode() ? clientResponse.getEntity(String.class) : null; 61 | clientResponse.close(); 62 | return new RequestResult(status, uriString(location), data); 63 | } 64 | 65 | private static String uriString(URI location) { 66 | return location==null ? null : location.toString(); 67 | } 68 | 69 | 70 | public int getStatus() { 71 | return status; 72 | } 73 | 74 | public String getLocation() { 75 | return location; 76 | } 77 | 78 | public String getEntity() { 79 | return entity; 80 | } 81 | 82 | public Object toEntity() { 83 | return JsonHelper.jsonToSingleValue( getEntity() ); 84 | } 85 | 86 | public Map toMap() { 87 | final String json = getEntity(); 88 | return JsonHelper.jsonToMap(json); 89 | } 90 | 91 | public boolean statusIs( StatusType status ) { 92 | return getStatus() == status.getStatusCode(); 93 | } 94 | 95 | public boolean statusOtherThan( StatusType status ) { 96 | return !statusIs(status ); 97 | } 98 | 99 | public long getBatchId() { 100 | return batchId; 101 | } 102 | 103 | public boolean isBatchResult(){ 104 | return batchResult; 105 | } 106 | 107 | public static RequestResult extractFrom(Map batchResult) { 108 | return new RequestResult(200, (String) batchResult.get("location"),JsonHelper.createJsonFrom(batchResult.get("body"))); 109 | } 110 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/RestGraphDatabase.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | 4 | import org.neo4j.graphdb.*; 5 | import org.neo4j.kernel.Config; 6 | import org.neo4j.kernel.RestConfig; 7 | import org.neo4j.rest.graphdb.index.RestIndexManager; 8 | import java.net.URI; 9 | 10 | 11 | public class RestGraphDatabase extends AbstractRemoteDatabase { 12 | private RestAPI restAPI; 13 | 14 | 15 | public RestGraphDatabase( RestAPI api){ 16 | this.restAPI = api; 17 | } 18 | 19 | public RestGraphDatabase( String uri ) { 20 | this( new ExecutingRestRequest( uri )); 21 | } 22 | 23 | public RestGraphDatabase( String uri, String user, String password ) { 24 | this(new ExecutingRestRequest( uri, user, password )); 25 | } 26 | 27 | public RestGraphDatabase( RestRequest restRequest){ 28 | this(new RestAPI(restRequest)); 29 | } 30 | 31 | 32 | public RestAPI getRestAPI(){ 33 | return this.restAPI; 34 | } 35 | 36 | 37 | public RestIndexManager index() { 38 | return this.restAPI.index(); 39 | } 40 | 41 | public Node createNode() { 42 | return this.restAPI.createNode(null); 43 | } 44 | 45 | public Node getNodeById( long id ) { 46 | return this.restAPI.getNodeById(id); 47 | } 48 | 49 | public Node getReferenceNode() { 50 | return this.restAPI.getReferenceNode(); 51 | } 52 | 53 | public Relationship getRelationshipById( long id ) { 54 | return this.restAPI.getRelationshipById(id); 55 | } 56 | 57 | 58 | public RestRequest getRestRequest() { 59 | return this.restAPI.getRestRequest(); 60 | } 61 | 62 | public long getPropertyRefetchTimeInMillis() { 63 | return this.restAPI.getPropertyRefetchTimeInMillis(); 64 | } 65 | @Override 66 | public String getStoreDir() { 67 | return this.restAPI.getStoreDir(); 68 | } 69 | 70 | @Override 71 | public Config getConfig() { 72 | return new RestConfig(this); 73 | } 74 | 75 | @Override 76 | public boolean isReadOnly() { 77 | return false; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/RestRequest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import java.net.URI; 4 | 5 | public interface RestRequest { 6 | 7 | RequestResult get(String path); 8 | 9 | RequestResult get(String path, Object data); 10 | 11 | RequestResult delete(String path); 12 | 13 | RequestResult post(String path, Object data); 14 | 15 | RequestResult put(String path, Object data); 16 | 17 | RestRequest with(String uri); 18 | 19 | String getUri(); 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/RestResultException.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | public class RestResultException extends RuntimeException { 7 | public RestResultException(Object result) { 8 | super(format(toMap(result))); 9 | } 10 | 11 | private static String format(Map result) { 12 | if (result==null) return "Unknown Exception"; 13 | StringBuilder sb = new StringBuilder(); 14 | sb.append(result.get("message")).append(" at\n"); 15 | sb.append(result.get("exception")).append("\n"); 16 | List stacktrace = (List) result.get("stacktrace"); 17 | if (stacktrace != null) { 18 | for (String line : stacktrace) { 19 | sb.append(" ").append(line).append("\n"); 20 | } 21 | } 22 | return sb.toString(); 23 | } 24 | 25 | public static boolean isExceptionResult(Object result) { 26 | final Map map = toMap(result); 27 | return map!=null && map.containsKey("exception") && map.containsKey("message"); 28 | } 29 | 30 | private static Map toMap(Object result) { 31 | if (!(result instanceof Map)) return null; 32 | return (Map) result; 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/UpdatableRestResult.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | /** 4 | * @author mh 5 | * @since 21.09.11 6 | */ 7 | public interface UpdatableRestResult { 8 | void updateFrom(T newValue, RestAPI restApi); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/batch/BatchCallback.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.batch; 2 | 3 | import org.neo4j.rest.graphdb.RestAPI; 4 | 5 | public interface BatchCallback { 6 | T recordBatch(RestAPI batchRestApi); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/batch/BatchIterable.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.batch; 2 | 3 | import java.util.Iterator; 4 | 5 | import org.neo4j.rest.graphdb.RequestResult; 6 | import org.neo4j.rest.graphdb.RestAPI; 7 | import org.neo4j.rest.graphdb.UpdatableRestResult; 8 | 9 | /** 10 | * @author mh 11 | * @since 21.09.11 12 | */ 13 | public class BatchIterable implements Iterable, UpdatableRestResult> { 14 | private final long batchId; 15 | private RestAPI restApi; 16 | private Iterable data; 17 | 18 | public BatchIterable(RequestResult requestResult) { 19 | batchId = requestResult.getBatchId(); 20 | } 21 | 22 | @Override 23 | public void updateFrom(Iterable newValue, RestAPI restApi) { 24 | this.data = newValue; 25 | this.restApi = restApi; 26 | } 27 | 28 | @Override 29 | public Iterator iterator() { 30 | return data.iterator(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/batch/BatchRestAPI.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.batch; 2 | 3 | 4 | import org.neo4j.graphdb.Node; 5 | import org.neo4j.graphdb.PropertyContainer; 6 | import org.neo4j.graphdb.Relationship; 7 | import org.neo4j.graphdb.RelationshipType; 8 | import org.neo4j.graphdb.index.IndexHits; 9 | import org.neo4j.helpers.collection.MapUtil; 10 | import org.neo4j.rest.graphdb.ExecutingRestRequest; 11 | import org.neo4j.rest.graphdb.RequestResult; 12 | import org.neo4j.rest.graphdb.RestAPI; 13 | import org.neo4j.rest.graphdb.RestRequest; 14 | import org.neo4j.rest.graphdb.converter.RelationshipIterableConverter; 15 | import org.neo4j.rest.graphdb.converter.RestEntityExtractor; 16 | import org.neo4j.rest.graphdb.converter.RestIndexHitsConverter; 17 | import org.neo4j.rest.graphdb.entity.RestNode; 18 | import org.neo4j.rest.graphdb.entity.RestRelationship; 19 | import org.neo4j.rest.graphdb.index.IndexInfo; 20 | import org.neo4j.rest.graphdb.index.SimpleIndexHits; 21 | 22 | import java.util.Map; 23 | 24 | public class BatchRestAPI extends RestAPI { 25 | 26 | public BatchRestAPI( String uri ) { 27 | super(uri); 28 | } 29 | 30 | public BatchRestAPI( String uri, String user, String password ) { 31 | super(uri, user, password); 32 | } 33 | 34 | public BatchRestAPI(String uri, ExecutingRestRequest executingRestRequest){ 35 | super(uri); 36 | this.restRequest = new RecordingRestRequest(executingRestRequest, new RestOperations()); 37 | } 38 | 39 | @Override 40 | protected RestRequest createRestRequest( String uri, String user, String password){ 41 | return new RecordingRestRequest(new ExecutingRestRequest(uri, user, password),new RestOperations()); 42 | } 43 | 44 | 45 | @Override 46 | public Node createRestNode(RequestResult requestResult) { 47 | final long batchId = requestResult.getBatchId(); 48 | Node node = new RestNode("{"+batchId+"}", this); 49 | (getRecordingRequest()).getOperations().addToRestOperation(batchId, node, new RestEntityExtractor(this)); 50 | return node; 51 | } 52 | 53 | @Override 54 | public RestRelationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props) { 55 | final RestRequest restRequest = ((RestNode)startNode).getRestRequest(); 56 | Map data = MapUtil.map("to", ((RestNode)endNode).getUri(), "type", type.name()); 57 | if (props!=null && props.size()>0) { 58 | data.put("data",props); 59 | } 60 | //RequestResult requestResult = restRequest.post(restRequest.getUri()+"/relationships", data); 61 | RequestResult requestResult = restRequest.post( "relationships", data); 62 | return createRestRelationship(requestResult, startNode); 63 | } 64 | 65 | @Override 66 | public RestRelationship createRestRelationship(RequestResult requestResult, Node startNode) { 67 | final long batchId = requestResult.getBatchId(); 68 | RestRelationship relationship = new RestRelationship("{"+batchId+"}", this); 69 | getRecordingRequest().getOperations().addToRestOperation(batchId, relationship, new RestEntityExtractor(this)); 70 | return relationship; 71 | } 72 | 73 | private RecordingRestRequest getRecordingRequest() { 74 | return (RecordingRestRequest)this.restRequest; 75 | } 76 | 77 | public RestOperations getRecordedOperations(){ 78 | return (getRecordingRequest()).getOperations(); 79 | } 80 | 81 | public void stop() { 82 | getRecordingRequest().stop(); 83 | } 84 | 85 | @SuppressWarnings("unchecked") 86 | public Iterable wrapRelationships( RequestResult requestResult ) { 87 | final long batchId = requestResult.getBatchId(); 88 | final BatchIterable result = new BatchIterable(requestResult); 89 | getRecordingRequest().getOperations().addToRestOperation(batchId, result, new RelationshipIterableConverter(this)); 90 | return result; 91 | } 92 | 93 | public IndexHits queryIndex(String indexPath, Class entityType) { 94 | RequestResult response = restRequest.get(indexPath); 95 | final long batchId = response.getBatchId(); 96 | final SimpleIndexHits result = new SimpleIndexHits(batchId, entityType, this); 97 | getRecordingRequest().getOperations().addToRestOperation(batchId, result, new RestIndexHitsConverter(this,entityType)); 98 | return result; 99 | } 100 | 101 | public IndexInfo indexInfo(final String indexType) { 102 | return new BatchIndexInfo(); 103 | } 104 | 105 | private static class BatchIndexInfo implements IndexInfo { 106 | 107 | @Override 108 | public boolean checkConfig(String indexName, Map config) { 109 | return true; 110 | } 111 | 112 | @Override 113 | public String[] indexNames() { 114 | return new String[0]; 115 | } 116 | 117 | @Override 118 | public boolean exists(String indexName) { 119 | return true; 120 | } 121 | 122 | @Override 123 | public Map getConfig(String name) { 124 | return null; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/batch/RecordingRestRequest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.batch; 2 | 3 | 4 | import java.io.UnsupportedEncodingException; 5 | import java.net.URLEncoder; 6 | import java.util.Map; 7 | 8 | import javax.ws.rs.core.MediaType; 9 | 10 | import org.neo4j.rest.graphdb.RequestResult; 11 | import org.neo4j.rest.graphdb.RestRequest; 12 | import org.neo4j.rest.graphdb.batch.RestOperations.RestOperation; 13 | import org.neo4j.rest.graphdb.batch.RestOperations.RestOperation.Methods; 14 | 15 | 16 | 17 | public class RecordingRestRequest implements RestRequest { 18 | 19 | private final String baseUri; 20 | private MediaType contentType; 21 | private MediaType acceptHeader; 22 | private RestRequest restRequest; 23 | private RestOperations operations; 24 | private boolean stop; 25 | 26 | 27 | public RestOperations getOperations() { 28 | return operations; 29 | } 30 | 31 | public RecordingRestRequest( RestRequest restRequest) { 32 | this( restRequest.getUri(), MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_JSON_TYPE ); 33 | this.restRequest = restRequest; 34 | } 35 | 36 | public RecordingRestRequest( RestRequest restRequest, RestOperations operations ) { 37 | this(restRequest); 38 | this.operations = operations; 39 | } 40 | 41 | 42 | public RecordingRestRequest(String baseUri, MediaType contentType, MediaType acceptHeader) { 43 | this.baseUri = uriWithoutSlash( baseUri ); 44 | this.contentType = contentType; 45 | this.acceptHeader = acceptHeader; 46 | } 47 | 48 | @Override 49 | public RequestResult get(String path, Object data) { 50 | return this.record(Methods.GET, path, data, getBaseUri()); 51 | } 52 | 53 | @Override 54 | public RequestResult delete(String path) { 55 | return this.record(Methods.DELETE, path, null, getBaseUri()); 56 | } 57 | 58 | @Override 59 | public RequestResult post(String path, Object data) { 60 | return this.record(Methods.POST, path, data, getBaseUri()); 61 | } 62 | 63 | @Override 64 | public RequestResult put(String path, Object data) { 65 | return this.record(Methods.PUT, path, data, getBaseUri()); 66 | 67 | } 68 | 69 | @Override 70 | public RestRequest with(String uri) { 71 | return new RecordingRestRequest(this.restRequest.with(uri), this.operations); 72 | } 73 | 74 | @Override 75 | public String getUri() { 76 | return getBaseUri(); 77 | } 78 | 79 | @Override 80 | public RequestResult get(String path) { 81 | return this.record(Methods.GET, path, null, getBaseUri()); 82 | } 83 | 84 | public RequestResult record(Methods method, String path, Object data, String baseUri){ 85 | if (stop) throw new IllegalStateException("BatchRequest already executed"); 86 | return this.operations.record(method, path, data,baseUri); 87 | } 88 | 89 | 90 | 91 | 92 | private String uriWithoutSlash( String uri ) { 93 | String uriString = uri; 94 | return uriString.endsWith( "/" ) ? uriString.substring( 0, uriString.length() - 1 ) : uri; 95 | } 96 | 97 | public static String encode( Object value ) { 98 | if ( value == null ) return ""; 99 | try { 100 | return URLEncoder.encode( value.toString(), "utf-8" ).replaceAll( "\\+", "%20" ); 101 | } catch ( UnsupportedEncodingException e ) { 102 | throw new RuntimeException( e ); 103 | } 104 | } 105 | 106 | public Map getRecordedRequests(){ 107 | return this.operations.getRecordedRequests(); 108 | } 109 | 110 | public void stop() { 111 | this.stop = true; 112 | } 113 | 114 | public String getBaseUri() { 115 | return baseUri; 116 | } 117 | } 118 | 119 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/batch/RestOperations.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.batch; 2 | 3 | import org.neo4j.rest.graphdb.RequestResult; 4 | import org.neo4j.rest.graphdb.RestAPI; 5 | import org.neo4j.rest.graphdb.UpdatableRestResult; 6 | import org.neo4j.rest.graphdb.batch.RestOperations.RestOperation.Methods; 7 | import org.neo4j.rest.graphdb.converter.RestResultConverter; 8 | 9 | import javax.ws.rs.core.MediaType; 10 | import java.util.LinkedHashMap; 11 | import java.util.Map; 12 | import java.util.concurrent.atomic.AtomicLong; 13 | 14 | public class RestOperations { 15 | private AtomicLong currentBatchId = new AtomicLong(0); 16 | private Map operations = new LinkedHashMap(); 17 | private MediaType contentType; 18 | private MediaType acceptHeader; 19 | 20 | public RestOperations(){ 21 | this.contentType = MediaType.APPLICATION_JSON_TYPE; 22 | this.acceptHeader = MediaType.APPLICATION_JSON_TYPE; 23 | } 24 | 25 | public RestOperation getOperation(Long batchId) { 26 | return operations.get(batchId); 27 | } 28 | 29 | public static class RestOperation { 30 | 31 | public enum Methods{ 32 | POST, 33 | PUT, 34 | GET, 35 | DELETE 36 | } 37 | 38 | private Methods method; 39 | private Object data; 40 | private final String baseUri; 41 | private long batchId; 42 | private String uri; 43 | private MediaType contentType; 44 | private MediaType acceptHeader; 45 | private Object entity; 46 | private RestResultConverter resultConverter; 47 | 48 | 49 | 50 | public RestOperation(long batchId, Methods method, String uri, MediaType contentType, MediaType acceptHeader, Object data, String baseUri){ 51 | this.batchId = batchId; 52 | this.method = method; 53 | this.uri = uri; 54 | this.contentType = contentType; 55 | this.acceptHeader = acceptHeader; 56 | this.data = data; 57 | this.baseUri = baseUri; 58 | } 59 | 60 | public void updateEntity(Object updateObject, RestAPI restApi){ 61 | if (this.entity instanceof UpdatableRestResult){ 62 | ((UpdatableRestResult)this.entity).updateFrom(updateObject, restApi); 63 | } 64 | } 65 | 66 | public Object getEntity() { 67 | return entity; 68 | } 69 | 70 | public RestResultConverter getResultConverter() { 71 | return resultConverter; 72 | } 73 | 74 | public void setEntity(Object entity, RestResultConverter resultConverter) { 75 | this.entity = entity; 76 | this.resultConverter = resultConverter; 77 | } 78 | 79 | public Methods getMethod() { 80 | return method; 81 | } 82 | 83 | public Object getData() { 84 | return data; 85 | } 86 | 87 | public long getBatchId() { 88 | return batchId; 89 | } 90 | 91 | public String getUri() { 92 | return uri; 93 | } 94 | 95 | public MediaType getContentType() { 96 | return contentType; 97 | } 98 | 99 | public MediaType getAcceptHeader() { 100 | return acceptHeader; 101 | } 102 | 103 | public String getBaseUri() { 104 | return baseUri; 105 | } 106 | public boolean isSameUri(String baseUri) { 107 | return this.baseUri.equals(baseUri); 108 | } 109 | } 110 | 111 | public Map getRecordedRequests(){ 112 | return this.operations; 113 | } 114 | 115 | public RequestResult record(Methods method, String path, Object data, String baseUri){ 116 | long batchId = this.currentBatchId.incrementAndGet(); 117 | RestOperation r = new RestOperation(batchId,method,path,this.contentType,this.acceptHeader,data,baseUri); 118 | operations.put(batchId,r); 119 | return RequestResult.batchResult(r); 120 | } 121 | 122 | public void addToRestOperation(long batchId, Object entity, final RestResultConverter resultConverter){ 123 | this.operations.get(batchId).setEntity(entity, resultConverter); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/converter/RelationshipIterableConverter.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.converter; 2 | 3 | import org.neo4j.graphdb.Relationship; 4 | import org.neo4j.helpers.collection.IterableWrapper; 5 | import org.neo4j.rest.graphdb.RequestResult; 6 | import org.neo4j.rest.graphdb.RestAPI; 7 | import org.neo4j.rest.graphdb.entity.RestRelationship; 8 | 9 | import java.util.Collection; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author mh 14 | * @since 22.09.11 15 | */ 16 | public class RelationshipIterableConverter implements RestResultConverter { 17 | private final RestAPI restAPI; 18 | 19 | public RelationshipIterableConverter(RestAPI restAPI) { 20 | this.restAPI = restAPI; 21 | } 22 | 23 | @Override 24 | public Object convertFromRepresentation(RequestResult requestResult) { 25 | return new IterableWrapper((Collection) requestResult.toEntity()) { 26 | @Override 27 | protected Relationship underlyingObjectToObject(Object data) { 28 | return new RestRelationship((Map) data, restAPI); 29 | } 30 | }; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/converter/RestEntityExtractor.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.converter; 2 | 3 | import java.util.Map; 4 | 5 | import org.neo4j.rest.graphdb.RequestResult; 6 | import org.neo4j.rest.graphdb.RestAPI; 7 | import org.neo4j.rest.graphdb.entity.RestEntity; 8 | import org.neo4j.rest.graphdb.entity.RestNode; 9 | import org.neo4j.rest.graphdb.entity.RestRelationship; 10 | 11 | 12 | public class RestEntityExtractor implements RestResultConverter { 13 | private final RestAPI restApi; 14 | 15 | public RestEntityExtractor(RestAPI restApi) { 16 | this.restApi = restApi; 17 | } 18 | 19 | public Object convertFromRepresentation(RequestResult requestResult) { 20 | return convertFromRepresentation(requestResult.toMap()); 21 | } 22 | 23 | public Object convertFromRepresentation(Object value) { 24 | if (value instanceof Map) { 25 | RestEntity restEntity = createRestEntity((Map) value); 26 | if (restEntity != null) return restEntity; 27 | } 28 | return value; 29 | } 30 | 31 | RestEntity createRestEntity(Map data) { 32 | final String uri = (String) data.get("self"); 33 | if (uri == null || uri.isEmpty()) return null; 34 | if (uri.contains("/node/")) { 35 | return new RestNode(data, restApi); 36 | } 37 | if (uri.contains("/relationship/")) { 38 | return new RestRelationship(data, restApi); 39 | } 40 | return null; 41 | } 42 | 43 | public boolean canHandle(Object value) { 44 | if (value instanceof Map) { 45 | final String uri = (String) ((Map)value).get("self"); 46 | if (uri != null && (uri.contains("/node/") || uri.contains("/relationship/"))){ 47 | return true; 48 | } 49 | } 50 | return false; 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/converter/RestIndexHitsConverter.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.converter; 2 | 3 | import org.neo4j.graphdb.PropertyContainer; 4 | import org.neo4j.graphdb.index.IndexHits; 5 | import org.neo4j.rest.graphdb.RequestResult; 6 | import org.neo4j.rest.graphdb.RestAPI; 7 | import org.neo4j.rest.graphdb.index.SimpleIndexHits; 8 | 9 | import java.util.Collection; 10 | 11 | /** 12 | * @author mh 13 | * @since 22.09.11 14 | */ 15 | public class RestIndexHitsConverter implements RestResultConverter { 16 | private final RestAPI restAPI; 17 | private final Class entityType; 18 | 19 | public RestIndexHitsConverter(RestAPI restAPI,Class entityType) { 20 | this.restAPI = restAPI; 21 | this.entityType = entityType; 22 | } 23 | 24 | public IndexHits convertFromRepresentation(RequestResult response) { 25 | Collection hits = (Collection) response.toEntity(); 26 | return new SimpleIndexHits(hits, hits.size(), entityType, restAPI); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/converter/RestResultConverter.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.converter; 2 | 3 | import org.neo4j.rest.graphdb.RequestResult; 4 | 5 | public interface RestResultConverter { 6 | public Object convertFromRepresentation(RequestResult value); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/converter/RestTableResultExtractor.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.converter; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public class RestTableResultExtractor { 9 | 10 | private final RestEntityExtractor restEntityExtractor; 11 | 12 | public RestTableResultExtractor(RestEntityExtractor restEntityExtractor) { 13 | this.restEntityExtractor = restEntityExtractor; 14 | } 15 | 16 | public List> extract(Map restResult) { 17 | List columns = (List) restResult.get("columns"); 18 | return extractData(restResult, columns); 19 | } 20 | 21 | private List> extractData(Map restResult, List columns) { 22 | List> rows = (List>) restResult.get("data"); 23 | List> result = new ArrayList>(rows.size()); 24 | for (List row : rows) { 25 | result.add(mapRow(columns, row)); 26 | } 27 | return result; 28 | } 29 | 30 | private Map mapRow(List columns, List row) { 31 | int columnCount = columns.size(); 32 | Map newRow = new HashMap(columnCount); 33 | for (int i = 0; i < columnCount; i++) { 34 | final Object value = row.get(i); 35 | newRow.put(columns.get(i), restEntityExtractor.convertFromRepresentation(value)); 36 | } 37 | return newRow; 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/entity/RestEntity.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.entity; 2 | 3 | 4 | import org.neo4j.graphdb.NotFoundException; 5 | import org.neo4j.graphdb.PropertyContainer; 6 | import org.neo4j.helpers.collection.IterableWrapper; 7 | import org.neo4j.rest.graphdb.PropertiesMap; 8 | import org.neo4j.rest.graphdb.RequestResult; 9 | import org.neo4j.rest.graphdb.RestAPI; 10 | import org.neo4j.rest.graphdb.RestGraphDatabase; 11 | import org.neo4j.rest.graphdb.RestRequest; 12 | import org.neo4j.rest.graphdb.UpdatableRestResult; 13 | import org.neo4j.rest.graphdb.util.ArrayConverter; 14 | 15 | import javax.ws.rs.core.Response.Status; 16 | import java.net.URI; 17 | import java.util.Collection; 18 | import java.util.Collections; 19 | import java.util.Map; 20 | 21 | public class RestEntity implements PropertyContainer, UpdatableRestResult { 22 | private Map structuralData; 23 | private Map propertyData; 24 | private long lastTimeFetchedPropertyData; 25 | protected RestAPI restApi; 26 | 27 | 28 | protected RestRequest restRequest; 29 | private final ArrayConverter arrayConverter=new ArrayConverter(); 30 | 31 | public RestEntity( URI uri, RestAPI restApi ) { 32 | this( uri.toString(), restApi ); 33 | } 34 | 35 | public RestEntity( String uri, RestAPI restApi ) { 36 | this.restRequest = restApi.getRestRequest().with( uri ); 37 | this.restApi = restApi; 38 | } 39 | 40 | public RestEntity( Map data, RestAPI restApi ) { 41 | this.structuralData = data; 42 | this.restApi = restApi; 43 | this.propertyData = (Map) data.get( "data" ); 44 | this.lastTimeFetchedPropertyData = System.currentTimeMillis(); 45 | String uri = (String) data.get( "self" ); 46 | this.restRequest = restApi.getRestRequest().with( uri ); 47 | } 48 | 49 | public String getUri() { 50 | return this.restRequest.getUri(); 51 | } 52 | 53 | public void updateFrom(RestEntity updateEntity, RestAPI restApi){ 54 | this.restApi = restApi; 55 | this.restRequest = restApi.getRestRequest().with(updateEntity.getUri()); 56 | this.structuralData = updateEntity.getStructuralData(); 57 | this.propertyData = updateEntity.getPropertyData(); 58 | this.lastTimeFetchedPropertyData = System.currentTimeMillis(); 59 | } 60 | 61 | Map getStructuralData() { 62 | if ( this.structuralData == null ) { 63 | this.structuralData = restRequest.get( "" ) .toMap(); 64 | } 65 | return this.structuralData; 66 | } 67 | 68 | Map getPropertyData() { 69 | if (hasToUpdateProperties()) { 70 | RequestResult response = restRequest.get( "properties" ); 71 | boolean ok = response.statusIs( Status.OK ); 72 | if ( ok ) { 73 | this.propertyData = (Map) response.toMap( ); 74 | } else { 75 | this.propertyData = Collections.emptyMap(); 76 | } 77 | this.lastTimeFetchedPropertyData = System.currentTimeMillis(); 78 | } 79 | return this.propertyData; 80 | } 81 | 82 | private boolean hasToUpdateProperties() { 83 | return this.propertyData == null || timeElapsed( this.lastTimeFetchedPropertyData, restApi.getPropertyRefetchTimeInMillis() ); 84 | } 85 | 86 | private boolean timeElapsed( long since, long isItGreaterThanThis ) { 87 | return System.currentTimeMillis() - since > isItGreaterThanThis; 88 | } 89 | 90 | public Object getProperty( String key ) { 91 | Object value = getPropertyValue(key); 92 | if ( value == null ) { 93 | throw new NotFoundException( "'" + key + "' on " + this ); 94 | } 95 | return value; 96 | } 97 | 98 | private Object getPropertyValue( String key ) { 99 | Map properties = getPropertyData(); 100 | Object value = properties.get( key ); 101 | if ( value == null) return null; 102 | if ( value instanceof Collection ) { 103 | Collection col= (Collection) value; 104 | if (col.isEmpty()) return new String[0]; // todo concrete value type ? 105 | Object result = arrayConverter.toArray( col ); 106 | if (result == null) throw new IllegalStateException( "Could not determine type of property "+key ); 107 | properties.put(key,result); 108 | return result; 109 | 110 | } 111 | return PropertiesMap.assertSupportedPropertyValue( value ); 112 | } 113 | 114 | public Object getProperty( String key, Object defaultValue ) { 115 | Object value = getPropertyValue( key ); 116 | return value != null ? value : defaultValue; 117 | } 118 | 119 | @SuppressWarnings("unchecked") 120 | public Iterable getPropertyKeys() { 121 | return new IterableWrapper( getPropertyData().keySet() ) { 122 | @Override 123 | protected String underlyingObjectToObject( Object key ) { 124 | return key.toString(); 125 | } 126 | }; 127 | } 128 | 129 | @SuppressWarnings("unchecked") 130 | public Iterable getPropertyValues() { 131 | return (Iterable) getPropertyData().values(); 132 | } 133 | 134 | public boolean hasProperty( String key ) { 135 | return getPropertyData().containsKey( key ); 136 | } 137 | 138 | public Object removeProperty( String key ) { 139 | Object value = getProperty( key, null ); 140 | restRequest.delete("properties/" + key); 141 | invalidatePropertyData(); 142 | return value; 143 | } 144 | 145 | public void setProperty( String key, Object value ) { 146 | restRequest.put( "properties/" + key, value); 147 | invalidatePropertyData(); 148 | } 149 | 150 | private void invalidatePropertyData() { 151 | this.propertyData = null; 152 | } 153 | 154 | static long getEntityId( String uri ) { 155 | return Long.parseLong(uri.substring(uri.lastIndexOf('/') + 1)); 156 | } 157 | 158 | public long getId() { 159 | return getEntityId( getUri() ); 160 | } 161 | 162 | public void delete() { 163 | restRequest.delete( "" ); 164 | } 165 | 166 | @Override 167 | public int hashCode() { 168 | return (int) getId(); 169 | } 170 | 171 | @Override 172 | public boolean equals( Object o ) { 173 | if (o == null) return false; 174 | return getClass().equals( o.getClass() ) && getId() == ( (RestEntity) o ).getId(); 175 | } 176 | 177 | 178 | public RestGraphDatabase getGraphDatabase() { 179 | return new RestGraphDatabase(restApi); 180 | } 181 | 182 | public RestRequest getRestRequest() { 183 | return restRequest; 184 | } 185 | 186 | @Override 187 | public String toString() { 188 | return getUri(); 189 | } 190 | 191 | public RestAPI getRestApi() { 192 | return restApi; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/entity/RestNode.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.entity; 2 | 3 | import org.neo4j.graphdb.*; 4 | import org.neo4j.graphdb.Traverser.Order; 5 | import org.neo4j.helpers.collection.CombiningIterable; 6 | import org.neo4j.helpers.collection.IterableWrapper; 7 | import org.neo4j.helpers.collection.IteratorUtil; 8 | import org.neo4j.rest.graphdb.RestAPI; 9 | import org.neo4j.rest.graphdb.traversal.RestDirection; 10 | 11 | import java.net.URI; 12 | import java.util.Map; 13 | 14 | import static java.util.Arrays.asList; 15 | 16 | public class RestNode extends RestEntity implements Node { 17 | public RestNode( URI uri, RestAPI restApi ) { 18 | super( uri, restApi ); 19 | } 20 | 21 | public RestNode( String uri, RestAPI restApi ) { 22 | super( uri, restApi ); 23 | } 24 | 25 | public RestNode( Map data, RestAPI restApi ) { 26 | super( data, restApi ); 27 | } 28 | 29 | public Relationship createRelationshipTo( Node toNode, RelationshipType type ) { 30 | return this.restApi.createRelationship(this,(RestNode)toNode,type,null); 31 | } 32 | 33 | public Iterable getRelationships() { 34 | return restApi.wrapRelationships( restRequest.get( "relationships/all" ) ); 35 | } 36 | 37 | public Iterable getRelationships( RelationshipType... types ) { 38 | String path = getStructuralData().get( "all_relationships" ) + "/"; 39 | int counter = 0; 40 | for ( RelationshipType type : types ) { 41 | if ( counter++ > 0 ) { 42 | path += "&"; 43 | } 44 | path += type.name(); 45 | } 46 | return restApi.wrapRelationships( restRequest.get( path ) ); 47 | } 48 | 49 | 50 | public Iterable getRelationships( Direction direction ) { 51 | return restApi.wrapRelationships( restRequest.get( "relationships/" + RestDirection.from( direction ).shortName ) ); 52 | } 53 | 54 | public Iterable getRelationships( RelationshipType type, 55 | Direction direction ) { 56 | String relationshipsKey = RestDirection.from( direction ).longName + "_relationships"; 57 | Object relationship = getStructuralData().get( relationshipsKey ); 58 | return restApi.wrapRelationships( restRequest.get( relationship + "/" + type.name() ) ); 59 | } 60 | 61 | public Relationship getSingleRelationship( RelationshipType type, 62 | Direction direction ) { 63 | return IteratorUtil.singleOrNull( getRelationships( type, direction ) ); 64 | } 65 | 66 | public boolean hasRelationship() { 67 | return getRelationships().iterator().hasNext(); 68 | } 69 | 70 | public boolean hasRelationship( RelationshipType... types ) { 71 | return getRelationships( types ).iterator().hasNext(); 72 | } 73 | 74 | public boolean hasRelationship( Direction direction ) { 75 | return getRelationships( direction ).iterator().hasNext(); 76 | } 77 | 78 | public boolean hasRelationship( RelationshipType type, Direction direction ) { 79 | return getRelationships( type, direction ).iterator().hasNext(); 80 | } 81 | 82 | public Traverser traverse( Order order, StopEvaluator stopEvaluator, 83 | ReturnableEvaluator returnableEvaluator, Object... rels ) { 84 | throw new UnsupportedOperationException(); 85 | } 86 | 87 | public Traverser traverse( Order order, StopEvaluator stopEvaluator, 88 | ReturnableEvaluator returnableEvaluator, RelationshipType type, Direction direction ) { 89 | throw new UnsupportedOperationException(); 90 | } 91 | 92 | public Traverser traverse( Order order, StopEvaluator stopEvaluator, 93 | ReturnableEvaluator returnableEvaluator, RelationshipType type, Direction direction, 94 | RelationshipType secondType, Direction secondDirection ) { 95 | throw new UnsupportedOperationException(); 96 | } 97 | 98 | @Override 99 | public Iterable getRelationships(final Direction direction, RelationshipType... types) { 100 | return new CombiningIterable(new IterableWrapper, RelationshipType>(asList(types)) { 101 | @Override 102 | protected Iterable underlyingObjectToObject(RelationshipType relationshipType) { 103 | return getRelationships(relationshipType,direction); 104 | } 105 | }); 106 | } 107 | 108 | @Override 109 | public boolean hasRelationship(Direction direction, RelationshipType... types) { 110 | for (RelationshipType relationshipType : types) { 111 | if (hasRelationship(relationshipType,direction)) return true; 112 | } 113 | return false; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/entity/RestRelationship.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.entity; 2 | 3 | import org.neo4j.graphdb.*; 4 | import org.neo4j.rest.graphdb.RestAPI; 5 | 6 | import java.net.URI; 7 | import java.util.Map; 8 | 9 | 10 | public class RestRelationship extends RestEntity implements Relationship { 11 | 12 | RestRelationship( URI uri, RestAPI restApi ) { 13 | super( uri, restApi ); 14 | } 15 | 16 | public RestRelationship( String uri, RestAPI restApi ) { 17 | super( uri, restApi ); 18 | } 19 | 20 | public RestRelationship( Map data, RestAPI restApi ) { 21 | super( data, restApi ); 22 | } 23 | 24 | public Node getEndNode() { 25 | return node( (String) getStructuralData().get( "end" ) ); 26 | } 27 | 28 | public Node[] getNodes() { 29 | return new Node[]{ 30 | node( (String) getStructuralData().get( "start" ) ), 31 | node( (String) getStructuralData().get( "end" ) ) 32 | }; 33 | } 34 | 35 | public Node getOtherNode( Node node ) { 36 | long nodeId = node.getId(); 37 | String startNodeUri = (String) getStructuralData().get( "start" ); 38 | String endNodeUri = (String) getStructuralData().get( "end" ); 39 | if ( getEntityId( startNodeUri ) == nodeId ) { 40 | return node( endNodeUri ); 41 | } else if ( getEntityId( endNodeUri ) == nodeId ) { 42 | return node( startNodeUri ); 43 | } else { 44 | throw new NotFoundException( node + " isn't one of start/end for " + this ); 45 | } 46 | } 47 | 48 | private RestNode node( String uri ) { 49 | return new RestNode( uri, getRestApi() ); 50 | } 51 | 52 | public Node getStartNode() { 53 | return node( (String) getStructuralData().get( "start" ) ); 54 | } 55 | 56 | public RelationshipType getType() { 57 | return DynamicRelationshipType.withName( (String) getStructuralData().get( "type" ) ); 58 | } 59 | 60 | public boolean isType( RelationshipType type ) { 61 | return type.name().equals( getStructuralData().get( "type" ) ); 62 | } 63 | 64 | 65 | public RestRelationship create(RestNode startNode, RestNode endNode, RelationshipType type, Map props) { 66 | return this.restApi.createRelationship(startNode, endNode, type, props); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/index/IndexInfo.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.index; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * @author mh 7 | * @since 22.09.11 8 | */ 9 | public interface IndexInfo { 10 | boolean checkConfig(String indexName, Map config); 11 | 12 | String[] indexNames(); 13 | 14 | boolean exists(String indexName); 15 | 16 | Map getConfig(String name); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/index/RestIndex.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.index; 2 | 3 | 4 | import org.neo4j.graphdb.PropertyContainer; 5 | import org.neo4j.graphdb.index.Index; 6 | import org.neo4j.graphdb.index.IndexHits; 7 | import org.neo4j.index.lucene.QueryContext; 8 | import org.neo4j.rest.graphdb.*; 9 | import org.neo4j.rest.graphdb.entity.RestEntity; 10 | 11 | /** 12 | * @author mh 13 | * @since 24.01.11 14 | */ 15 | public abstract class RestIndex implements Index { 16 | private final RestRequest restRequest; 17 | private final String indexName; 18 | protected final RestAPI restApi; 19 | 20 | RestIndex( RestRequest restRequest, String indexName, RestAPI restApi ) { 21 | this.restRequest = restRequest; 22 | this.indexName = indexName; 23 | this.restApi = restApi; 24 | } 25 | 26 | public String getName() { 27 | return indexName; 28 | } 29 | 30 | private String getTypeName() { 31 | return getEntityType().getSimpleName().toLowerCase(); 32 | } 33 | 34 | public void add( T entity, String key, Object value ) { 35 | final RestEntity restEntity = (RestEntity) entity; 36 | final String indexPath = indexPath(key, value); 37 | try { 38 | addToIndex(restEntity, indexPath); 39 | } catch (Exception e) { 40 | throw new RuntimeException(String.format("Error adding element %d %s %s to index %s", restEntity.getId(), key, value, indexName)); 41 | } 42 | } 43 | 44 | private void addToIndex(RestEntity restEntity, String indexPath) { 45 | String uri = restEntity.getUri(); 46 | final RequestResult response = restRequest.post(indexPath, uri); 47 | if (response.getStatus() != 201) throw new RuntimeException("Error adding to index"); 48 | } 49 | 50 | private String indexPath( String key, Object value ) { 51 | return "index/" + getTypeName() + "/" + indexName + (key!=null? "/" + ExecutingRestRequest.encode( key ) :"") + (value!=null ? "/" + ExecutingRestRequest.encode( value ):""); 52 | } 53 | private String queryPath( String key, Object value ) { 54 | return indexPath(key,null) + "?query="+ExecutingRestRequest.encode( value ); 55 | } 56 | 57 | public void remove( T entity, String key, Object value ) { 58 | final String indexPath = indexPath(key, value) + "/" + ((RestEntity) entity).getId(); 59 | deleteIndex(indexPath); 60 | } 61 | 62 | private void deleteIndex(String indexPath) { 63 | restRequest.delete(indexPath); 64 | } 65 | 66 | public void remove(T entity, String key) { 67 | deleteIndex(indexPath(key, null) + "/" + ((RestEntity) entity).getId()); 68 | } 69 | 70 | public void remove(T entity) { 71 | deleteIndex(indexPath( null, null) + "/" + ( (RestEntity) entity ).getId()); 72 | } 73 | 74 | public void delete() { 75 | deleteIndex(indexPath(null,null)); 76 | } 77 | 78 | public org.neo4j.graphdb.index.IndexHits get( String key, Object value ) { 79 | final String indexPath = indexPath(key, value); 80 | return restApi.queryIndex(indexPath,getEntityType()); 81 | } 82 | 83 | 84 | public IndexHits query( String key, Object value ) { 85 | final String indexPath = queryPath(key, value); 86 | return restApi.queryIndex(indexPath, getEntityType()); 87 | } 88 | 89 | public org.neo4j.graphdb.index.IndexHits query( Object value ) { 90 | if (value instanceof QueryContext) { 91 | value = ((QueryContext)value).getQueryOrQueryObject(); 92 | } 93 | return query("null",value); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/index/RestIndexManager.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.index; 2 | 3 | import org.neo4j.graphdb.Node; 4 | import org.neo4j.graphdb.PropertyContainer; 5 | import org.neo4j.graphdb.Relationship; 6 | import org.neo4j.graphdb.index.*; 7 | import org.neo4j.index.impl.lucene.LuceneIndexImplementation; 8 | import org.neo4j.rest.graphdb.RequestResult; 9 | import org.neo4j.rest.graphdb.RestAPI; 10 | import org.neo4j.rest.graphdb.RestRequest; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | public class RestIndexManager implements IndexManager { 16 | public static final String RELATIONSHIP = "relationship"; 17 | public static final String NODE = "node"; 18 | private RestRequest restRequest; 19 | private RestAPI restApi; 20 | 21 | public RestIndexManager( RestRequest restRequest, RestAPI restApi ) { 22 | this.restRequest = restRequest; 23 | this.restApi = restApi; 24 | } 25 | 26 | public boolean existsForNodes( String indexName ) { 27 | return indexInfo(NODE).exists(indexName); 28 | } 29 | 30 | @SuppressWarnings({"unchecked"}) 31 | private IndexInfo indexInfo(final String indexType) { 32 | return restApi.indexInfo(indexType); 33 | } 34 | 35 | @SuppressWarnings("unchecked") 36 | private boolean checkIndex( final String indexType, final String indexName, Map config ){ 37 | final IndexInfo indexInfo = indexInfo(indexType); 38 | return indexInfo.checkConfig(indexName, config); 39 | } 40 | 41 | public boolean noConfigProvided(Map config) { 42 | return config == null || config.isEmpty(); 43 | } 44 | 45 | public Index forNodes( String indexName ) { 46 | if (!checkIndex(NODE, indexName, null)){ 47 | createIndex(NODE, indexName, LuceneIndexImplementation.EXACT_CONFIG); 48 | } 49 | return new RestNodeIndex( restRequest, indexName, restApi ); 50 | } 51 | 52 | public Index forNodes( String indexName, Map config ) { 53 | if (noConfigProvided(config)){ 54 | throw new IllegalArgumentException("No index configuration was provided!"); 55 | } 56 | if (!checkIndex(NODE, indexName, config)){ 57 | createIndex(NODE, indexName, config); 58 | } 59 | return new RestNodeIndex( restRequest, indexName, restApi ); 60 | } 61 | 62 | public String[] nodeIndexNames() { 63 | final IndexInfo indexInfo = indexInfo(NODE); 64 | return indexInfo.indexNames(); 65 | } 66 | 67 | public boolean existsForRelationships( String indexName ) { 68 | return indexInfo(RELATIONSHIP).exists(indexName); 69 | } 70 | 71 | public RelationshipIndex forRelationships( String indexName ) { 72 | if (!checkIndex(RELATIONSHIP, indexName, null)){ 73 | createIndex(RELATIONSHIP, indexName, LuceneIndexImplementation.EXACT_CONFIG); 74 | } 75 | return new RestRelationshipIndex( restRequest, indexName, restApi ); 76 | } 77 | 78 | public RelationshipIndex forRelationships( String indexName, Map config ) { 79 | if (noConfigProvided(config)){ 80 | throw new IllegalArgumentException("No index configuration was provided!"); 81 | } 82 | if (!checkIndex(RELATIONSHIP, indexName, config)){ 83 | createIndex(RELATIONSHIP, indexName, config); 84 | } 85 | return new RestRelationshipIndex( restRequest, indexName, restApi ); 86 | } 87 | 88 | private void createIndex(String type, String indexName, Map config) { 89 | Map data=new HashMap(); 90 | data.put("name",indexName); 91 | data.put("config",config); 92 | restRequest.post("index/" + type, data); 93 | } 94 | 95 | public String[] relationshipIndexNames() { 96 | return indexInfo(RELATIONSHIP).indexNames(); 97 | } 98 | 99 | @SuppressWarnings({"unchecked"}) 100 | public Map getConfiguration( Index index ) { 101 | String typeName = typeName(index.getEntityType()); 102 | return indexInfo(typeName).getConfig(index.getName()); 103 | } 104 | 105 | private String typeName(Class type) { 106 | if (Node.class.isAssignableFrom(type)) return NODE; 107 | if (Relationship.class.isAssignableFrom(type)) return RELATIONSHIP; 108 | throw new IllegalArgumentException("Invalid index type "+type); 109 | } 110 | 111 | public String setConfiguration( Index index, String s, String s1 ) { 112 | throw new UnsupportedOperationException(); 113 | } 114 | 115 | public String removeConfiguration( Index index, String s ) { 116 | throw new UnsupportedOperationException(); 117 | } 118 | 119 | @Override 120 | public AutoIndexer getNodeAutoIndexer() { 121 | throw new UnsupportedOperationException(); 122 | } 123 | 124 | @Override 125 | public RelationshipAutoIndexer getRelationshipAutoIndexer() { 126 | throw new UnsupportedOperationException(); 127 | } 128 | } 129 | 130 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/index/RestNodeIndex.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.index; 2 | 3 | import org.neo4j.graphdb.Node; 4 | import org.neo4j.rest.graphdb.RestAPI; 5 | import org.neo4j.rest.graphdb.RestRequest; 6 | 7 | /** 8 | * @author mh 9 | * @since 24.01.11 10 | */ 11 | public class RestNodeIndex extends RestIndex { 12 | public RestNodeIndex( RestRequest restRequest, String indexName, RestAPI restApi ) { 13 | super( restRequest, indexName, restApi ); 14 | } 15 | 16 | public Class getEntityType() { 17 | return Node.class; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/index/RestRelationshipIndex.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.index; 2 | 3 | import org.neo4j.graphdb.Node; 4 | import org.neo4j.graphdb.Relationship; 5 | import org.neo4j.graphdb.index.RelationshipIndex; 6 | import org.neo4j.rest.graphdb.RestAPI; 7 | import org.neo4j.rest.graphdb.RestRequest; 8 | 9 | /** 10 | * @author mh 11 | * @since 24.01.11 12 | */ 13 | public class RestRelationshipIndex extends RestIndex implements RelationshipIndex { 14 | public RestRelationshipIndex( RestRequest restRequest, String indexName, RestAPI restApi ) { 15 | super( restRequest, indexName, restApi ); 16 | } 17 | 18 | public Class getEntityType() { 19 | return Relationship.class; 20 | } 21 | 22 | public org.neo4j.graphdb.index.IndexHits get( String s, Object o, Node node, Node node1 ) { 23 | throw new UnsupportedOperationException(); 24 | } 25 | 26 | public org.neo4j.graphdb.index.IndexHits query( String s, Object o, Node node, Node node1 ) { 27 | throw new UnsupportedOperationException(); 28 | } 29 | 30 | public org.neo4j.graphdb.index.IndexHits query( Object o, Node node, Node node1 ) { 31 | throw new UnsupportedOperationException(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/index/RetrievedIndexInfo.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.index; 2 | 3 | import com.sun.jersey.api.client.ClientResponse; 4 | import org.neo4j.rest.graphdb.RequestResult; 5 | 6 | import java.util.Collections; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | /** 11 | * @author mh 12 | * @since 22.09.11 13 | */ 14 | public class RetrievedIndexInfo implements IndexInfo { 15 | private Map indexInfo; 16 | 17 | public RetrievedIndexInfo(RequestResult response) { 18 | if (response.statusIs(ClientResponse.Status.NO_CONTENT)) this.indexInfo = Collections.emptyMap(); 19 | else this.indexInfo = (Map) response.toMap(); 20 | } 21 | 22 | @Override 23 | public boolean checkConfig(String indexName, Map config) { 24 | Map existingConfig = (Map) indexInfo.get(indexName); 25 | if (config == null) { 26 | return existingConfig != null; 27 | } else { 28 | if (existingConfig == null) { 29 | return false; 30 | } else { 31 | if (existingConfig.entrySet().containsAll(config.entrySet())) { 32 | return true; 33 | } else { 34 | throw new IllegalArgumentException("Index with the same name but different config exists!"); 35 | } 36 | } 37 | } 38 | } 39 | 40 | @Override 41 | public String[] indexNames() { 42 | Set keys = indexInfo.keySet(); 43 | return keys.toArray(new String[keys.size()]); 44 | } 45 | 46 | @Override 47 | public boolean exists(String indexName) { 48 | return indexInfo.containsKey(indexName); 49 | } 50 | 51 | @Override 52 | public Map getConfig(String name) { 53 | return (Map) indexInfo.get(name); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/index/SimpleIndexHits.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.index; 2 | 3 | import org.neo4j.graphdb.PropertyContainer; 4 | import org.neo4j.graphdb.index.IndexHits; 5 | import org.neo4j.rest.graphdb.RestAPI; 6 | import org.neo4j.rest.graphdb.UpdatableRestResult; 7 | import org.neo4j.rest.graphdb.converter.RestEntityExtractor; 8 | 9 | import java.util.Collection; 10 | import java.util.Iterator; 11 | 12 | /** 13 | * @author mh 14 | * @since 22.09.11 15 | */ 16 | public class SimpleIndexHits implements IndexHits, UpdatableRestResult> { 17 | private Collection hits; 18 | private Class entityType; 19 | private int size; 20 | private Iterator iterator; 21 | private RestEntityExtractor entityExtractor; 22 | 23 | public SimpleIndexHits(long batchId, Class entityType, final RestAPI restApi) { 24 | this.entityType = entityType; 25 | this.entityExtractor = restApi.createExtractor(); 26 | 27 | } 28 | 29 | public SimpleIndexHits(Collection hits, int size, Class entityType, final RestAPI restApi) { 30 | this.hits = hits; 31 | this.entityType = entityType; 32 | this.iterator = this.hits.iterator(); 33 | this.size = size; 34 | this.entityExtractor = restApi.createExtractor(); 35 | } 36 | 37 | public int size() { 38 | return size; 39 | } 40 | 41 | public void close() { 42 | 43 | } 44 | 45 | public T getSingle() { 46 | Iterator it = hits.iterator(); 47 | return it.hasNext() ? transform(it.next()) : null; 48 | } 49 | 50 | public float currentScore() { 51 | return 0; 52 | } 53 | 54 | public Iterator iterator() { 55 | return this; 56 | } 57 | 58 | public boolean hasNext() { 59 | return iterator.hasNext(); 60 | } 61 | 62 | public T next() { 63 | Object value = iterator.next(); 64 | return transform(value); 65 | } 66 | 67 | private T transform(Object value) { 68 | return (T) entityExtractor.convertFromRepresentation(value); 69 | } 70 | 71 | public void remove() { 72 | 73 | } 74 | 75 | @Override 76 | public void updateFrom(SimpleIndexHits newValue, RestAPI restApi) { 77 | this.hits= newValue.hits; 78 | this.iterator = this.hits.iterator(); 79 | this.size = newValue.size; 80 | this.entityExtractor = restApi.createExtractor(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/query/QueryEngine.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.query; 2 | 3 | import java.util.Map; 4 | 5 | import org.neo4j.rest.graphdb.util.QueryResult; 6 | 7 | public interface QueryEngine { 8 | QueryResult query(String statement, Map params); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/query/RestCypherQueryEngine.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.query; 2 | 3 | import java.util.Iterator; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import org.neo4j.helpers.collection.MapUtil; 8 | import org.neo4j.rest.graphdb.RequestResult; 9 | import org.neo4j.rest.graphdb.RestAPI; 10 | import org.neo4j.rest.graphdb.RestRequest; 11 | import org.neo4j.rest.graphdb.converter.RestEntityExtractor; 12 | import org.neo4j.rest.graphdb.converter.RestTableResultExtractor; 13 | import org.neo4j.rest.graphdb.util.ConvertedResult; 14 | import org.neo4j.rest.graphdb.util.DefaultConverter; 15 | import org.neo4j.rest.graphdb.util.Handler; 16 | import org.neo4j.rest.graphdb.util.QueryResult; 17 | import org.neo4j.rest.graphdb.util.QueryResultBuilder; 18 | import org.neo4j.rest.graphdb.util.ResultConverter; 19 | 20 | 21 | public class RestCypherQueryEngine implements QueryEngine> { 22 | private final RestRequest restRequest; 23 | private final RestAPI restApi; 24 | private final ResultConverter resultConverter; 25 | 26 | public RestCypherQueryEngine(RestAPI restApi) { 27 | this(restApi,null); 28 | } 29 | public RestCypherQueryEngine(RestAPI restApi, ResultConverter resultConverter) { 30 | this.restApi = restApi; 31 | this.resultConverter = resultConverter!=null ? resultConverter : new DefaultConverter(); 32 | this.restRequest = restApi.getRestRequest(); 33 | } 34 | 35 | @Override 36 | public QueryResult> query(String statement, Map params) { 37 | final String parametrizedStatement = QueryResultBuilder.replaceParams(statement, params); 38 | final RequestResult requestResult = restRequest.get("ext/CypherPlugin/graphdb/execute_query", MapUtil.map("query", parametrizedStatement)); 39 | return new RestQueryResult(requestResult.toMap(),restApi,resultConverter); 40 | } 41 | 42 | static class RestQueryResult implements QueryResult> { 43 | QueryResultBuilder> result; 44 | 45 | @Override 46 | public ConvertedResult to(Class type) { 47 | return result.to(type); 48 | } 49 | 50 | @Override 51 | public ConvertedResult to(Class type, ResultConverter, R> converter) { 52 | return result.to(type,converter); 53 | } 54 | 55 | @Override 56 | public void handle(Handler> handler) { 57 | result.handle(handler); 58 | } 59 | 60 | @Override 61 | public Iterator> iterator() { 62 | return result.iterator(); 63 | } 64 | 65 | public RestQueryResult(Map result, RestAPI restApi, ResultConverter resultConverter) { 66 | final RestTableResultExtractor extractor = new RestTableResultExtractor(new RestEntityExtractor(restApi)); 67 | final List> data = extractor.extract(result); 68 | this.result=new QueryResultBuilder>(data, resultConverter); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/query/RestGremlinQueryEngine.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.query; 2 | 3 | import java.util.Collections; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | 7 | import org.neo4j.helpers.collection.IterableWrapper; 8 | import org.neo4j.helpers.collection.MapUtil; 9 | import org.neo4j.rest.graphdb.RequestResult; 10 | import org.neo4j.rest.graphdb.RestAPI; 11 | import org.neo4j.rest.graphdb.RestRequest; 12 | import org.neo4j.rest.graphdb.RestResultException; 13 | import org.neo4j.rest.graphdb.converter.RestEntityExtractor; 14 | import org.neo4j.rest.graphdb.converter.RestTableResultExtractor; 15 | import org.neo4j.rest.graphdb.util.ConvertedResult; 16 | import org.neo4j.rest.graphdb.util.DefaultConverter; 17 | import org.neo4j.rest.graphdb.util.Handler; 18 | import org.neo4j.rest.graphdb.util.JsonHelper; 19 | import org.neo4j.rest.graphdb.util.QueryResult; 20 | import org.neo4j.rest.graphdb.util.QueryResultBuilder; 21 | import org.neo4j.rest.graphdb.util.ResultConverter; 22 | 23 | /** 24 | * @author mh 25 | * @since 22.06.11 26 | */ 27 | public class RestGremlinQueryEngine implements QueryEngine { 28 | private final RestRequest restRequest; 29 | private final RestAPI restApi; 30 | private final ResultConverter resultConverter; 31 | 32 | 33 | public RestGremlinQueryEngine(RestAPI restApi) { 34 | this(restApi,null); 35 | } 36 | public RestGremlinQueryEngine(RestAPI restApi, ResultConverter resultConverter) { 37 | this.restApi = restApi; 38 | this.resultConverter = resultConverter!=null ? resultConverter : new DefaultConverter(); 39 | this.restRequest = restApi.getRestRequest(); 40 | } 41 | 42 | @Override 43 | public QueryResult query(String statement, Map params) { 44 | final String paramsString = JsonHelper.createJsonFrom(params == null ? Collections.emptyMap() : params); 45 | final Map data = MapUtil.map("script", statement,"params",paramsString); 46 | final RequestResult requestResult = restRequest.get("ext/GremlinPlugin/graphdb/execute_script", data); 47 | final Object result = JsonHelper.readJson(requestResult.getEntity()); 48 | if (requestResult.getStatus() == 500) { 49 | return handleError(result); 50 | } else { 51 | return new RestQueryResult(result,restApi,resultConverter); 52 | } 53 | } 54 | 55 | private QueryResult handleError(Object result) { 56 | if (result instanceof Map) { 57 | Map mapResult = (Map) result; 58 | if (RestResultException.isExceptionResult(mapResult)) { 59 | throw new RestResultException(mapResult); 60 | } 61 | } 62 | throw new RestResultException(Collections.singletonMap("exception", result.toString())); 63 | } 64 | 65 | public static class RestQueryResult implements QueryResult { 66 | QueryResultBuilder result; 67 | private final RestAPI restApi; 68 | 69 | 70 | @Override 71 | public ConvertedResult to(Class type) { 72 | return result.to(type); 73 | } 74 | 75 | @Override 76 | public ConvertedResult to(Class type, ResultConverter converter) { 77 | return result.to(type,converter); 78 | } 79 | 80 | @Override 81 | public void handle(Handler handler) { 82 | result.handle(handler); 83 | } 84 | 85 | @Override 86 | public Iterator iterator() { 87 | return result.iterator(); 88 | } 89 | 90 | public RestQueryResult(Object result, RestAPI restApi, ResultConverter resultConverter) { 91 | this.restApi = restApi; 92 | final Iterable convertedResult = convertRestResult(result); 93 | this.result=new QueryResultBuilder(convertedResult, resultConverter); 94 | } 95 | 96 | private Iterable convertRestResult(Object result) { 97 | final RestEntityExtractor restEntityExtractor = new RestEntityExtractor(restApi); 98 | if (result instanceof Map) { 99 | Map mapResult= (Map) result; 100 | if (RestResultException.isExceptionResult(mapResult)) { 101 | throw new RestResultException(mapResult); 102 | } 103 | if (isTableResult(mapResult)) { 104 | return (Iterable) new RestTableResultExtractor(restEntityExtractor).extract(mapResult); 105 | } 106 | } 107 | if (result instanceof Iterable) { 108 | return new IterableWrapper((Iterable)result) { 109 | @Override 110 | protected T underlyingObjectToObject(Object value) { 111 | return (T) restEntityExtractor.convertFromRepresentation(value); 112 | } 113 | }; 114 | } 115 | return Collections.singletonList((T) restEntityExtractor.convertFromRepresentation(result)); 116 | } 117 | 118 | public static boolean isTableResult(Map mapResult) { 119 | return mapResult.containsKey("columns") && mapResult.containsKey("data"); 120 | } 121 | } 122 | 123 | 124 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/traversal/NodePath.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.traversal; 2 | 3 | import static java.util.Arrays.asList; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | import java.util.Iterator; 8 | 9 | import org.neo4j.graphdb.Node; 10 | import org.neo4j.graphdb.Path; 11 | import org.neo4j.graphdb.PropertyContainer; 12 | import org.neo4j.graphdb.Relationship; 13 | 14 | public class NodePath implements Path { 15 | private final Node node; 16 | 17 | public NodePath(Node node) { 18 | this.node = node; 19 | } 20 | 21 | @Override 22 | public Node startNode() { 23 | return node; 24 | } 25 | 26 | @Override 27 | public Node endNode() { 28 | return node; 29 | } 30 | 31 | @Override 32 | public Relationship lastRelationship() { 33 | return null; 34 | } 35 | 36 | @Override 37 | public Iterable relationships() { 38 | return Collections.emptyList(); 39 | } 40 | 41 | @Override 42 | public Iterable nodes() { 43 | return asList(node); 44 | } 45 | 46 | @Override 47 | public int length() { 48 | return 0; 49 | } 50 | 51 | @Override 52 | public Iterator iterator() { 53 | return Arrays.asList(node).iterator(); 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/traversal/RelationshipPath.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.traversal; 2 | 3 | import static java.util.Arrays.asList; 4 | 5 | import java.util.Arrays; 6 | import java.util.Iterator; 7 | 8 | import org.neo4j.graphdb.Node; 9 | import org.neo4j.graphdb.Path; 10 | import org.neo4j.graphdb.PropertyContainer; 11 | import org.neo4j.graphdb.Relationship; 12 | 13 | public class RelationshipPath implements Path { 14 | private final Relationship relationship; 15 | 16 | public RelationshipPath(Relationship relationship) { 17 | this.relationship = relationship; 18 | } 19 | 20 | @Override 21 | public Node startNode() { 22 | return relationship.getStartNode(); 23 | } 24 | 25 | @Override 26 | public Node endNode() { 27 | return relationship.getEndNode(); 28 | } 29 | 30 | @Override 31 | public Relationship lastRelationship() { 32 | return relationship; 33 | } 34 | 35 | @Override 36 | public Iterable relationships() { 37 | return asList(relationship); 38 | } 39 | 40 | @Override 41 | public Iterable nodes() { 42 | return asList(startNode(),endNode()); 43 | } 44 | 45 | @Override 46 | public int length() { 47 | return 1; 48 | } 49 | 50 | @Override 51 | public Iterator iterator() { 52 | return Arrays.asList(startNode(), lastRelationship(), endNode()).iterator(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/traversal/RestDirection.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.traversal; 2 | 3 | import org.neo4j.graphdb.Direction; 4 | 5 | public enum RestDirection { 6 | INCOMING( Direction.INCOMING, "incoming", "in" ), 7 | OUTGOING( Direction.OUTGOING, "outgoing", "out" ), 8 | BOTH( Direction.BOTH, "all", "all" ); 9 | 10 | public final Direction direction; 11 | public final String longName; 12 | public final String shortName; 13 | 14 | RestDirection( Direction direction, String longName, String shortName ) { 15 | this.direction = direction; 16 | this.longName = longName; 17 | this.shortName = shortName; 18 | } 19 | 20 | public static RestDirection from( Direction direction ) { 21 | for ( RestDirection restDirection : values() ) { 22 | if ( restDirection.direction == direction ) return restDirection; 23 | } 24 | throw new RuntimeException( "No Rest-Direction for " + direction ); 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/traversal/RestPathParser.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.traversal; 2 | 3 | import org.neo4j.graphdb.Node; 4 | import org.neo4j.graphdb.Path; 5 | import org.neo4j.graphdb.Relationship; 6 | import org.neo4j.helpers.collection.IterableWrapper; 7 | import org.neo4j.rest.graphdb.RestAPI; 8 | import org.neo4j.rest.graphdb.entity.RestNode; 9 | import org.neo4j.rest.graphdb.entity.RestRelationship; 10 | 11 | import java.util.Collection; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * @author Michael Hunger 17 | * @since 03.02.11 18 | */ 19 | public class RestPathParser { 20 | public static Path parse(Map path, final RestAPI restApi) { 21 | final Collection> nodesData = (Collection>) path.get("nodes"); 22 | final Collection> relationshipsData = (Collection>) path.get("relationships"); 23 | final Map lastRelationshipData = lastElement(relationshipsData); 24 | final Map startData = (Map) path.get("start"); 25 | final Map endData = (Map) path.get("end"); 26 | final Integer length = (Integer) path.get("length"); 27 | 28 | return new SimplePath( 29 | new RestNode(startData,restApi), 30 | new RestNode(endData,restApi), 31 | new RestRelationship(lastRelationshipData,restApi), 32 | length, 33 | new IterableWrapper>(nodesData) { 34 | @Override 35 | protected Node underlyingObjectToObject(Map data) { 36 | return new RestNode(data,restApi); 37 | } 38 | }, 39 | new IterableWrapper>(relationshipsData) { 40 | @Override 41 | protected Relationship underlyingObjectToObject(Map data) { 42 | return new RestRelationship(data,restApi); 43 | } 44 | }); 45 | } 46 | 47 | private static Map lastElement(Collection> collection) { 48 | if (collection.isEmpty()) return null; 49 | if (collection instanceof List) { 50 | List> list = (List>) collection; 51 | return list.get(list.size()-1); 52 | } 53 | Map result = null; 54 | for (Map value : collection) { 55 | result=value; 56 | } 57 | return result; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/traversal/RestTraversal.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.traversal; 2 | 3 | import org.neo4j.graphdb.*; 4 | import org.neo4j.graphdb.traversal.*; 5 | import org.neo4j.graphdb.traversal.Traverser; 6 | import org.neo4j.helpers.Predicate; 7 | import org.neo4j.kernel.Traversal; 8 | import org.neo4j.kernel.Uniqueness; 9 | import org.neo4j.rest.graphdb.RequestResult; 10 | import org.neo4j.rest.graphdb.RestRequest; 11 | import org.neo4j.rest.graphdb.entity.RestNode; 12 | 13 | import javax.ws.rs.core.Response; 14 | import java.lang.reflect.Field; 15 | import java.util.*; 16 | 17 | /** 18 | * @author Michael Hunger 19 | * @since 02.02.11 20 | */ 21 | public class RestTraversal implements RestTraversalDescription { 22 | 23 | private static final String FULLPATH = "fullpath"; 24 | private final Map description=new HashMap(); 25 | 26 | @Override 27 | public String toString() { 28 | return description.toString(); 29 | } 30 | 31 | public RestTraversalDescription uniqueness(UniquenessFactory uniquenessFactory) { 32 | return uniqueness(uniquenessFactory,null); 33 | } 34 | 35 | public RestTraversalDescription uniqueness(UniquenessFactory uniquenessFactory, Object value) { 36 | String uniqueness = restify(uniquenessFactory); 37 | add("uniqueness",value==null ? uniqueness : toMap("name",uniqueness, "value", value)); 38 | return null; 39 | } 40 | 41 | private String restify(UniquenessFactory uniquenessFactory) { 42 | if (uniquenessFactory instanceof Uniqueness) { 43 | return ((Uniqueness)uniquenessFactory).name().toLowerCase().replace("_"," "); 44 | } 45 | throw new UnsupportedOperationException("Only values of "+Uniqueness.class+" are supported"); 46 | } 47 | 48 | public RestTraversalDescription prune(PruneEvaluator pruneEvaluator) { 49 | if (pruneEvaluator == PruneEvaluator.NONE) { 50 | return add( "prune_evaluator", toMap( "language", "builtin", "name", "none" ) ); 51 | } 52 | Integer maxDepth= getMaxDepthValueOrNull(pruneEvaluator); 53 | if (maxDepth!=null) { 54 | return maxDepth(maxDepth); 55 | } 56 | throw new UnsupportedOperationException("Only max depth supported"); 57 | } 58 | 59 | private Integer getMaxDepthValueOrNull(PruneEvaluator pruneEvaluator) { 60 | try { 61 | final Field depthField = pruneEvaluator.getClass().getDeclaredField("val$depth"); 62 | depthField.setAccessible(true); 63 | return (Integer) depthField.get(pruneEvaluator); 64 | } catch (Exception e) { 65 | return null; 66 | } 67 | } 68 | 69 | public RestTraversalDescription filter(Predicate pathPredicate) { 70 | if (pathPredicate == Traversal.returnAll()) return add("return_filter",toMap("language","builtin", "name","all")); 71 | if (pathPredicate == Traversal.returnAllButStartNode()) return add("return_filter",toMap("language","builtin", "name","all_but_start_node")); 72 | throw new UnsupportedOperationException("Only builtin paths supported"); 73 | } 74 | 75 | public RestTraversalDescription evaluator(Evaluator evaluator) { 76 | throw new UnsupportedOperationException(); 77 | } 78 | 79 | public RestTraversalDescription prune(ScriptLanguage language, String code) { 80 | return add("prune_evaluator",toMap("language",language.name().toLowerCase(),"body",code )); 81 | } 82 | 83 | public RestTraversalDescription filter(ScriptLanguage language, String code) { 84 | return add("return_filter",toMap("language",language.name().toLowerCase(),"body",code )); 85 | } 86 | 87 | public RestTraversalDescription maxDepth(int depth) { 88 | return add("max_depth",depth); 89 | } 90 | 91 | public RestTraversalDescription order(BranchOrderingPolicy branchOrderingPolicy) { 92 | throw new UnsupportedOperationException(); 93 | } 94 | 95 | public RestTraversalDescription depthFirst() { 96 | return add("order","depth_first"); 97 | } 98 | 99 | public RestTraversalDescription breadthFirst() { 100 | return add("order", "breadth_first"); 101 | } 102 | 103 | private RestTraversalDescription add(String key, Object value) { 104 | description.put(key,value); 105 | return this; 106 | } 107 | 108 | public RestTraversalDescription relationships(RelationshipType relationshipType) { 109 | return relationships(relationshipType, null); 110 | } 111 | 112 | public RestTraversalDescription relationships(RelationshipType relationshipType, Direction direction) { 113 | if (!description.containsKey("relationships")) { 114 | description.put("relationships",new HashSet>()); 115 | } 116 | Set> relationships= (Set>) description.get("relationships"); 117 | relationships.add(toMap("type", relationshipType, "direction", directionString(direction))); 118 | return this; 119 | } 120 | 121 | private Map toMap(Object...params) { 122 | if (params.length % 2 != 0) throw new IllegalArgumentException("toMap needs an even number of arguments, but was "+Arrays.toString(params)); 123 | 124 | Map result = new HashMap(); 125 | for (int i = 0; i < params.length; i+=2) { 126 | if (params[i+1] == null) continue; 127 | result.put(params[i].toString(), params[i + 1].toString()); 128 | } 129 | return result; 130 | } 131 | 132 | private String directionString(Direction direction) { 133 | return RestDirection.from(direction).shortName; 134 | } 135 | 136 | public RestTraversalDescription expand(RelationshipExpander relationshipExpander) { 137 | return null; 138 | } 139 | 140 | public Traverser traverse(Node node) { 141 | final RestNode restNode = (RestNode) node; 142 | final RestRequest request = restNode.getRestRequest(); 143 | final RequestResult result = request.post("traverse/" + FULLPATH, description); 144 | if (result.statusOtherThan(Response.Status.OK)) throw new RuntimeException(String.format("Error executing traversal: %d %s",result.getStatus(), description)); 145 | final Object col = result.toEntity(); 146 | if (!(col instanceof Collection)) throw new RuntimeException(String.format("Unexpected traversal result, %s instead of collection", col!=null ? col.getClass() : null)); 147 | return new RestTraverser((Collection) col,restNode.getRestApi()); 148 | } 149 | 150 | public static RestTraversalDescription description() { 151 | return new RestTraversal(); 152 | } 153 | 154 | public Map getPostData() { 155 | return description; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/traversal/RestTraversalDescription.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.traversal; 2 | 3 | import org.neo4j.graphdb.Direction; 4 | import org.neo4j.graphdb.Path; 5 | import org.neo4j.graphdb.RelationshipType; 6 | import org.neo4j.graphdb.traversal.PruneEvaluator; 7 | import org.neo4j.graphdb.traversal.TraversalDescription; 8 | import org.neo4j.helpers.Predicate; 9 | 10 | /** 11 | * @author Michael Hunger 12 | * @since 03.02.11 13 | */ 14 | public interface RestTraversalDescription extends TraversalDescription { 15 | RestTraversalDescription prune(ScriptLanguage language, String code); 16 | 17 | RestTraversalDescription prune(PruneEvaluator pruneEvaluator); 18 | 19 | RestTraversalDescription filter(ScriptLanguage language, String code); 20 | 21 | RestTraversalDescription maxDepth(int depth); 22 | 23 | RestTraversalDescription breadthFirst(); 24 | 25 | RestTraversalDescription relationships(RelationshipType relationshipType, Direction direction); 26 | 27 | RestTraversalDescription filter(Predicate pathPredicate); 28 | 29 | 30 | public enum ScriptLanguage { 31 | JAVASCRIPT; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/traversal/RestTraverser.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.traversal; 2 | 3 | import org.neo4j.graphdb.Node; 4 | import org.neo4j.graphdb.Path; 5 | import org.neo4j.graphdb.Relationship; 6 | import org.neo4j.graphdb.traversal.Traverser; 7 | import org.neo4j.helpers.collection.IterableWrapper; 8 | import org.neo4j.rest.graphdb.RestAPI; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | import java.util.Iterator; 13 | import java.util.Map; 14 | 15 | /** 16 | * @author Michael Hunger 17 | * @since 03.02.11 18 | */ 19 | public class RestTraverser implements Traverser { 20 | private final Collection paths; 21 | public RestTraverser(Collection col, RestAPI restApi) { 22 | this.paths = parseToPaths(col, restApi); 23 | } 24 | 25 | private Collection parseToPaths(Collection col, RestAPI restApi) { 26 | Collection result=new ArrayList(col.size()); 27 | for (Object path : col) { 28 | if (!(path instanceof Map)) throw new RuntimeException("Expected Map for Path representation but got: "+(path!=null ? path.getClass() : null)); 29 | result.add(RestPathParser.parse((Map) path, restApi)); 30 | } 31 | return result; 32 | } 33 | 34 | public Iterable nodes() { 35 | return new IterableWrapper(paths) { 36 | @Override 37 | protected Node underlyingObjectToObject(Path path) { 38 | return path.endNode(); 39 | } 40 | }; 41 | } 42 | 43 | public Iterable relationships() { 44 | return new IterableWrapper(paths) { 45 | @Override 46 | protected Relationship underlyingObjectToObject(Path path) { 47 | return path.lastRelationship(); 48 | } 49 | }; 50 | } 51 | 52 | public Iterator iterator() { 53 | return paths.iterator(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/traversal/SimplePath.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.traversal; 2 | 3 | import org.neo4j.graphdb.Node; 4 | import org.neo4j.graphdb.Path; 5 | import org.neo4j.graphdb.PropertyContainer; 6 | import org.neo4j.graphdb.Relationship; 7 | 8 | import java.util.Iterator; 9 | 10 | /** 11 | * @author Michael Hunger 12 | * @since 03.02.11 13 | */ 14 | public class SimplePath implements Path { 15 | Iterable relationships; 16 | Iterable nodes; 17 | private final Relationship lastRelationship; 18 | private int length; 19 | private Node startNode; 20 | private Node endNode; 21 | 22 | public SimplePath(Node startNode, Node endNode, Relationship lastRelationship, int length, Iterable nodes, Iterable relationships) { 23 | this.startNode = startNode; 24 | this.endNode = endNode; 25 | this.lastRelationship = lastRelationship; 26 | this.length = length; 27 | this.nodes = nodes; 28 | this.relationships = relationships; 29 | } 30 | 31 | public Node startNode() { 32 | return startNode; 33 | } 34 | 35 | public Node endNode() { 36 | return endNode; 37 | } 38 | 39 | public Relationship lastRelationship() { 40 | return lastRelationship; 41 | } 42 | 43 | public Iterable relationships() { 44 | return relationships; 45 | } 46 | 47 | public Iterable nodes() { 48 | return nodes; 49 | } 50 | 51 | public int length() { 52 | return length; 53 | } 54 | 55 | public Iterator iterator() { 56 | return new Iterator() 57 | { 58 | Iterator current = nodes().iterator(); 59 | Iterator next = relationships().iterator(); 60 | 61 | public boolean hasNext() 62 | { 63 | return current.hasNext(); 64 | } 65 | 66 | public PropertyContainer next() 67 | { 68 | try 69 | { 70 | return current.next(); 71 | } 72 | finally 73 | { 74 | Iterator temp = current; 75 | current = next; 76 | next = temp; 77 | } 78 | } 79 | 80 | public void remove() 81 | { 82 | next.remove(); 83 | } 84 | }; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/ArrayConverter.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.Collection; 5 | 6 | /** 7 | * @author Michael Hunger 8 | * @since 02.02.11 9 | */ 10 | public class ArrayConverter { 11 | public Object toArray(Collection col) { 12 | Object entry = getNonNullEntry(col); 13 | if (entry==null) return null; 14 | Class elementClass = getArrayElementClass( entry ); 15 | Object array = Array.newInstance(elementClass, col.size()); 16 | if (Object.class.isAssignableFrom( elementClass)) { 17 | col.toArray( (Object[])array ); 18 | } else { 19 | int i=0; 20 | for ( Object value : col ) { 21 | setArrayValue(array,i,value,elementClass); 22 | i+=1; 23 | } 24 | } 25 | return array; 26 | } 27 | 28 | private void setArrayValue( Object array, int i, Object value, Class type ) { 29 | if (value==null) return; 30 | if ( value instanceof Number ) { 31 | Number number = (Number) value; 32 | if (type.equals( int.class )) { Array.setInt( array, i, number.intValue()); return;} 33 | if (type.equals( long.class )) { Array.setLong( array, i, number.longValue()); return;} 34 | if (type.equals( double.class )) { Array.setDouble( array, i, number.doubleValue()); return;} 35 | if (type.equals( float.class )) { Array.setFloat( array, i, number.floatValue()); return;} 36 | if (type.equals( byte.class )) { Array.setByte( array, i, number.byteValue()); return;} 37 | if (type.equals( short.class )) { Array.setShort( array, i, number.shortValue()); return;} 38 | } 39 | if (type.equals( char.class )) { Array.setChar( array, i, (Character)value ); return;} 40 | if (type.equals( boolean.class )) { Array.setBoolean( array, i, (Boolean) value ); return;} 41 | } 42 | 43 | private Class getArrayElementClass( Object entry ) { 44 | Class type = entry.getClass(); 45 | if (type.equals( Integer.class )) return int.class; 46 | if (type.equals( Long.class )) return long.class; 47 | if (type.equals( Double.class )) return double.class; 48 | if (type.equals( Float.class )) return float.class; 49 | if (type.equals( Byte.class )) return byte.class; 50 | if (type.equals( Short.class )) return short.class; 51 | if (type.equals( Character.class )) return char.class; 52 | if (type.equals( Boolean.class )) return boolean.class; 53 | return type; 54 | } 55 | 56 | private Object getNonNullEntry(Collection col) { 57 | for ( Object entry : col ) { 58 | if (entry!=null) return entry; 59 | } 60 | return null; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/ConvertedResult.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | 4 | public interface ConvertedResult extends Iterable { 5 | R single(); 6 | void handle(Handler handler); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/DefaultConverter.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map; 5 | 6 | import org.neo4j.graphdb.Node; 7 | import org.neo4j.graphdb.Path; 8 | import org.neo4j.graphdb.Relationship; 9 | import org.neo4j.rest.graphdb.traversal.NodePath; 10 | import org.neo4j.rest.graphdb.traversal.RelationshipPath; 11 | 12 | 13 | public class DefaultConverter implements ResultConverter { 14 | public R convert(Object value, Class type) { 15 | if (value == null || type.isInstance(value)) return (R) value; 16 | Object singleValue = extractValue(value); 17 | if (singleValue == null || type.isInstance(singleValue)) return (R) singleValue; 18 | final Class sourceType = singleValue.getClass(); 19 | Object result = doConvert(singleValue, sourceType, type); 20 | if (result == null) 21 | throw new RuntimeException("Cannot automatically convert " + sourceType + " to " + type + " please use a custom converter"); 22 | return (R) result; 23 | } 24 | 25 | protected Object extractValue(Object value) { 26 | if (value instanceof Map) return extractSingle(((Map)value).values()); 27 | if (value instanceof Iterable) return extractSingle((Iterable)value); 28 | return value; 29 | } 30 | 31 | private Object extractSingle(Iterable values) { 32 | final Iterator it = values.iterator(); 33 | if (!it.hasNext()) throw new RuntimeException("Cannot extract single value from empty Iterable."); 34 | final Object result = it.next(); 35 | if (it.hasNext()) throw new RuntimeException("Cannot extract single value from Iterable with more than one elements."); 36 | return result; 37 | } 38 | 39 | protected Object doConvert(Object value, Class sourceType, Class type) { 40 | if (Node.class.isAssignableFrom(type)) { 41 | return toNode(value, sourceType); 42 | } 43 | if (Relationship.class.isAssignableFrom(type)) { 44 | return toRelationship(value, sourceType); 45 | } 46 | if (Path.class.isAssignableFrom(type)) { 47 | return toPath(value, sourceType); 48 | } 49 | if (type.isEnum()) { 50 | return Enum.valueOf(type, value.toString()); 51 | } 52 | return null; 53 | } 54 | 55 | protected Path toPath(Object value, Class sourceType) { 56 | if (Node.class.isAssignableFrom(sourceType)) return new NodePath((Node) value); 57 | if (Relationship.class.isAssignableFrom(sourceType)) return new RelationshipPath((Relationship) value); 58 | return null; 59 | } 60 | 61 | protected Relationship toRelationship(Object value, Class sourceType) { 62 | if (Relationship.class.isAssignableFrom(sourceType)) return ((Relationship) value); 63 | if (Path.class.isAssignableFrom(sourceType)) return ((Path) value).lastRelationship(); 64 | if (Node.class.isAssignableFrom(sourceType)) return ((Node) value).getRelationships().iterator().next(); 65 | return null; 66 | } 67 | 68 | protected Node toNode(Object value, Class sourceType) { 69 | if (Node.class.isAssignableFrom(sourceType)) return (Node)value; 70 | if (Path.class.isAssignableFrom(sourceType)) return ((Path) value).endNode(); 71 | if (Relationship.class.isAssignableFrom(sourceType)) return ((Relationship) value).getEndNode(); 72 | return null; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/Handler.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | public interface Handler { 4 | void handle(R value); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/JsonHelper.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | /** 4 | * @author mh 5 | * @since 13.12.10 6 | */ 7 | 8 | import org.codehaus.jackson.JsonGenerator; 9 | import org.codehaus.jackson.map.ObjectMapper; 10 | import org.neo4j.rest.graphdb.PropertiesMap; 11 | 12 | import java.io.IOException; 13 | import java.io.StringWriter; 14 | import java.util.Collection; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | public class JsonHelper { 19 | 20 | static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); 21 | 22 | @SuppressWarnings("unchecked") 23 | public static Map jsonToMap( String json ) { 24 | return (Map) readJson( json ); 25 | } 26 | 27 | @SuppressWarnings("unchecked") 28 | public static List> jsonToListOfRelationshipRepresentations( String json ) { 29 | return (List>) readJson( json ); 30 | } 31 | 32 | public static Object readJson( String json ) { 33 | ObjectMapper mapper = new ObjectMapper(); 34 | try { 35 | return mapper.readValue( json, Object.class ); 36 | } catch ( IOException e ) { 37 | throw new RuntimeException( e ); 38 | } 39 | } 40 | 41 | public static Object jsonToSingleValue( String json ) { 42 | Object jsonObject = readJson( json ); 43 | return jsonObject instanceof Collection ? jsonObject : 44 | PropertiesMap.assertSupportedPropertyValue( jsonObject ); 45 | } 46 | 47 | public static String createJsonFrom( Object data ) { 48 | try { 49 | StringWriter writer = new StringWriter(); 50 | JsonGenerator generator = OBJECT_MAPPER.getJsonFactory() 51 | .createJsonGenerator( writer ).useDefaultPrettyPrinter(); 52 | OBJECT_MAPPER.writeValue( generator, data ); 53 | writer.close(); 54 | return writer.getBuffer().toString(); 55 | } catch ( IOException e ) { 56 | throw new RuntimeException( e ); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/QueryResult.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | 4 | public interface QueryResult extends Iterable { 5 | ConvertedResult to(Class type); 6 | ConvertedResult to(Class type, ResultConverter resultConverter); 7 | void handle(Handler handler); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/QueryResultBuilder.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map; 5 | 6 | import org.neo4j.graphdb.index.IndexHits; 7 | import org.neo4j.helpers.collection.ClosableIterable; 8 | import org.neo4j.helpers.collection.IteratorWrapper; 9 | 10 | 11 | public class QueryResultBuilder implements QueryResult { 12 | private Iterable result; 13 | private final ResultConverter defaultConverter; 14 | private final boolean isClosableIterable; 15 | private boolean isClosed; 16 | 17 | public QueryResultBuilder(Iterable result) { 18 | this(result, new DefaultConverter()); 19 | } 20 | 21 | public QueryResultBuilder(Iterable result, final ResultConverter defaultConverter) { 22 | this.result = result; 23 | this.isClosableIterable = result instanceof IndexHits || result instanceof ClosableIterable; 24 | this.defaultConverter = defaultConverter; 25 | } 26 | 27 | public static String replaceParams(String statement, Map params) { 28 | if (params==null || params.isEmpty()) return statement; 29 | for (Map.Entry param : params.entrySet()) { 30 | statement = statement.replaceAll("%"+param.getKey()+"\\b",""+param.getValue()); 31 | } 32 | return statement; 33 | } 34 | 35 | @Override 36 | public ConvertedResult to(Class type) { 37 | return this.to(type, defaultConverter); 38 | } 39 | 40 | @Override 41 | public ConvertedResult to(final Class type, final ResultConverter resultConverter) { 42 | return new ConvertedResult() { 43 | @Override 44 | public R single() { 45 | try { 46 | final Iterator it = result.iterator(); 47 | if (!it.hasNext()) throw new IllegalStateException("Expected at least one result, got none."); 48 | final T value = it.next(); 49 | if (it.hasNext()) 50 | throw new IllegalStateException("Expected at least one result, got more than one."); 51 | return resultConverter.convert(value, type); 52 | } finally { 53 | closeIfNeeded(); 54 | } 55 | } 56 | 57 | @Override 58 | public void handle(Handler handler) { 59 | try { 60 | for (T value : result) { 61 | handler.handle(resultConverter.convert(value, type)); 62 | } 63 | } finally { 64 | closeIfNeeded(); 65 | } 66 | } 67 | 68 | @Override 69 | public Iterator iterator() { 70 | return new IteratorWrapper(result.iterator()) { 71 | protected R underlyingObjectToObject(T value) { 72 | return resultConverter.convert(value, type); 73 | } 74 | }; 75 | } 76 | }; 77 | } 78 | 79 | @Override 80 | public void handle(Handler handler) { 81 | try { 82 | for (T value : result) { 83 | handler.handle(value); 84 | } 85 | } finally { 86 | closeIfNeeded(); 87 | } 88 | } 89 | 90 | 91 | private void closeIfNeeded() { 92 | if (isClosableIterable && !isClosed) { 93 | if (result instanceof IndexHits) { 94 | ((IndexHits) result).close(); 95 | } else if (result instanceof ClosableIterable) { 96 | ((ClosableIterable) result).close(); 97 | } 98 | isClosed=true; 99 | } 100 | } 101 | 102 | @Override 103 | public Iterator iterator() { 104 | return result.iterator(); 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/ResultConverter.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | public interface ResultConverter { 4 | R convert(T value, Class type); 5 | 6 | ResultConverter NO_OP_RESULT_CONVERTER = new ResultConverter() { 7 | @Override 8 | public Object convert(Object value, Class type) { 9 | return null; 10 | } 11 | }; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/neo4j/rest/graphdb/util/TestHelper.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb.util; 2 | 3 | import org.neo4j.graphdb.Node; 4 | import org.neo4j.graphdb.Relationship; 5 | 6 | public class TestHelper { 7 | 8 | public static Relationship firstRelationshipBetween( Iterable relationships, final Node startNode, final Node endNode ) { 9 | for ( Relationship relationship : relationships ) { 10 | if ( relationship.getOtherNode( startNode ).equals( endNode ) ) return relationship; 11 | } 12 | return null; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/BatchRestAPITest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.neo4j.graphdb.Direction; 7 | import org.neo4j.graphdb.Node; 8 | import org.neo4j.graphdb.Relationship; 9 | import org.neo4j.graphdb.index.Index; 10 | import org.neo4j.graphdb.index.IndexHits; 11 | import org.neo4j.rest.graphdb.batch.BatchCallback; 12 | import org.neo4j.rest.graphdb.entity.RestRelationship; 13 | import org.neo4j.rest.graphdb.util.TestHelper; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertThat; 17 | import static org.neo4j.helpers.collection.MapUtil.map; 18 | 19 | public class BatchRestAPITest extends RestTestBase { 20 | private RestAPI restAPI; 21 | 22 | // TODO transaction check, exception handling if an exception happened in the server 23 | 24 | @Before 25 | public void init(){ 26 | this.restAPI = ((RestGraphDatabase)getRestGraphDb()).getRestAPI(); 27 | } 28 | 29 | @Test 30 | public void testCreateNode(){ 31 | TestBatchResult response =this.restAPI.executeBatch(new BatchCallback() { 32 | 33 | @Override 34 | public TestBatchResult recordBatch(RestAPI batchRestApi) { 35 | TestBatchResult result=new TestBatchResult(); 36 | result.n1 = batchRestApi.createNode(map("name", "node1")); 37 | result.n2 = batchRestApi.createNode(map("name", "node2")); 38 | return result; 39 | } 40 | }); 41 | 42 | assertEquals("node1", response.n1.getProperty("name")); 43 | assertEquals("node2", response.n2.getProperty("name")); 44 | } 45 | 46 | @Test(expected = IllegalStateException.class) 47 | public void testLeakedBatchApiWontWork() { 48 | RestAPI leaked =this.restAPI.executeBatch(new BatchCallback() { 49 | @Override 50 | public RestAPI recordBatch(RestAPI batchRestApi) { 51 | return batchRestApi; 52 | } 53 | }); 54 | leaked.createNode(map()); 55 | } 56 | 57 | @Test 58 | public void testCreateRelationship(){ 59 | TestBatchResult r = this.restAPI.executeBatch(new BatchCallback() { 60 | @Override 61 | public TestBatchResult recordBatch(RestAPI batchRestApi) { 62 | TestBatchResult result=new TestBatchResult(); 63 | result.n1 = batchRestApi.createNode(map("name", "newnode1")); 64 | result.n2 = batchRestApi.createNode(map("name", "newnode2")); 65 | result.rel = batchRestApi.createRelationship(result.n1, result.n2, Type.TEST, map("name", "rel") ); 66 | result.allRelationships = result.n1.getRelationships(); 67 | return result; 68 | } 69 | }); 70 | 71 | Relationship foundRelationship = TestHelper.firstRelationshipBetween( r.n1.getRelationships(Type.TEST, Direction.OUTGOING), r.n1, r.n2); 72 | Assert.assertNotNull("found relationship", foundRelationship); 73 | assertEquals("same relationship", r.rel, foundRelationship); 74 | assertEquals("rel", r.rel.getProperty("name")); 75 | 76 | assertThat(r.n1.getRelationships(Type.TEST, Direction.OUTGOING), new IsRelationshipToNodeMatcher(r.n1, r.n2)); 77 | assertThat(r.n1.getRelationships(Direction.OUTGOING), new IsRelationshipToNodeMatcher(r.n1, r.n2)); 78 | assertThat(r.n1.getRelationships(Direction.BOTH), new IsRelationshipToNodeMatcher(r.n1, r.n2)); 79 | assertThat(r.n1.getRelationships(Type.TEST), new IsRelationshipToNodeMatcher(r.n1, r.n2)); 80 | assertThat(r.allRelationships, new IsRelationshipToNodeMatcher(r.n1, r.n2)); 81 | } 82 | 83 | @Test 84 | public void testQueryIndex() { 85 | final MatrixDataGraph matrixDataGraph = new MatrixDataGraph(getGraphDatabase()); 86 | matrixDataGraph.createNodespace(); 87 | final IndexHits heroes = restAPI.executeBatch(new BatchCallback>() { 88 | @Override 89 | public IndexHits recordBatch(RestAPI batchRestApi) { 90 | final Index index = batchRestApi.index().forNodes("heroes"); 91 | return index.query("name:Neo"); 92 | } 93 | }); 94 | assertEquals("1 hero",1,heroes.size()); 95 | assertEquals("Neo indexed",matrixDataGraph.getNeoNode(),heroes.iterator().next()); 96 | } 97 | static class TestBatchResult { 98 | Node n1; 99 | Node n2; 100 | RestRelationship rel; 101 | Iterable allRelationships; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/IsRelationshipToNodeMatcher.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.hamcrest.Description; 4 | import org.junit.internal.matchers.TypeSafeMatcher; 5 | import org.neo4j.graphdb.Node; 6 | import org.neo4j.graphdb.Relationship; 7 | import org.neo4j.rest.graphdb.util.TestHelper; 8 | 9 | /** 10 | * @author mh 11 | * @since 24.01.11 12 | */ 13 | class IsRelationshipToNodeMatcher extends TypeSafeMatcher> { 14 | private final Node startNode; 15 | private final Node endNode; 16 | 17 | public IsRelationshipToNodeMatcher( Node startNode, Node endNode ) { 18 | this.startNode = startNode; 19 | this.endNode = endNode; 20 | } 21 | 22 | @Override 23 | public boolean matchesSafely( Iterable relationships ) { 24 | return TestHelper.firstRelationshipBetween( relationships, startNode, endNode ) != null; 25 | } 26 | 27 | public void describeTo( Description description ) { 28 | description.appendValue( startNode ).appendText( " to " ).appendValue( endNode ).appendText( "not contained in relationships" ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/LocalTestServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.neo4j.rest.graphdb; 18 | 19 | import org.apache.commons.configuration.Configuration; 20 | import org.mortbay.component.LifeCycle; 21 | import org.mortbay.jetty.Server; 22 | import org.neo4j.graphdb.GraphDatabaseService; 23 | import org.neo4j.kernel.AbstractGraphDatabase; 24 | import org.neo4j.server.AddressResolver; 25 | import org.neo4j.server.Bootstrapper; 26 | import org.neo4j.server.NeoServerWithEmbeddedWebServer; 27 | import org.neo4j.server.configuration.PropertyFileConfigurator; 28 | import org.neo4j.server.database.Database; 29 | import org.neo4j.server.database.GraphDatabaseFactory; 30 | import org.neo4j.server.modules.RESTApiModule; 31 | import org.neo4j.server.modules.ServerModule; 32 | import org.neo4j.server.modules.ThirdPartyJAXRSModule; 33 | import org.neo4j.server.startup.healthcheck.StartupHealthCheck; 34 | import org.neo4j.server.startup.healthcheck.StartupHealthCheckRule; 35 | import org.neo4j.server.web.Jetty6WebServer; 36 | import org.neo4j.test.ImpermanentGraphDatabase; 37 | 38 | import java.io.File; 39 | import java.io.IOException; 40 | import java.net.URI; 41 | import java.net.URL; 42 | import java.util.Arrays; 43 | import java.util.Collections; 44 | import java.util.List; 45 | import java.util.Map; 46 | import java.util.concurrent.CountDownLatch; 47 | import java.util.concurrent.TimeUnit; 48 | 49 | /** 50 | * @author mh 51 | * @since 24.03.11 52 | */ 53 | public class LocalTestServer { 54 | private NeoServerWithEmbeddedWebServer neoServer; 55 | private final int port; 56 | private final String hostname; 57 | protected String propertiesFile = "test-db.properties"; 58 | 59 | public LocalTestServer() { 60 | this("localhost",7473); 61 | } 62 | 63 | public LocalTestServer(String hostname, int port) { 64 | this.port = port; 65 | this.hostname = hostname; 66 | } 67 | 68 | public void start() { 69 | if (neoServer!=null) throw new IllegalStateException("Server already running"); 70 | URL url = getClass().getResource("/" + propertiesFile); 71 | if (url==null) throw new IllegalArgumentException("Could not resolve properties file "+propertiesFile); 72 | final List> serverModules = Arrays.asList(RESTApiModule.class, ThirdPartyJAXRSModule.class); 73 | final Bootstrapper bootstrapper = new Bootstrapper() { 74 | @Override 75 | protected GraphDatabaseFactory getGraphDatabaseFactory(Configuration configuration) { 76 | return new GraphDatabaseFactory() { 77 | @Override 78 | public AbstractGraphDatabase createDatabase(String databaseStoreDirectory, Map databaseProperties) { 79 | try { 80 | return new ImpermanentGraphDatabase(); 81 | } catch (IOException e) { 82 | throw new RuntimeException(e); 83 | } 84 | } 85 | }; 86 | } 87 | 88 | @Override 89 | protected Iterable getHealthCheckRules() { 90 | return Collections.emptyList(); 91 | } 92 | 93 | @Override 94 | protected Iterable> getServerModules() { 95 | return serverModules; 96 | } 97 | }; 98 | final AddressResolver addressResolver = new AddressResolver() { 99 | @Override 100 | public String getHostname() { 101 | return hostname; 102 | } 103 | }; 104 | final Jetty6WebServer jettyWebServer = new Jetty6WebServer() { 105 | @Override 106 | protected void startJetty() { 107 | final Server jettyServer = getJetty(); 108 | jettyServer.setStopAtShutdown(true); 109 | final JettyStartupListener startupListener = new JettyStartupListener(); 110 | jettyServer.getServer().addLifeCycleListener(startupListener); 111 | // System.err.println("jetty is started before notification " + jettyServer.isStarted()); 112 | 113 | super.startJetty(); 114 | 115 | startupListener.await(); 116 | // System.err.println("jetty is started after notification " + jettyServer.isStarted()); 117 | } 118 | }; 119 | neoServer = new NeoServerWithEmbeddedWebServer(bootstrapper 120 | , addressResolver, new StartupHealthCheck(), new PropertyFileConfigurator(new File(url.getPath())), jettyWebServer, serverModules) { 121 | @Override 122 | protected int getWebServerPort() { 123 | return port; 124 | } 125 | }; 126 | neoServer.start(); 127 | } 128 | 129 | public void stop() { 130 | try { 131 | neoServer.stop(); 132 | } catch(Exception e) { 133 | System.err.println("Error stopping server: "+e.getMessage()); 134 | } 135 | neoServer=null; 136 | } 137 | 138 | public int getPort() { 139 | return port; 140 | } 141 | 142 | public String getHostname() { 143 | return hostname; 144 | } 145 | 146 | public LocalTestServer withPropertiesFile(String propertiesFile) { 147 | this.propertiesFile = propertiesFile; 148 | return this; 149 | } 150 | public Database getDatabase() { 151 | return neoServer.getDatabase(); 152 | } 153 | 154 | public URI baseUri() { 155 | return neoServer.baseUri(); 156 | } 157 | 158 | public void cleanDb() { 159 | Neo4jDatabaseCleaner cleaner = new Neo4jDatabaseCleaner(getGraphDatabase()); 160 | cleaner.cleanDb(); 161 | } 162 | 163 | public GraphDatabaseService getGraphDatabase() { 164 | return getDatabase().graph; 165 | } 166 | 167 | private static class JettyStartupListener implements LifeCycle.Listener { 168 | CountDownLatch latch=new CountDownLatch(1); 169 | public void await() { 170 | try { 171 | latch.await(5, TimeUnit.SECONDS); 172 | } catch(InterruptedException ie) { 173 | Thread.currentThread().interrupt(); 174 | throw new RuntimeException(ie); 175 | } 176 | } 177 | 178 | @Override 179 | public void lifeCycleStarting(LifeCycle event) { 180 | } 181 | 182 | @Override 183 | public void lifeCycleStarted(LifeCycle event) { 184 | latch.countDown(); 185 | } 186 | 187 | @Override 188 | public void lifeCycleFailure(LifeCycle event, Throwable cause) { 189 | latch.countDown(); 190 | throw new RuntimeException(cause); 191 | } 192 | 193 | @Override 194 | public void lifeCycleStopping(LifeCycle event) { 195 | 196 | } 197 | 198 | @Override 199 | public void lifeCycleStopped(LifeCycle event) { 200 | latch.countDown(); 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/MatrixDataGraph.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import java.util.Map; 4 | 5 | import org.neo4j.graphdb.Direction; 6 | import org.neo4j.graphdb.GraphDatabaseService; 7 | import org.neo4j.graphdb.Node; 8 | import org.neo4j.graphdb.Relationship; 9 | import org.neo4j.graphdb.RelationshipType; 10 | import org.neo4j.graphdb.Transaction; 11 | import org.neo4j.graphdb.index.Index; 12 | import org.neo4j.graphdb.index.IndexManager; 13 | import org.neo4j.helpers.collection.MapUtil; 14 | 15 | 16 | /** 17 | * Creates a database using the matrix example for testing purposes 18 | * @author Klemens Burchardi 19 | * @since 03.08.11 20 | */ 21 | public class MatrixDataGraph { 22 | /** specify relationship types*/ 23 | public enum RelTypes implements RelationshipType{ 24 | NEO_NODE, 25 | KNOWS, 26 | FIGHTS, 27 | CODED_BY, 28 | PERSONS_REFERENCE, 29 | HEROES_REFERENCE, 30 | HERO, 31 | VILLAINS_REFERENCE, 32 | VILLAIN 33 | } 34 | 35 | private GraphDatabaseService graphDb; 36 | 37 | public MatrixDataGraph(GraphDatabaseService graphDb){ 38 | this.graphDb = graphDb; 39 | } 40 | 41 | 42 | /** 43 | * fills the database with nodes and relationships, using the matrix example 44 | * @param graphDb the graph database to fill 45 | * @return MatrixDataGraph the instance for chaining purposes 46 | */ 47 | public MatrixDataGraph createNodespace() { 48 | Transaction tx = this.graphDb.beginTx(); 49 | try { 50 | Node referenceNode = this.graphDb.getReferenceNode(); 51 | 52 | //create the index for all characters that are considered good guys (sorry cypher) 53 | IndexManager index = this.graphDb.index(); 54 | Index goodGuys = index.forNodes("heroes"); 55 | //create persons collection node 56 | Node persons = this.graphDb.createNode(); 57 | persons.setProperty("type", "Persons Collection"); 58 | //create heroes collection node 59 | Node heroes = this.graphDb.createNode(); 60 | heroes.setProperty("type", "Heroes Collection"); 61 | //create villains collection node 62 | Node villains = this.graphDb.createNode(); 63 | villains.setProperty("type", "Villains Collection"); 64 | // create neo node 65 | Node neo = this.graphDb.createNode(); 66 | addMultiplePropertiesToNode(neo, MapUtil.map("age",29, "name","Thomas Anderson", "type", "hero")); 67 | 68 | 69 | // connect the persons collection node to the reference node 70 | referenceNode.createRelationshipTo( persons, RelTypes.PERSONS_REFERENCE); 71 | // connect the heroes collection node to the persons collection node 72 | persons.createRelationshipTo( heroes, RelTypes.HEROES_REFERENCE); 73 | // connect the villains collection node to the persons collection node 74 | persons.createRelationshipTo( villains, RelTypes.VILLAINS_REFERENCE); 75 | // connect neo to the reference node 76 | referenceNode.createRelationshipTo( neo, RelTypes.NEO_NODE ); 77 | // connect neo to the heroes collection node 78 | heroes.createRelationshipTo( neo, RelTypes.HERO); 79 | 80 | 81 | // create trinity node 82 | Node trinity = this.graphDb.createNode(); 83 | addMultiplePropertiesToNode(trinity, MapUtil.map("name","Trinity", "type", "hero")); 84 | createRelationshipWithProperties(neo, trinity, RelTypes.KNOWS, MapUtil.map( "age", "3 days")); 85 | 86 | // connect trinity to the heroes collection node 87 | heroes.createRelationshipTo( trinity, RelTypes.HERO); 88 | 89 | // create morpheus node 90 | Node morpheus = this.graphDb.createNode(); 91 | addMultiplePropertiesToNode(morpheus, MapUtil.map( "name","Morpheus", "occupation","Total badass", "rank","Captain", "type","hero")); 92 | neo.createRelationshipTo( morpheus, RelTypes.KNOWS ); 93 | 94 | createRelationshipWithProperties(morpheus, trinity, RelTypes.KNOWS, MapUtil.map( "age", "12 years")); 95 | // connect morpheus to the heroes collection node 96 | heroes.createRelationshipTo( morpheus, RelTypes.HERO); 97 | 98 | //add all good guys to the index 99 | addMultipleNodesToIndex(goodGuys, "name", MapUtil.map("Neo",neo, "Trinity", trinity, "Morpheus", morpheus)); 100 | 101 | // create cypher node 102 | Node cypher = this.graphDb.createNode(); 103 | addMultiplePropertiesToNode(cypher, MapUtil.map("last name","Reagan", "name","Cypher", "type","villain" )); 104 | trinity.createRelationshipTo( cypher, RelTypes.KNOWS ); 105 | createRelationshipWithProperties(morpheus, cypher, RelTypes.KNOWS, MapUtil.map( "disclosure", "public")); 106 | // connect cypher to the villains collection node 107 | villains.createRelationshipTo( cypher, RelTypes.VILLAIN); 108 | 109 | // create smith node 110 | Node smith = this.graphDb.createNode(); 111 | addMultiplePropertiesToNode(smith, MapUtil.map("language","C++", "name","Agent Smith", "version","1.0b", "type","villain")); 112 | neo.createRelationshipTo( smith, RelTypes.FIGHTS ); 113 | createRelationshipWithProperties(cypher, smith, RelTypes.KNOWS, MapUtil.map( "age", "6 months", "disclosure", "secret")); 114 | 115 | // connect smith to the villains collection node 116 | villains.createRelationshipTo( smith, RelTypes.VILLAIN); 117 | 118 | // create architect node 119 | Node architect = this.graphDb.createNode(); 120 | architect.setProperty( "name", "The Architect" ); 121 | smith.createRelationshipTo( architect, RelTypes.CODED_BY ); 122 | 123 | tx.success(); 124 | } finally { 125 | tx.finish(); 126 | 127 | } 128 | return this; 129 | } 130 | 131 | 132 | public void addMultiplePropertiesToNode(Node node, Map props){ 133 | for (Map.Entry entry : props.entrySet()){ 134 | node.setProperty(entry.getKey(), entry.getValue()); 135 | } 136 | } 137 | 138 | public void addMultipleNodesToIndex(Index indexName, String key, Map namedNodes){ 139 | for (Map.Entry entry : namedNodes.entrySet()){ 140 | indexName.add((Node)entry.getValue(), key, entry.getKey()); 141 | } 142 | } 143 | 144 | 145 | public void createRelationshipWithProperties(Node startNode, Node endNode, RelationshipType relType, Map props){ 146 | Relationship rel = startNode.createRelationshipTo(endNode, relType); 147 | for (Map.Entry entry : props.entrySet()){ 148 | rel.setProperty(entry.getKey(), entry.getValue()); 149 | } 150 | } 151 | 152 | public GraphDatabaseService getGraphDatabase() { 153 | return graphDb; 154 | } 155 | 156 | /** 157 | * Get the Neo node. (a.k.a. Thomas Anderson node) 158 | * 159 | * @return the Neo node 160 | */ 161 | public Node getNeoNode() { 162 | return this.graphDb.getReferenceNode().getSingleRelationship( 163 | RelTypes.NEO_NODE, Direction.OUTGOING ).getEndNode(); 164 | } 165 | 166 | /** 167 | * Get the Persons Collection node 168 | * 169 | * @return the Persons Collection node 170 | */ 171 | public Node getPersonsCollectionNode() { 172 | return this.graphDb.getReferenceNode().getSingleRelationship( 173 | RelTypes.PERSONS_REFERENCE, Direction.OUTGOING ).getEndNode(); 174 | } 175 | 176 | /** 177 | * Get the Heroes Collection node 178 | * 179 | * @return the Heroes Collection node 180 | */ 181 | public Node getHeroesCollectionNode() { 182 | return this.getPersonsCollectionNode().getSingleRelationship( 183 | RelTypes.HEROES_REFERENCE, Direction.OUTGOING ).getEndNode(); 184 | } 185 | 186 | /** 187 | * Get the Villains Collection node 188 | * 189 | * @return the Villains Collection node 190 | */ 191 | public Node getVillainsCollectionNode() { 192 | return this.getPersonsCollectionNode().getSingleRelationship( 193 | RelTypes.VILLAINS_REFERENCE, Direction.OUTGOING ).getEndNode(); 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/MatrixDatabaseRestTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import org.junit.Assert; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.neo4j.graphdb.Direction; 12 | import org.neo4j.graphdb.GraphDatabaseService; 13 | import org.neo4j.graphdb.Node; 14 | import org.neo4j.graphdb.Path; 15 | import org.neo4j.graphdb.index.Index; 16 | import org.neo4j.graphdb.index.IndexHits; 17 | import org.neo4j.graphdb.index.IndexManager; 18 | import org.neo4j.graphdb.traversal.Evaluators; 19 | import org.neo4j.graphdb.traversal.TraversalDescription; 20 | import org.neo4j.graphdb.traversal.Traverser; 21 | import org.neo4j.helpers.Predicate; 22 | import org.neo4j.kernel.Traversal; 23 | import org.neo4j.rest.graphdb.MatrixDataGraph.RelTypes; 24 | import org.neo4j.rest.graphdb.traversal.RestTraversal; 25 | import org.neo4j.rest.graphdb.traversal.RestTraversalDescription.ScriptLanguage; 26 | 27 | public class MatrixDatabaseRestTest extends RestTestBase{ 28 | 29 | private MatrixDataGraph embeddedmdg; 30 | private MatrixDataGraph restmdg; 31 | 32 | @Before 33 | public void matrixTestSetUp() { 34 | //fill server db with matrix nodes 35 | this.embeddedmdg = new MatrixDataGraph(getGraphDatabase()).createNodespace(); 36 | this.restmdg = new MatrixDataGraph(getRestGraphDb()); 37 | } 38 | 39 | @Test 40 | public void testSetMaxtrixProperty() { 41 | restmdg.getNeoNode().setProperty( "occupation", "the one" ); 42 | Node node = embeddedmdg.getNeoNode(); 43 | Assert.assertEquals( "the one", node.getProperty( "occupation" ) ); 44 | } 45 | 46 | @Test 47 | public void checkForIndex() throws Exception { 48 | IndexManager index = getRestGraphDb().index(); 49 | assertTrue(index.existsForNodes("heroes")); 50 | } 51 | 52 | @Test 53 | public void useTrinityIndex() throws Exception { 54 | IndexManager index = getRestGraphDb().index(); 55 | Index goodGuys = index.forNodes("heroes"); 56 | IndexHits hits = goodGuys.get( "name", "Trinity" ); 57 | Node trinity = hits.getSingle(); 58 | assertEquals( "Trinity", trinity.getProperty("name") ); 59 | } 60 | 61 | @Test 62 | public void useMorpheusQuery() throws Exception { 63 | IndexManager index = getRestGraphDb().index(); 64 | Index goodGuys = index.forNodes("heroes"); 65 | for (Node morpheus : goodGuys.query("name", "Morpheus")){ 66 | assertEquals( "Morpheus", morpheus.getProperty("name") ); 67 | } 68 | } 69 | 70 | /** 71 | * get the number of all nodes that know the neo node 72 | * @throws Exception 73 | */ 74 | @Test 75 | public void getNeoFriends() throws Exception { 76 | Node neoNode = restmdg.getNeoNode(); 77 | System.out.println(neoNode.getProperty("name")); 78 | Traverser friendsTraverser = getFriends( neoNode ); 79 | int numberOfFriends = 0; 80 | for ( Path friendPath : friendsTraverser ) { 81 | numberOfFriends++; 82 | } 83 | 84 | assertEquals( 4, numberOfFriends ); 85 | } 86 | 87 | /** 88 | * get the number of all heroes that are connected to the heroes collection node 89 | * @throws Exception 90 | */ 91 | @Test 92 | public void checkNumberOfHeroes() throws Exception { 93 | Traverser heroesTraverser = getHeroesViaRest(); 94 | int numberOfHeroes = 0; 95 | for ( Path heroPath : heroesTraverser ) { 96 | numberOfHeroes++; 97 | } 98 | 99 | assertEquals( 3, numberOfHeroes ); 100 | } 101 | 102 | 103 | /** 104 | * check if rest traversal returns the same as embedded traversal 105 | * @throws Exception 106 | */ 107 | @Test 108 | public void checkTraverseByProperties() throws Exception { 109 | Traverser heroesTraverserRest = getHeroesViaRest(); 110 | Traverser heroesTraverserByProperties = getHeroesByNodeProperties(); 111 | assertEquals( heroesTraverserRest.nodes().iterator().next().getId(), heroesTraverserByProperties.nodes().iterator().next().getId() ); 112 | } 113 | 114 | /** 115 | * check if different REST Traversals for all heroes return the same 116 | * @throws Exception 117 | */ 118 | @Test 119 | public void checkTraverseByPropertiesRest() throws Exception { 120 | Traverser heroesTraverserRest = getHeroesViaRest(); 121 | Traverser heroesTraverserByPropertiesRest = getHeroesByNodePropertiesViaRest(); 122 | assertEquals( heroesTraverserRest.nodes().iterator().next(), heroesTraverserByPropertiesRest.nodes().iterator().next() ); 123 | } 124 | 125 | /** 126 | * check if rest traversal and traversal via the collection node return the same result 127 | * @throws Exception 128 | */ 129 | @Test 130 | public void checkTraverseByCollectionNode() throws Exception { 131 | Traverser heroesTraverserRest = getHeroesViaRest(); 132 | Traverser heroesTraverserByCollection = getHeroesByCollectionNodeViaRest(); 133 | assertEquals( heroesTraverserRest.nodes().iterator().next(), heroesTraverserByCollection.nodes().iterator().next() ); 134 | } 135 | 136 | 137 | /** 138 | * returns a traverser for all nodes that have an outgoing relationship of the type KNOWS 139 | * @param person the startnode 140 | * @return the Traverser 141 | */ 142 | private static Traverser getFriends( final Node person ) { 143 | TraversalDescription td = RestTraversal.description() 144 | .maxDepth(10) 145 | .breadthFirst() 146 | .relationships( RelTypes.KNOWS, Direction.OUTGOING ) 147 | .filter(Traversal.returnAllButStartNode()); 148 | return td.traverse( person ); 149 | } 150 | 151 | /** 152 | * returns a traverser for all nodes that have an outgoing relationship of the type HERO an are 3 positions down in the path 153 | * @return the Traverser 154 | */ 155 | private Traverser getHeroesViaRest() { 156 | TraversalDescription td = RestTraversal.description() 157 | .maxDepth(3) 158 | .breadthFirst() 159 | .relationships( RelTypes.PERSONS_REFERENCE, Direction.OUTGOING ) 160 | .relationships( RelTypes.HEROES_REFERENCE, Direction.OUTGOING ) 161 | .relationships( RelTypes.HERO, Direction.OUTGOING ) 162 | .filter(ScriptLanguage.JAVASCRIPT, "position.length() == 3;"); 163 | return td.traverse(this.restmdg.getGraphDatabase().getReferenceNode()); 164 | } 165 | 166 | /** 167 | * returns a traverser for all nodes that have a hero relationship and are connected to the hero collection node 168 | * @return 169 | */ 170 | private Traverser getHeroesByCollectionNodeViaRest(){ 171 | TraversalDescription td = RestTraversal.description() 172 | .maxDepth(10) 173 | .breadthFirst() 174 | .relationships( RelTypes.HERO, Direction.OUTGOING ); 175 | return td.traverse( this.restmdg.getHeroesCollectionNode() ); 176 | } 177 | 178 | /** 179 | * returns a traverser for all nodes that have a property type == hero via the REST API 180 | * @return the Traverser 181 | */ 182 | private Traverser getHeroesByNodePropertiesViaRest() { 183 | TraversalDescription td = RestTraversal.description() 184 | .maxDepth(3) 185 | .breadthFirst() 186 | .relationships( RelTypes.PERSONS_REFERENCE, Direction.OUTGOING ) 187 | .relationships( RelTypes.HEROES_REFERENCE, Direction.OUTGOING ) 188 | .relationships( RelTypes.HERO, Direction.OUTGOING ) 189 | .filter(ScriptLanguage.JAVASCRIPT, "position.endNode().getProperty('type','none') == 'hero';"); 190 | return td.traverse(this.restmdg.getGraphDatabase().getReferenceNode()); 191 | } 192 | 193 | 194 | /** 195 | * returns a traverser for all nodes that have a property type == hero in the embedded Database 196 | * @return the Traverser 197 | */ 198 | private Traverser getHeroesByNodeProperties() { 199 | TraversalDescription td = Traversal.description() 200 | .breadthFirst() 201 | .relationships( RelTypes.PERSONS_REFERENCE, Direction.OUTGOING ) 202 | .relationships( RelTypes.HEROES_REFERENCE, Direction.OUTGOING ) 203 | .relationships( RelTypes.HERO, Direction.OUTGOING ) 204 | .filter(new Predicate() { public boolean accept(Path path) { return path.endNode().getProperty("type","none").equals("hero");}}); 205 | return td.traverse(this.embeddedmdg.getGraphDatabase().getReferenceNode()); 206 | } 207 | 208 | 209 | } 210 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/Neo4jDatabaseCleaner.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.neo4j.graphdb.*; 4 | import org.neo4j.graphdb.index.IndexManager; 5 | 6 | import java.util.Arrays; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * @author mh 12 | * @since 09.05.11 13 | */ 14 | public class Neo4jDatabaseCleaner { 15 | private GraphDatabaseService graph; 16 | 17 | public Neo4jDatabaseCleaner(GraphDatabaseService graph) { 18 | this.graph = graph; 19 | } 20 | 21 | public Map cleanDb() { 22 | Map result = new HashMap(); 23 | Transaction tx = graph.beginTx(); 24 | try { 25 | removeNodes(result); 26 | clearIndex(result); 27 | tx.success(); 28 | } finally { 29 | tx.finish(); 30 | } 31 | return result; 32 | } 33 | 34 | private void removeNodes(Map result) { 35 | Node refNode = graph.getReferenceNode(); 36 | int nodes = 0, relationships = 0; 37 | for (Node node : graph.getAllNodes()) { 38 | for (Relationship rel : node.getRelationships(Direction.OUTGOING)) { 39 | rel.delete(); 40 | relationships++; 41 | } 42 | if (!refNode.equals(node)) { 43 | node.delete(); 44 | nodes++; 45 | } 46 | } 47 | result.put("nodes", nodes); 48 | result.put("relationships", relationships); 49 | 50 | } 51 | 52 | private void clearIndex(Map result) { 53 | IndexManager indexManager = graph.index(); 54 | result.put("node-indexes", Arrays.asList(indexManager.nodeIndexNames())); 55 | result.put("relationship-indexes", Arrays.asList(indexManager.relationshipIndexNames())); 56 | for (String ix : indexManager.nodeIndexNames()) { 57 | indexManager.forNodes(ix).delete(); 58 | } 59 | for (String ix : indexManager.relationshipIndexNames()) { 60 | indexManager.forRelationships(ix).delete(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RecordingRestRequestTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import static org.junit.Assert.*; 4 | import java.net.URI; 5 | import java.net.URISyntaxException; 6 | 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.neo4j.rest.graphdb.batch.RecordingRestRequest; 10 | import org.neo4j.rest.graphdb.batch.RestOperations; 11 | 12 | public class RecordingRestRequestTest { 13 | 14 | private ExecutingRestRequest exeRequest; 15 | private RecordingRestRequest recRequest; 16 | private String baseUri; 17 | 18 | @Before 19 | public void init(){ 20 | this.baseUri = "www.test.net"; 21 | this.exeRequest = new ExecutingRestRequest(baseUri); 22 | this.recRequest = new RecordingRestRequest(exeRequest, new RestOperations()); 23 | } 24 | 25 | @Test 26 | public void testCreate() { 27 | RecordingRestRequest testRequest = new RecordingRestRequest(exeRequest, new RestOperations()); 28 | assertEquals(this.baseUri, testRequest.getBaseUri()); 29 | assertEquals(0, testRequest.getRecordedRequests().size()); 30 | 31 | } 32 | 33 | @Test 34 | public void testGetWithoutData(){ 35 | RequestResult response = recRequest.get("/node"); 36 | assertEquals(1, response.getBatchId()); 37 | assertEquals(1, recRequest.getRecordedRequests().size()); 38 | } 39 | 40 | @Test 41 | public void testGetWithData(){ 42 | RequestResult response = recRequest.get("/node","Test"); 43 | assertEquals(1, response.getBatchId()); 44 | assertEquals(1, recRequest.getRecordedRequests().size()); 45 | } 46 | 47 | @Test 48 | public void testPost(){ 49 | RequestResult response = recRequest.post("/node","Test"); 50 | assertEquals(1, response.getBatchId()); 51 | assertEquals(1, recRequest.getRecordedRequests().size()); 52 | } 53 | 54 | @Test 55 | public void testPut(){ 56 | RequestResult response = recRequest.put("/node","Test"); 57 | assertEquals(1, response.getBatchId()); 58 | assertEquals(1, recRequest.getRecordedRequests().size()); 59 | } 60 | 61 | @Test 62 | public void testDelete(){ 63 | RequestResult response = recRequest.delete("/node"); 64 | assertEquals(1, response.getBatchId()); 65 | assertEquals(1, recRequest.getRecordedRequests().size()); 66 | } 67 | 68 | @Test 69 | public void testMultipleEntries(){ 70 | RequestResult response = recRequest.post("/node","Test"); 71 | assertEquals(1, response.getBatchId()); 72 | assertEquals(1, recRequest.getRecordedRequests().size()); 73 | response = recRequest.delete("/node"); 74 | assertEquals(2, response.getBatchId()); 75 | assertEquals(2, recRequest.getRecordedRequests().size()); 76 | response = recRequest.get("/node","Test"); 77 | assertEquals(3, response.getBatchId()); 78 | assertEquals(3, recRequest.getRecordedRequests().size()); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RelationshipHasMatcher.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import org.hamcrest.Description; 8 | import org.junit.internal.matchers.TypeSafeMatcher; 9 | import org.neo4j.graphdb.Direction; 10 | import org.neo4j.graphdb.Node; 11 | import org.neo4j.graphdb.Relationship; 12 | import org.neo4j.graphdb.RelationshipType; 13 | 14 | public class RelationshipHasMatcher extends TypeSafeMatcher>{ 15 | 16 | private final Node node; 17 | private final Direction direction; 18 | private final List typeNames; 19 | 20 | public RelationshipHasMatcher(Node startNode, Direction direction, RelationshipType... types){ 21 | this.node = startNode; 22 | this.direction = direction; 23 | this.typeNames = fillTypeNames(Arrays.asList(types)); 24 | } 25 | 26 | 27 | 28 | @Override 29 | public void describeTo(Description description) { 30 | description.appendText("Not all relationships matched the constraints. Node: ").appendValue(node).appendText(" direction: ").appendValue(direction).appendText(" relationship type(s): ").appendValue(typeNames); 31 | 32 | } 33 | 34 | @Override 35 | public boolean matchesSafely(Iterable relationships) { 36 | for (Relationship relationship : relationships) { 37 | 38 | boolean isStartnode = this.node.equals(relationship.getStartNode()); 39 | boolean isEndnode = this.node.equals(relationship.getEndNode()); 40 | if (!isStartnode && !isEndnode){ 41 | return false; 42 | } 43 | 44 | Direction relationshipDirection = isStartnode ? Direction.OUTGOING : Direction.INCOMING; 45 | 46 | if (this.direction != null && this.direction!= relationshipDirection){ 47 | return false; 48 | } 49 | 50 | 51 | if(!this.typeNames.isEmpty() && !this.typeNames.contains(relationship.getType().name())){ 52 | return false; 53 | } 54 | } 55 | 56 | return true; 57 | } 58 | 59 | public static RelationshipHasMatcher match(Node startNode, Direction direction, RelationshipType... types){ 60 | return new RelationshipHasMatcher(startNode, direction, types); 61 | } 62 | 63 | public static List fillTypeNames(List types){ 64 | List names = new ArrayList(); 65 | for (RelationshipType type : types) { 66 | names.add(type.name()); 67 | } 68 | return names; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestCypherQueryEngineTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import static java.util.Arrays.asList; 4 | import static org.junit.Assert.*; 5 | 6 | import java.util.Collection; 7 | import java.util.Collections; 8 | import java.util.HashMap; 9 | import java.util.Iterator; 10 | import java.util.Map; 11 | import java.util.Vector; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.neo4j.graphdb.Node; 16 | import org.neo4j.graphdb.RelationshipType; 17 | import org.neo4j.graphdb.index.Index; 18 | import org.neo4j.graphdb.index.IndexHits; 19 | import org.neo4j.graphdb.index.IndexManager; 20 | import org.neo4j.helpers.collection.IteratorUtil; 21 | import org.neo4j.helpers.collection.MapUtil; 22 | import org.neo4j.rest.graphdb.MatrixDataGraph.RelTypes; 23 | import org.neo4j.rest.graphdb.query.RestCypherQueryEngine; 24 | import org.neo4j.rest.graphdb.util.QueryResult; 25 | 26 | 27 | public class RestCypherQueryEngineTest extends RestTestBase { 28 | private RestCypherQueryEngine queryEngine; 29 | private RestAPI restAPI; 30 | private MatrixDataGraph embeddedMatrixdata; 31 | private MatrixDataGraph restMatrixData; 32 | 33 | @Before 34 | public void init() throws Exception { 35 | embeddedMatrixdata = new MatrixDataGraph(getGraphDatabase()).createNodespace(); 36 | restMatrixData = new MatrixDataGraph(getRestGraphDb()); 37 | this.restAPI = ((RestGraphDatabase)getRestGraphDb()).getRestAPI(); 38 | queryEngine = new RestCypherQueryEngine(restAPI); 39 | } 40 | 41 | @Test 42 | public void testGetReferenceNode(){ 43 | final String queryString = "start n=(%reference) return n"; 44 | final Node result = (Node) queryEngine.query(queryString, MapUtil.map("reference",0)).to(Node.class).single(); 45 | assertEquals(embeddedMatrixdata.getGraphDatabase().getReferenceNode(), result); 46 | 47 | } 48 | 49 | @Test 50 | public void testGetNeoNode(){ 51 | final String queryString = "start neo=(%neo) return neo"; 52 | final Node result = (Node) queryEngine.query(queryString, MapUtil.map("neo",getNeoId())).to(Node.class).single(); 53 | assertEquals(embeddedMatrixdata.getNeoNode(), result); 54 | } 55 | 56 | @Test 57 | public void testGetNeoNodeByIndexLookup(){ 58 | final String queryString = "start neo=(heroes,name,\"%neoname\") return neo"; 59 | final Node result = (Node) queryEngine.query(queryString, MapUtil.map("neoname","Neo")).to(Node.class).single(); 60 | assertEquals(embeddedMatrixdata.getNeoNode(), result); 61 | } 62 | 63 | @Test 64 | public void testGetNeoNodeByIndexQuery(){ 65 | final String queryString = "start neo=(heroes,\"name:%neoname\") return neo"; 66 | final Node result = (Node) queryEngine.query(queryString, MapUtil.map("neoname","Neo")).to(Node.class).single(); 67 | assertEquals(embeddedMatrixdata.getNeoNode(), result); 68 | } 69 | 70 | @Test 71 | public void testGetNeoNodeSingleProperty(){ 72 | final String queryString = "start neo=(%neo) return neo.name"; 73 | final String result = (String) queryEngine.query(queryString, MapUtil.map("neo",getNeoId())).to(String.class).single(); 74 | assertEquals("Thomas Anderson", result); 75 | } 76 | 77 | @Test 78 | public void testGetNeoNodeViaMorpheus(){ 79 | final String queryString = "start morpheus=(heroes,\"name:%morpheusname\") match (morpheus) <-[:KNOWS]- (neo) return neo"; 80 | final Node result = (Node) queryEngine.query(queryString, MapUtil.map("morpheusname","Morpheus")).to(Node.class).single(); 81 | assertEquals(embeddedMatrixdata.getNeoNode(), result); 82 | } 83 | 84 | @Test 85 | public void testGetCypherNodeViaMorpheusAndFilter(){ 86 | final String queryString = "start morpheus=(heroes,\"name:%morpheusname\") match (morpheus) -[:KNOWS]-> (person) where person.type = \"villain\" return person"; 87 | final Node result = (Node) queryEngine.query(queryString, MapUtil.map("morpheusname","Morpheus")).to(Node.class).single(); 88 | assertEquals("Cypher", result.getProperty("name")); 89 | } 90 | 91 | @Test 92 | public void testGetArchitectViaMorpheusAndFilter(){ 93 | final String queryString = "start morpheus=(heroes,\"name:%morpheusname\") match (morpheus) -[:KNOWS]-> (person) -[:KNOWS]-> (smith) -[:CODED_BY]-> (architect) where person.type = \"villain\" return architect"; 94 | final Node result = (Node) queryEngine.query(queryString, MapUtil.map("morpheusname","Morpheus")).to(Node.class).single(); 95 | assertEquals("The Architect", result.getProperty("name")); 96 | } 97 | 98 | 99 | @Test 100 | public void testGetNeoNodeMultipleProperties(){ 101 | final String queryString = "start neo=(%neo) return neo.name, neo.type, neo.age"; 102 | final Collection> result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("neo",getNeoId()))); 103 | assertEquals(asList( MapUtil.map("neo.name", "Thomas Anderson", "neo.type","hero", "neo.age", 29 )),result); 104 | 105 | } 106 | 107 | @Test 108 | public void testGetRelationshipType(){ 109 | final String queryString ="start n=(%reference) match (n)-[r]->() return r~TYPE"; 110 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("reference",0)).to(String.class)); 111 | assertTrue(result.contains("NEO_NODE")); 112 | } 113 | 114 | 115 | public long getNeoId(){ 116 | return embeddedMatrixdata.getNeoNode().getId(); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestEntityTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.neo4j.graphdb.Direction; 6 | import org.neo4j.graphdb.Node; 7 | import org.neo4j.graphdb.Relationship; 8 | import org.neo4j.rest.graphdb.util.TestHelper; 9 | 10 | import java.util.Arrays; 11 | 12 | public class RestEntityTest extends RestTestBase { 13 | 14 | @Test 15 | public void testSetProperty() { 16 | getRestGraphDb().getReferenceNode().setProperty( "name", "test" ); 17 | Node node = getRestGraphDb().getReferenceNode(); 18 | Assert.assertEquals( "test", node.getProperty( "name" ) ); 19 | } 20 | 21 | @Test 22 | public void testSetStringArrayProperty() { 23 | getRestGraphDb().getReferenceNode().setProperty( "name", new String[]{"test"} ); 24 | Node node = getRestGraphDb().getReferenceNode(); 25 | Assert.assertArrayEquals( new String[]{"test"}, (String[])node.getProperty( "name" ) ); 26 | } 27 | @Test 28 | public void testSetDoubleArrayProperty() { 29 | double[] data = {0, 1, 2}; 30 | getRestGraphDb().getReferenceNode().setProperty( "data", data ); 31 | Node node = getRestGraphDb().getReferenceNode(); 32 | Assert.assertTrue("same double array",Arrays.equals( data, (double[])node.getProperty( "data" ) )); 33 | } 34 | 35 | @Test 36 | public void testRemoveProperty() { 37 | Node node = getRestGraphDb().getReferenceNode(); 38 | node.setProperty( "name", "test" ); 39 | Assert.assertEquals( "test", node.getProperty( "name" ) ); 40 | node.removeProperty( "name" ); 41 | Assert.assertEquals( false, node.hasProperty( "name" ) ); 42 | } 43 | 44 | 45 | @Test 46 | public void testSetPropertyOnRelationship() { 47 | Node refNode = getRestGraphDb().getReferenceNode(); 48 | Node node = getRestGraphDb().createNode(); 49 | Relationship rel = refNode.createRelationshipTo( node, Type.TEST ); 50 | rel.setProperty( "name", "test" ); 51 | Assert.assertEquals( "test", rel.getProperty( "name" ) ); 52 | Relationship foundRelationship = TestHelper.firstRelationshipBetween( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), refNode, node ); 53 | Assert.assertEquals( "test", foundRelationship.getProperty( "name" ) ); 54 | } 55 | 56 | @Test 57 | public void testRemovePropertyOnRelationship() { 58 | Node refNode = getRestGraphDb().getReferenceNode(); 59 | Node node = getRestGraphDb().createNode(); 60 | Relationship rel = refNode.createRelationshipTo( node, Type.TEST ); 61 | rel.setProperty( "name", "test" ); 62 | Assert.assertEquals( "test", rel.getProperty( "name" ) ); 63 | Relationship foundRelationship = TestHelper.firstRelationshipBetween( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), refNode, node ); 64 | Assert.assertEquals( "test", foundRelationship.getProperty( "name" ) ); 65 | rel.removeProperty( "name" ); 66 | Assert.assertEquals( false, rel.hasProperty( "name" ) ); 67 | Relationship foundRelationship2 = TestHelper.firstRelationshipBetween( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), refNode, node ); 68 | Assert.assertEquals( false, foundRelationship2.hasProperty( "name" ) ); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestGraphDbTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.neo4j.graphdb.*; 6 | import org.neo4j.rest.graphdb.util.TestHelper; 7 | 8 | import java.util.Date; 9 | 10 | public class RestGraphDbTest extends RestTestBase { 11 | 12 | @Test 13 | public void testGetRefNode() { 14 | Node refNode = getRestGraphDb().getReferenceNode(); 15 | Node nodeById = getRestGraphDb().getNodeById( 0 ); 16 | Assert.assertEquals( refNode, nodeById ); 17 | } 18 | 19 | @Test 20 | public void testCreateNode() { 21 | Node node = getRestGraphDb().createNode(); 22 | Assert.assertEquals( node, getRestGraphDb().getNodeById( node.getId() ) ); 23 | } 24 | 25 | @Test 26 | public void testCreateRelationship() { 27 | Node refNode = getRestGraphDb().getReferenceNode(); 28 | Node node = getRestGraphDb().createNode(); 29 | Relationship rel = refNode.createRelationshipTo( node, Type.TEST ); 30 | Relationship foundRelationship = TestHelper.firstRelationshipBetween( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), refNode, node ); 31 | Assert.assertNotNull( "found relationship", foundRelationship ); 32 | Assert.assertEquals( "same relationship", rel, foundRelationship ); 33 | Assert.assertThat( refNode.getRelationships( Type.TEST, Direction.OUTGOING ), new IsRelationshipToNodeMatcher( refNode, node ) ); 34 | Assert.assertThat( refNode.getRelationships( Direction.OUTGOING ), new IsRelationshipToNodeMatcher( refNode, node ) ); 35 | Assert.assertThat( refNode.getRelationships( Direction.BOTH ), new IsRelationshipToNodeMatcher( refNode, node ) ); 36 | Assert.assertThat( refNode.getRelationships( Type.TEST ), new IsRelationshipToNodeMatcher( refNode, node ) ); 37 | } 38 | 39 | @Test 40 | public void testBasic() { 41 | Node refNode = getRestGraphDb().getReferenceNode(); 42 | Node node = getRestGraphDb().createNode(); 43 | Relationship rel = refNode.createRelationshipTo( node, 44 | DynamicRelationshipType.withName( "TEST" ) ); 45 | rel.setProperty( "date", new Date().getTime() ); 46 | node.setProperty( "name", "Mattias test" ); 47 | refNode.createRelationshipTo( node, 48 | DynamicRelationshipType.withName( "TEST" ) ); 49 | 50 | for ( Relationship relationship : refNode.getRelationships() ) { 51 | System.out.println( "rel prop:" + relationship.getProperty( "date", null ) ); 52 | Node endNode = relationship.getEndNode(); 53 | System.out.println( "node prop:" + endNode.getProperty( "name", null ) ); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestGremlinQueryEngineTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import static java.util.Arrays.asList; 4 | import static org.junit.Assert.assertEquals; 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import org.junit.Before; 8 | import org.junit.Ignore; 9 | import org.junit.Test; 10 | import org.neo4j.graphdb.Node; 11 | import org.neo4j.graphdb.index.Index; 12 | import org.neo4j.graphdb.index.IndexHits; 13 | import org.neo4j.graphdb.index.IndexManager; 14 | import org.neo4j.helpers.collection.IteratorUtil; 15 | import org.neo4j.helpers.collection.MapUtil; 16 | import org.neo4j.rest.graphdb.query.RestGremlinQueryEngine; 17 | 18 | public class RestGremlinQueryEngineTest extends RestTestBase { 19 | private RestGremlinQueryEngine queryEngine; 20 | private RestAPI restAPI; 21 | private MatrixDataGraph embeddedMatrixdata; 22 | private MatrixDataGraph restMatrixData; 23 | 24 | @Before 25 | public void init() throws Exception { 26 | embeddedMatrixdata = new MatrixDataGraph(getGraphDatabase()).createNodespace(); 27 | restMatrixData = new MatrixDataGraph(getRestGraphDb()); 28 | this.restAPI = ((RestGraphDatabase)getRestGraphDb()).getRestAPI(); 29 | queryEngine = new RestGremlinQueryEngine(restAPI); 30 | } 31 | 32 | 33 | @Test 34 | public void testGetReferenceNode(){ 35 | final String queryString = "g.v(0)"; 36 | final Node result = (Node) queryEngine.query(queryString, null).to(Node.class).single(); 37 | assertEquals(embeddedMatrixdata.getGraphDatabase().getReferenceNode(), result); 38 | 39 | } 40 | 41 | @Test 42 | public void testGetNeoNodeByReferenceNode(){ 43 | final String queryString = "g.v(0).out('NEO_NODE')"; 44 | final Node result = (Node) queryEngine.query(queryString, null).to(Node.class).single(); 45 | assertEquals(embeddedMatrixdata.getNeoNode(), result); 46 | 47 | } 48 | 49 | @Test 50 | public void testGetSingleProperty(){ 51 | final String queryString = "g.v(neo).name"; 52 | final String result = (String) queryEngine.query(queryString, MapUtil.map("neo",getNeoId())).to(String.class).single(); 53 | assertEquals(embeddedMatrixdata.getNeoNode().getProperty("name"), result); 54 | 55 | } 56 | 57 | @Test 58 | public void testGetMultipleResults(){ 59 | final String queryString = "g.v(neo).out('KNOWS').name"; 60 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("neo",getNeoId()))); 61 | assertEquals(createCollectionWithMultipleProperties("Trinity","Morpheus") ,result); 62 | } 63 | 64 | @Test 65 | public void testGetMultipleResultsAsNodes(){ 66 | final String queryString = "g.v(neo).out('KNOWS')"; 67 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("neo",getNeoId())).to(Node.class)); 68 | assertEquals(createCollectionWithMultipleProperties(embeddedMatrixdata.getGraphDatabase().getNodeById(getTrinityId()),embeddedMatrixdata.getGraphDatabase().getNodeById(getMorpheusId())) ,result); 69 | } 70 | 71 | @Test 72 | public void testGetMultipleResultsWithMultipleStartNodes(){ 73 | final String queryString = "[g.v(morpheus), g.v(trinity)]._().out('KNOWS').name"; 74 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("morpheus", getMorpheusId(), "trinity", getTrinityId()))); 75 | assertEquals(createCollectionWithMultipleProperties("Trinity","Cypher","Cypher") ,result); 76 | } 77 | 78 | @Test 79 | public void testGetMultipleIDResults(){ 80 | final String queryString = "g.v(neo).out('KNOWS').id"; 81 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("neo",getNeoId()))); 82 | assertEquals(createCollectionWithMultipleProperties((int)getTrinityId(),(int)getMorpheusId()) ,result); 83 | } 84 | 85 | 86 | @Test 87 | public void testFilter(){ 88 | final String queryString = "g.v(morpheus).out('KNOWS').filter{it.type.equals(\"villain\")}.name"; 89 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("morpheus",getMorpheusId()))); 90 | assertEquals(createCollectionWithMultipleProperties("Cypher") ,result); 91 | 92 | } 93 | 94 | /** 95 | @Test 96 | public void testIfThenElse(){ 97 | final String queryString = "g.v(neo).out('KNOWS').ifThenElse{it.name.equals(\"Trinity\")}{it.name}{it.out('KNOWS').name}"; 98 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("neo",getNeoId()))); 99 | //assertEquals(createCollectionWithMultipleProperties((int)getTrinityId(),(int)getMorpheusId()) ,result); 100 | System.out.println(result); 101 | }*/ 102 | 103 | 104 | @Ignore 105 | @Test 106 | public void testQueryList2(){ 107 | final String queryString = "[g.v(neo),g.v(trinity)]._().type.as('person.type').name.as('person.name').table(new Table()).cap >> 1"; 108 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("neo", getNeoId(), "trinity",getTrinityId()))); 109 | assertEquals(asList(MapUtil.map("person.type","hero", "person.name", "Thomas Anderson"), MapUtil.map("person.type","hero", "person.name", "Trinity")), result); 110 | 111 | } 112 | 113 | 114 | @Test 115 | public void testQueryList() throws Exception { 116 | final String queryString = "t = new Table(); [g.v(neo),g.v(trinity)].each{ n -> n.as('person.name').as('person.type').table(t,['person.name','person.type']){ it.type }{ it.name } >> -1}; t;" ; 117 | final Collection result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("neo", getNeoId(), "trinity",getTrinityId()))); 118 | assertEquals(asList(MapUtil.map("person.type","hero", "person.name", "Thomas Anderson"), MapUtil.map("person.type","hero", "person.name", "Trinity")), result); 119 | } 120 | 121 | 122 | public ArrayList createCollectionWithMultipleProperties(Object... params){ 123 | ArrayList list = new ArrayList(); 124 | for(Object param : params){ 125 | list.add(param); 126 | } 127 | return list; 128 | } 129 | 130 | 131 | 132 | public long getNeoId(){ 133 | return embeddedMatrixdata.getNeoNode().getId(); 134 | } 135 | 136 | public long getTrinityId(){ 137 | IndexManager index = getRestGraphDb().index(); 138 | Index goodGuys = index.forNodes("heroes"); 139 | IndexHits hits = goodGuys.get( "name", "Trinity" ); 140 | Node trinity = hits.getSingle(); 141 | return trinity.getId(); 142 | } 143 | 144 | public long getMorpheusId(){ 145 | IndexManager index = getRestGraphDb().index(); 146 | Index goodGuys = index.forNodes("heroes"); 147 | IndexHits hits = goodGuys.get( "name", "Morpheus" ); 148 | Node morpheus = hits.getSingle(); 149 | return morpheus.getId(); 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestIndexTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.apache.lucene.index.Term; 4 | import org.apache.lucene.search.TermQuery; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.neo4j.graphdb.Node; 8 | import org.neo4j.graphdb.Relationship; 9 | import org.neo4j.graphdb.index.Index; 10 | import org.neo4j.graphdb.index.IndexHits; 11 | import org.neo4j.graphdb.index.IndexManager; 12 | import org.neo4j.graphdb.index.RelationshipIndex; 13 | import org.neo4j.index.lucene.QueryContext; 14 | 15 | import java.util.Arrays; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | public class RestIndexTest extends RestTestBase { 21 | 22 | private static final String NODE_INDEX_NAME = "NODE_INDEX"; 23 | private static final String REL_INDEX_NAME = "REL_INDEX"; 24 | 25 | @Test 26 | public void testAddToNodeIndex() { 27 | nodeIndex().add(node(), "name", "test"); 28 | IndexHits hits = nodeIndex().get("name", "test"); 29 | Assert.assertEquals("index results", true, hits.hasNext()); 30 | Assert.assertEquals(node(), hits.next()); 31 | } 32 | 33 | @Test 34 | public void testNotFoundInNodeIndex() { 35 | IndexHits hits = nodeIndex().get("foo", "bar"); 36 | Assert.assertEquals("no index results", false, hits.hasNext()); 37 | } 38 | 39 | @Test 40 | public void testAddToRelationshipIndex() { 41 | final long value = System.currentTimeMillis(); 42 | relationshipIndex().add(relationship(), "name", value); 43 | IndexHits hits = relationshipIndex().get("name", value); 44 | Assert.assertEquals("index results", true, hits.hasNext()); 45 | Assert.assertEquals(relationship(), hits.next()); 46 | } 47 | 48 | @Test 49 | public void testNotFoundInRelationshipIndex() { 50 | IndexHits hits = relationshipIndex().get("foo", "bar"); 51 | Assert.assertEquals("no index results", false, hits.hasNext()); 52 | } 53 | 54 | @Test 55 | public void testDeleteKeyValueFromNodeIndex() { 56 | String value = String.valueOf(System.currentTimeMillis()); 57 | nodeIndex().add(node(), "time", value); 58 | IndexHits hits = nodeIndex().get("time", value); 59 | Assert.assertEquals("found in index results", true, hits.hasNext()); 60 | Assert.assertEquals("found in index results", node(), hits.next()); 61 | nodeIndex().remove(node(), "time", value); 62 | IndexHits hitsAfterRemove = nodeIndex().get("time", value); 63 | Assert.assertEquals("not found in index results", false, hitsAfterRemove.hasNext()); 64 | } 65 | 66 | @Test 67 | public void testDeleteKeyFromNodeIndex() { 68 | String value = String.valueOf(System.currentTimeMillis()); 69 | nodeIndex().add(node(), "time", value); 70 | IndexHits hits = nodeIndex().get("time", value); 71 | Assert.assertEquals("found in index results", true, hits.hasNext()); 72 | Assert.assertEquals("found in index results", node(), hits.next()); 73 | nodeIndex().remove(node(), "time"); 74 | IndexHits hitsAfterRemove = nodeIndex().get("time", value); 75 | Assert.assertEquals("not found in index results", false, hitsAfterRemove.hasNext()); 76 | } 77 | @Test 78 | public void testDeleteNodeFromNodeIndex() { 79 | String value = String.valueOf(System.currentTimeMillis()); 80 | nodeIndex().add(node(), "time", value); 81 | IndexHits hits = nodeIndex().get("time", value); 82 | Assert.assertEquals("found in index results", true, hits.hasNext()); 83 | Assert.assertEquals("found in index results", node(), hits.next()); 84 | nodeIndex().remove(node()); 85 | IndexHits hitsAfterRemove = nodeIndex().get("time", value); 86 | Assert.assertEquals("not found in index results", false, hitsAfterRemove.hasNext()); 87 | } 88 | @Test 89 | public void testDeleteIndex() { 90 | final String indexName = nodeIndex().getName(); 91 | nodeIndex().delete(); 92 | final List indexNames = Arrays.asList(getRestGraphDb().index().nodeIndexNames()); 93 | Assert.assertEquals("removed index name",false,indexNames.contains(indexName)); 94 | } 95 | @Test 96 | public void testCreateFulltextIndex() { 97 | Map config=new HashMap(); 98 | config.put("provider", "lucene"); 99 | config.put("type","fulltext"); 100 | final IndexManager indexManager = getRestGraphDb().index(); 101 | final Index index = indexManager.forNodes("fulltext", config); 102 | final Map config2 = indexManager.getConfiguration(index); 103 | Assert.assertEquals("provider", config.get("provider"), config2.get("provider")); 104 | Assert.assertEquals("type", config.get("type"), config2.get("type")); 105 | } 106 | 107 | @Test 108 | public void testQueryFulltextIndexWithKey() { 109 | Map config=new HashMap(); 110 | config.put("provider","lucene"); 111 | config.put("type","fulltext"); 112 | final Index index = getRestGraphDb().index().forNodes("text-index", config); 113 | index.add(node(),"text","any text"); 114 | final IndexHits hits = index.query("text", "any t*"); 115 | Assert.assertEquals("found in index results", true, hits.hasNext()); 116 | Assert.assertEquals("found in index results", node(), hits.next()); 117 | } 118 | @Test 119 | public void testQueryFulltextIndexWithOutKey() { 120 | Map config=new HashMap(); 121 | config.put("provider","lucene"); 122 | config.put("type","fulltext"); 123 | final Index index = getRestGraphDb().index().forNodes("text-index", config); 124 | index.add(node(),"text","any text"); 125 | final IndexHits hits = index.query("text:any t*"); 126 | Assert.assertEquals("found in index results", true, hits.hasNext()); 127 | Assert.assertEquals("found in index results", node(), hits.next()); 128 | } 129 | 130 | @Test 131 | public void testQueryFulltextIndexWithLuceneQueryTerm() { 132 | Map config = new HashMap(); 133 | config.put("provider", "lucene"); 134 | config.put("type", "fulltext"); 135 | final Index index = getRestGraphDb().index().forNodes("text-index", config); 136 | index.add(node(), "text", "any text"); 137 | TermQuery luceneQuery = new TermQuery(new Term("text", "any t*")); 138 | // TODO this works only because the toString implementation renders a complete query -> dangerous assumption 139 | final IndexHits hits = index.query(luceneQuery); 140 | Assert.assertEquals("found in index results", true, hits.hasNext()); 141 | Assert.assertEquals("found in index results", node(), hits.next()); 142 | } 143 | 144 | @Test 145 | public void testQueryFulltextIndexWithQueryContext() { 146 | Map config = new HashMap(); 147 | config.put("provider", "lucene"); 148 | config.put("type", "fulltext"); 149 | final Index index = getRestGraphDb().index().forNodes("text-index", config); 150 | index.add(node(), "text", "any text"); 151 | QueryContext ctx = new QueryContext("text:any t*"); 152 | final IndexHits hits = index.query(ctx); 153 | Assert.assertEquals("found in index results", true, hits.hasNext()); 154 | Assert.assertEquals("found in index results", node(), hits.next()); 155 | } 156 | 157 | @Test 158 | public void testDeleteFromRelationshipIndex() { 159 | String value = String.valueOf(System.currentTimeMillis()); 160 | relationshipIndex().add(relationship(), "time", value); 161 | IndexHits hits = relationshipIndex().get("time", value); 162 | Assert.assertEquals("found in index results", true, hits.hasNext()); 163 | Assert.assertEquals("found in index results", relationship(), hits.next()); 164 | relationshipIndex().remove(relationship(), "time", value); 165 | IndexHits hitsAfterRemove = relationshipIndex().get("time", value); 166 | Assert.assertEquals("not found in index results", false, hitsAfterRemove.hasNext()); 167 | } 168 | 169 | private Index nodeIndex() { 170 | return getRestGraphDb().index().forNodes(NODE_INDEX_NAME); 171 | } 172 | 173 | private RelationshipIndex relationshipIndex() { 174 | return getRestGraphDb().index().forRelationships(REL_INDEX_NAME); 175 | } 176 | 177 | @Test 178 | public void testNodeIndexIsListed() { 179 | nodeIndex().add(node(), "name", "test"); 180 | Assert.assertTrue("node index name listed", Arrays.asList(getRestGraphDb().index().nodeIndexNames()).contains(NODE_INDEX_NAME)); 181 | } 182 | 183 | @Test 184 | public void testRelationshipIndexIsListed() { 185 | relationshipIndex().add(relationship(), "name", "test"); 186 | Assert.assertTrue("relationship index name listed", Arrays.asList(getRestGraphDb().index().relationshipIndexNames()).contains(REL_INDEX_NAME)); 187 | } 188 | 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestNodeTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import static org.junit.Assert.*; 4 | import static org.neo4j.graphdb.Direction.INCOMING; 5 | import static org.neo4j.graphdb.Direction.OUTGOING; 6 | import static org.neo4j.rest.graphdb.RelationshipHasMatcher.match; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.neo4j.graphdb.Node; 11 | import org.neo4j.graphdb.Relationship; 12 | import org.neo4j.rest.graphdb.MatrixDataGraph.RelTypes; 13 | 14 | public class RestNodeTest extends RestTestBase { 15 | 16 | 17 | private MatrixDataGraph embeddedMatrixdata; 18 | private MatrixDataGraph restMatrixData; 19 | private Node neo; 20 | 21 | 22 | @Before 23 | public void createMatrixdata() { 24 | embeddedMatrixdata = new MatrixDataGraph(getGraphDatabase()).createNodespace(); 25 | restMatrixData = new MatrixDataGraph(getRestGraphDb()); 26 | neo = restMatrixData.getNeoNode(); 27 | } 28 | 29 | @Test 30 | public void testGetRelationshipsWithoutDirectionWithoutRelationshipType() { 31 | Iterable relationships = neo.getRelationships(); 32 | assertThat(relationships, match(neo, null)); 33 | } 34 | 35 | @Test 36 | public void testGetRelationshipsWithIncomingDirectionWithoutRelationshipType() { 37 | Iterable relationships = neo.getRelationships(INCOMING); 38 | assertThat(relationships, match(neo, INCOMING)); 39 | } 40 | 41 | @Test 42 | public void testGetRelationshipsWithOutgoingDirectionWithoutRelationshipType() { 43 | Iterable relationships = neo.getRelationships(OUTGOING); 44 | assertThat(relationships, match(neo, OUTGOING)); 45 | } 46 | 47 | @Test 48 | public void testGetRelationshipsWithoutDirectionWithSingleRelationshipType() { 49 | Iterable relationships = neo.getRelationships(RelTypes.NEO_NODE); 50 | assertThat(relationships, match(neo, null, RelTypes.NEO_NODE)); 51 | } 52 | 53 | 54 | @Test 55 | public void testGetRelationshipsWithIncomingDirectionWithSingleRelationshipType() { 56 | Iterable relationships = neo.getRelationships(INCOMING, RelTypes.NEO_NODE); 57 | assertThat(relationships, match(neo, INCOMING, RelTypes.NEO_NODE)); 58 | } 59 | 60 | @Test 61 | public void testGetRelationshipsWithOutgoingDirectionWithSingleRelationshipType() { 62 | Iterable relationships = neo.getRelationships(OUTGOING, RelTypes.KNOWS); 63 | assertThat(relationships, match(neo, OUTGOING, RelTypes.KNOWS)); 64 | } 65 | 66 | @Test 67 | public void testGetRelationshipsWithoutDirectionWithMultipleRelationshipTypes() { 68 | Iterable relationships = neo.getRelationships(RelTypes.NEO_NODE, RelTypes.HERO); 69 | assertThat(relationships, match(neo, null, RelTypes.NEO_NODE, RelTypes.HERO)); 70 | } 71 | 72 | @Test 73 | public void testGetRelationshipsWithIncomingDirectionWithMultipleRelationshipTypes() { 74 | Iterable relationships = neo.getRelationships(INCOMING, RelTypes.NEO_NODE, RelTypes.HERO ); 75 | assertThat(relationships, match(neo, INCOMING, RelTypes.NEO_NODE, RelTypes.HERO)); 76 | 77 | } 78 | 79 | @Test 80 | public void testGetRelationshipsWithOutgoingDirectionWithMultipleRelationshipTypes() { 81 | Iterable relationships = neo.getRelationships(OUTGOING, RelTypes.KNOWS, RelTypes.FIGHTS ); 82 | assertThat(relationships, match(neo, OUTGOING, RelTypes.KNOWS, RelTypes.FIGHTS)); 83 | 84 | } 85 | 86 | @Test 87 | public void testHasRelationshipsWithoutDirectionWithoutRelationshipType() { 88 | boolean hasRelationship = neo.hasRelationship(); 89 | assertTrue(hasRelationship); 90 | } 91 | 92 | @Test 93 | public void testHasRelationshipsWithIncomingDirectionWithoutRelationshipType() { 94 | boolean hasRelationship = neo.hasRelationship(INCOMING); 95 | assertTrue(hasRelationship); 96 | } 97 | 98 | @Test 99 | public void testHasRelationshipsWithOutgoingDirectionWithoutRelationshipType() { 100 | boolean hasRelationship = neo.hasRelationship(OUTGOING); 101 | assertTrue(hasRelationship); 102 | } 103 | 104 | @Test 105 | public void testHasRelationshipsWithoutDirectionWithSingleRelationshipType() { 106 | boolean hasRelationship = neo.hasRelationship(RelTypes.KNOWS); 107 | assertTrue(hasRelationship); 108 | } 109 | 110 | @Test 111 | public void testHasRelationshipsWithIncomingDirectionWithSingleRelationshipType() { 112 | boolean hasRelationship = neo.hasRelationship(INCOMING, RelTypes.HERO); 113 | assertTrue(hasRelationship); 114 | } 115 | 116 | @Test 117 | public void testHasRelationshipsWithIncomingDirectionWithSingleRelationshipTypeParamsReversed() { 118 | boolean hasRelationship = neo.hasRelationship(RelTypes.HERO, INCOMING); 119 | assertTrue(hasRelationship); 120 | } 121 | 122 | @Test 123 | public void testHasRelationshipsWithOutgoingDirectionWithSingleRelationshipType() { 124 | boolean hasRelationship = neo.hasRelationship(OUTGOING, RelTypes.KNOWS); 125 | assertTrue(hasRelationship); 126 | } 127 | 128 | @Test 129 | public void testHasRelationshipsWithOutgoingDirectionWithSingleRelationshipTypeParamsReversed() { 130 | boolean hasRelationship = neo.hasRelationship(RelTypes.KNOWS, OUTGOING); 131 | assertTrue(hasRelationship); 132 | } 133 | 134 | @Test 135 | public void testHasRelationshipsWithoutDirectionWithMultipleRelationshipTypes() { 136 | boolean hasRelationship = neo.hasRelationship(RelTypes.KNOWS, RelTypes.HERO); 137 | assertTrue(hasRelationship); 138 | } 139 | 140 | @Test 141 | public void testHasRelationshipsWithIncomingDirectionWithMultipleRelationshipTypes() { 142 | boolean hasRelationship = neo.hasRelationship(INCOMING, RelTypes.NEO_NODE, RelTypes.HERO); 143 | assertTrue(hasRelationship); 144 | } 145 | 146 | @Test 147 | public void testHasRelationshipsWithOutgoingDirectionWithMultipleRelationshipTypes() { 148 | boolean hasRelationship = neo.hasRelationship(OUTGOING, RelTypes.KNOWS, RelTypes.FIGHTS); 149 | assertTrue(hasRelationship); 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestTestBase.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | 4 | import org.junit.After; 5 | import org.junit.AfterClass; 6 | import org.junit.Before; 7 | import org.junit.BeforeClass; 8 | import org.neo4j.graphdb.Direction; 9 | import org.neo4j.graphdb.GraphDatabaseService; 10 | import org.neo4j.graphdb.Node; 11 | import org.neo4j.graphdb.Relationship; 12 | 13 | import java.net.URISyntaxException; 14 | import java.util.Iterator; 15 | 16 | public class RestTestBase { 17 | 18 | private GraphDatabaseService restGraphDb; 19 | private static final String HOSTNAME = "localhost"; 20 | private static final int PORT = 7473; 21 | private static LocalTestServer neoServer = new LocalTestServer(HOSTNAME,PORT).withPropertiesFile("neo4j-server.properties"); 22 | private static final String SERVER_ROOT_URI = "http://" + HOSTNAME + ":" + PORT + "/db/data/"; 23 | private static final String SERVER_CLEANDB_URI = "http://" + HOSTNAME + ":" + PORT + "/cleandb/secret-key"; 24 | private static final String CONFIG = RestTestBase.class.getResource("/neo4j-server.properties").getFile(); 25 | 26 | @BeforeClass 27 | public static void startDb() throws Exception { 28 | neoServer.start(); 29 | } 30 | 31 | @Before 32 | public void setUp() throws URISyntaxException { 33 | neoServer.cleanDb(); 34 | restGraphDb = new RestGraphDatabase(SERVER_ROOT_URI); 35 | } 36 | 37 | @After 38 | public void tearDown() throws Exception { 39 | restGraphDb.shutdown(); 40 | } 41 | 42 | @AfterClass 43 | public static void shutdownDb() { 44 | neoServer.stop(); 45 | 46 | } 47 | 48 | protected Relationship relationship() { 49 | Iterator it = node().getRelationships(Direction.OUTGOING).iterator(); 50 | if (it.hasNext()) return it.next(); 51 | return node().createRelationshipTo(restGraphDb.createNode(), Type.TEST); 52 | } 53 | 54 | protected Node node() { 55 | return restGraphDb.getReferenceNode(); 56 | } 57 | 58 | protected GraphDatabaseService getGraphDatabase() { 59 | return neoServer.getGraphDatabase(); 60 | } 61 | 62 | protected GraphDatabaseService getRestGraphDb() { 63 | return restGraphDb; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestTraversalExecutionTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.neo4j.graphdb.Node; 6 | import org.neo4j.graphdb.Relationship; 7 | import org.neo4j.graphdb.traversal.TraversalDescription; 8 | import org.neo4j.graphdb.traversal.Traverser; 9 | import org.neo4j.rest.graphdb.traversal.RestTraversal; 10 | 11 | public class RestTraversalExecutionTest extends RestTestBase { 12 | @Test 13 | public void testTraverseToNeighbour() { 14 | final Relationship rel = relationship(); 15 | final TraversalDescription traversalDescription = RestTraversal.description().maxDepth(1).breadthFirst(); 16 | System.out.println("traversalDescription = " + traversalDescription); 17 | final Traverser traverser = traversalDescription.traverse(rel.getStartNode()); 18 | final Iterable nodes = traverser.nodes(); 19 | Assert.assertEquals(rel.getEndNode(), nodes.iterator().next()); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/RestTraversalTest.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.neo4j.graphdb.traversal.TraversalDescription; 7 | import org.neo4j.kernel.Uniqueness; 8 | import org.neo4j.rest.graphdb.traversal.RestTraversal; 9 | import org.neo4j.rest.graphdb.traversal.RestTraversalDescription; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * @author Michael Hunger 15 | * @since 03.02.11 16 | */ 17 | public class RestTraversalTest { 18 | private RestTraversal traversalDescription; 19 | 20 | @Before 21 | public void setUp() throws Exception { 22 | traversalDescription = (RestTraversal) RestTraversal.description(); 23 | } 24 | 25 | @Test 26 | public void testUniqueness() throws Exception { 27 | traversalDescription.uniqueness(Uniqueness.NODE_PATH); 28 | Assert.assertEquals("node path", getPostData("uniqueness")); 29 | } 30 | 31 | @Test 32 | public void testUniquenessWithValue() throws Exception { 33 | traversalDescription.uniqueness(Uniqueness.NODE_PATH,"test"); 34 | String param = "uniqueness"; 35 | final Map uniquenessMap = (Map) getPostData(param); 36 | Assert.assertEquals("node path", uniquenessMap.get("name")); 37 | Assert.assertEquals("test", uniquenessMap.get("value")); 38 | } 39 | 40 | private Object getPostData(String param) { 41 | return traversalDescription.getPostData().get(param); 42 | } 43 | 44 | @Test 45 | public void testPruneScript() throws Exception { 46 | traversalDescription.prune(RestTraversalDescription.ScriptLanguage.JAVASCRIPT, "return true;"); 47 | Map pruneEvaluator= (Map) getPostData("prune_evaluator"); 48 | Assert.assertEquals("javascript", pruneEvaluator.get("language")); 49 | Assert.assertEquals("return true;", pruneEvaluator.get("body")); 50 | } 51 | 52 | @Test 53 | public void testFilterScript() throws Exception { 54 | traversalDescription.filter(RestTraversalDescription.ScriptLanguage.JAVASCRIPT, "return true;"); 55 | Map pruneEvaluator= (Map) getPostData("return_filter"); 56 | Assert.assertEquals("javascript", pruneEvaluator.get("language")); 57 | Assert.assertEquals("return true;", pruneEvaluator.get("body")); 58 | } 59 | 60 | @Test 61 | public void testEvaluator() throws Exception { 62 | 63 | } 64 | 65 | @Test 66 | public void testPrune() throws Exception { 67 | 68 | } 69 | 70 | @Test 71 | public void testFilter() throws Exception { 72 | 73 | } 74 | 75 | @Test 76 | public void testMaxDepth() throws Exception { 77 | 78 | } 79 | 80 | @Test 81 | public void testOrder() throws Exception { 82 | 83 | } 84 | 85 | @Test 86 | public void testDepthFirst() throws Exception { 87 | 88 | } 89 | 90 | @Test 91 | public void testBreadthFirst() throws Exception { 92 | 93 | } 94 | 95 | @Test 96 | public void testRelationships() throws Exception { 97 | 98 | } 99 | 100 | @Test 101 | public void testRelationshipsAndDirection() throws Exception { 102 | 103 | } 104 | 105 | @Test 106 | public void testExpand() throws Exception { 107 | 108 | } 109 | @Test 110 | public void testComplexTraversal() throws Exception { 111 | 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/test/java/org/neo4j/rest/graphdb/Type.java: -------------------------------------------------------------------------------- 1 | package org.neo4j.rest.graphdb; 2 | 3 | import org.neo4j.graphdb.RelationshipType; 4 | 5 | /** 6 | * @author mh 7 | * @since 24.01.11 8 | */ 9 | enum Type implements RelationshipType { 10 | TEST 11 | } 12 | -------------------------------------------------------------------------------- /src/test/resources/neo4j-server.properties: -------------------------------------------------------------------------------- 1 | org.neo4j.server.database.location=neo4j-home/data 2 | #org.neo4j.server.bundledir=neo4j-home/bundles 3 | #org.neo4j.webserver.port=7474 4 | # 5 | #org.neo4j.server.thirdparty_jaxrs_classes=org.neo4j.server.extension.test.delete=/cleandb 6 | #org.neo4j.server.thirdparty.delete.key=secret-key 7 | # 8 | #org.neo4j.server.webadmin.rrdb.location=neo4j-home/rrd 9 | #org.neo4j.server.webadmin.data.uri=/db/data/ 10 | #org.neo4j.server.webadmin.management.uri=/db/manage/ 11 | # 12 | #org.neo4j.export.basepath=neo4j-home/export 13 | --------------------------------------------------------------------------------