Hot questions for Using Neo4j in rest

Question:

I'm starting to use the Neo4j Rest Api but when I try to connect the server I get the following error :

{
  "errors" : [ {
    "code" : "Neo.ClientError.Security.AuthorizationFailed",
    "message" : "No authorization header supplied."
  } ]
}

This error seems to be normal because I am not authenticating to the server when I use my requests. In the Neo4j 2.2.2 manual (http://neo4j.com/docs/stable/rest-api-security.html) I've read I'm getting this error because :

Requests should include an Authorization header, with a value of Basic , where "payload" is a base64 encoded string of "username:password". Example request GET http://localhost:7474/user/neo4j Accept: application/json; charset=UTF-8 Authorization: Basic bmVvNGo6c2VjcmV0

But I can't get rid of this error because I don't know how to include the header in my requests ! Here is an example of a request in my code :

WebResource resource = Client.create().resource( nodeEntryPointUri );   
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )
                .type( MediaType.APPLICATION_JSON )
                .entity( "{\"data\" : \"nex\"}" )
                .post( ClientResponse.class );      
response.close();

So if anyone can help me to authenticate to the server with my requests, that could be really helpful !

Thanks


Answer:

In Jersey 1.x you can supply your client instance with a filter dealing with authentication:

Client client = Client.create()
client.addFilter(new HTTPBasicAuthFilter("neo4j","<mypwd>")); // <-- that's it!
WebResource resource = client.resource(
    "http://localhost:7474/db/data/transaction/commit"
);

ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )
   .type( MediaType.APPLICATION_JSON )
   .post( ClientResponse.class, someStringContainingJsonPayload);

Question:

We are willing to have neo4j on production.

I tried to look at the docs and understand if the way to communicate with neo4j only by REST or whether we have other protocols to do that?

We planning to have thousands of requests per sec and we worried that http rest wont be good for us as protocol.

Any clarification about that? Thanks, ray.


Answer:

Currently only protocol which is supported by Neo4j is HTTP.

Neo4j version 3.0 will contains binary protocol.


REST is one option, you can choose drivers for your programming language

Question:

OS : Kubuntu 15.10 Neo4J Version : 2.3.1 Java Version : JDK 1.8

There are two ways of running a neo4j instance. 1. Server 2. Local

In server we need to run /bin/neo4j start and the path specified in the server config file needs to be empty, else it will throw error

In local mode i.e shell mode, /bin/neo4j-shell again we can run localy or we can specify the ip:port, unfotunately we cannot specify ip:port with db:path.

I am following this tutorial: http://www.tutorialspoint.com/neo4j/neo4j_native_java_api_example.htm, in the end, for windows there is a GUI where in we can select the database and we can view in Web Gui localhost:7474

Question:

How to start a server locally/remote with WebUI Admin Console on a pre-existing neo4j database?

Edit:

Neo4J.java

package com.tp.neo4j.java.examples;

import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;

public class Neo4J {
public static void main(String[] args) {
    GraphDatabaseFactory dbFactory = new GraphDatabaseFactory();
    GraphDatabaseService db= dbFactory.newEmbeddedDatabase("data/graph.db");
    try (Transaction tx = db.beginTx()) {

        Node javaNode = db.createNode(Tutorials.JAVA);
        javaNode.setProperty("TutorialID", "JAVA001");
        javaNode.setProperty("Title", "Learn Java");
        javaNode.setProperty("NoOfChapters", "25");
        javaNode.setProperty("Status", "Completed");                

        Node scalaNode = db.createNode(Tutorials.SCALA);
        scalaNode.setProperty("TutorialID", "SCALA001");
        scalaNode.setProperty("Title", "Learn Scala");
        scalaNode.setProperty("NoOfChapters", "20");
        scalaNode.setProperty("Status", "Completed");

        Relationship relationship = javaNode.createRelationshipTo
        (scalaNode,TutorialRelationships.JVM_LANGIAGES);
        relationship.setProperty("Id","1234");
        relationship.setProperty("OOPS","YES");
        relationship.setProperty("FP","YES");

        tx.success();
    }
       System.out.println("Done successfully");
  }
}

Server properties: org.neo4j.server.database.location=data/graph.db

Neo4j properties:

allow_store_upgrade=true
remote_shell_port=1337

Embedded Server properties in Java:

GraphDatabaseService db =dbFactory.newEmbeddedDatabase(new File("/opt/neo4j/data/graph.db")); 

Steps to reproduce the error:

  1. Run the Java Application. It creates db in the specified path.
  2. Modify the server properties in conf folder to point to the path specified in java
  3. Start neo4j : sudo neo4j start [Neo4J starts successfully if the db path mentioned in the server properties is empty]

Error

WARNING: Max 1024 open files allowed, minimum of 40 000 recommended. See the Neo4j manual.
Starting Neo4j Server.../opt/neo4j/data/log was missing, recreating...
WARNING: not changing user
process [3484]... waiting for server to be ready.... Failed to start within 120 seconds.
Neo4j Server may have failed to start, please check the logs. 

Log:

2015-12-29 07:35:55.276+0530 INFO  Successfully shutdown Neo4j Server
2015-12-29 07:35:55.277+0530 ERROR Failed to start Neo4j: Starting Neo4j failed: Component 'org.neo4j.server.database.LifecycleManagingDatabase@4ae673d' was successfully initialized, but failed to start. Please see attached cause exception. Starting Neo4j failed: Component 'org.neo4j.server.database.LifecycleManagingDatabase@4ae673d' was successfully initialized, but failed to start. Please see attached cause exception.
org.neo4j.server.ServerStartupException: Starting Neo4j failed: Component 'org.neo4j.server.database.LifecycleManagingDatabase@4ae673d' was successfully initialized, but failed to start. Please see attached cause exception.
    at org.neo4j.server.exception.ServerStartupErrors.translateToServerStartupError(ServerStartupErrors.java:67)
    at org.neo4j.server.AbstractNeoServer.start(AbstractNeoServer.java:234)
    at org.neo4j.server.Bootstrapper.start(Bootstrapper.java:97)
    at org.neo4j.server.CommunityBootstrapper.start(CommunityBootstrapper.java:48)
    at org.neo4j.server.CommunityBootstrapper.main(CommunityBootstrapper.java:35)
Caused by: org.neo4j.kernel.lifecycle.LifecycleException: Component 'org.neo4j.server.database.LifecycleManagingDatabase@4ae673d' was successfully initialized, but failed to start. Please see attached cause exception.
    at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:462)
    at org.neo4j.kernel.lifecycle.LifeSupport.start(LifeSupport.java:111)
    at org.neo4j.server.AbstractNeoServer.start(AbstractNeoServer.java:194)
    ... 3 more
Caused by: java.lang.RuntimeException: Error starting org.neo4j.kernel.impl.factory.CommunityFacadeFactory, /opt/neo4j/data/graph.db
    at org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.newFacade(GraphDatabaseFacadeFactory.java:143)
    at org.neo4j.kernel.impl.factory.CommunityFacadeFactory.newFacade(CommunityFacadeFactory.java:43)
    at org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.newFacade(GraphDatabaseFacadeFactory.java:108)
    at org.neo4j.server.CommunityNeoServer$1.newGraphDatabase(CommunityNeoServer.java:66)
    at org.neo4j.server.database.LifecycleManagingDatabase.start(LifecycleManagingDatabase.java:95)
    at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:452)
    ... 5 more
Caused by: org.neo4j.kernel.lifecycle.LifecycleException: Component 'org.neo4j.kernel.NeoStoreDataSource@2895e461' was successfully initialized, but failed to start. Please see attached cause exception.
    at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:462)
    at org.neo4j.kernel.lifecycle.LifeSupport.start(LifeSupport.java:111)
    at org.neo4j.kernel.impl.transaction.state.DataSourceManager.start(DataSourceManager.java:112)
    at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:452)
    at org.neo4j.kernel.lifecycle.LifeSupport.start(LifeSupport.java:111)
    at org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.newFacade(GraphDatabaseFacadeFactory.java:139)
    ... 10 more
Caused by: org.neo4j.kernel.impl.storemigration.StoreUpgrader$UnexpectedUpgradingStoreVersionException: '/opt/neo4j/data/graph.db/neostore.nodestore.db' has a store version number that we cannot upgrade from. Expected 'v0.A.3' but file is version '\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00'.
    at org.neo4j.kernel.impl.storemigration.UpgradableDatabase.checkUpgradeable(UpgradableDatabase.java:96)
    at org.neo4j.kernel.impl.storemigration.StoreUpgrader.migrateIfNeeded(StoreUpgrader.java:149)
    at org.neo4j.kernel.NeoStoreDataSource.upgradeStore(NeoStoreDataSource.java:636)
    at org.neo4j.kernel.NeoStoreDataSource.start(NeoStoreDataSource.java:527)
    at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:452)
    ... 15 more

Note: We can import only csv files, we cannot import a pre-existing neo4j db.

Note: Tried Java Rest Binding, but it seems to have lot issues, Maven issue, dependency issue.


Answer:

Not really sure what you're asking. You can run Neo4j with the Admin interface on database files on disk by setting the database path in conf/neo4j-server.properties pointing to your database store location.

Question:

While sending off Cypher queries to Neo4J's transactional Cypher API, I am running into the following error:

Neo.ClientError.Request.InvalidFormat Unable to deserialize request: Unrecognized character escape ''' (code 39)

My Cypher query looks like this

MATCH (n:Test {id:'test'}) SET n.`label` = 'John Doe\'s house';

While this query works just fine when executed in Neo4J's browser interface it fails when using the REST API. Is this a bug or am I doing something wrong? In case this is not a bug, how do I have to escape ' to get it working in both?

Edit: I found this answer and tested the triple single and triple double quotes but they just caused another Neo.ClientError.Request.InvalidFormat error to be thrown.

Note: I am using Neo4J 2.2.2

Note 2: Just in case it's important, below is the JSON body I am sending to the endpoint.

{"statements":[
  {"statement": "MATCH (n:Test {id:'test'}) SET n.`label` = 'John Doe\'s house';"}
]}

Answer:

You'll have to escape the \ too:

{"statements":[
  {"statement": "MATCH (n:Test {id:'test'}) SET n.`label` = 'John Doe\\'s house';"}
]}

But if you use parameters (recommended), you can do

{"statements":[
  {"statement": "MATCH (n:Test {id:'test'}) SET n.`label` = {lbl}",
   "parameters" : {"lbl" : "Jane Doe's house"}
  }

]}

Question:

I would like to query a Neo4j server by sending a Cypher query to it and receive the output as some kind of table.

I have read that people using RestCypherQueryEngine, but the neo4j-contrib/java-rest-binding says on github that "this library is no longer maintained".

So what is the usual, non-deprecated way to contact a Neo4j server from java (via REST?), send it a Cypher query with parameters, receive the result and interpret it as some kind of table?


Answer:

It seems that the Neo4j Java Driver is the preferred way to execute Cypher queries.

https://neo4j.com/developer/java/#neo4j-java-driver

Queries can be run as

StatementResult result = session.run( "MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title" );
while ( result.hasNext() )
{
    Record record = result.next();
    System.out.println( record.get( "title" ).asString() + " " +  record.get("name").asString() );
}

Question:

I have created an AWS EC2 instance running Neo4j(Community AMI) and i have connected to the end point successfully through the browser.now i want to access my db from java application through the Restbinding

    `RestAPI graphDB = new RestAPIFacade("EC2_ENDPOINT:7474/db/data/");
    QueryEngine engine=new RestCypherQueryEngine(graphDB); 

     QueryResult<Map<String,Object>> result = engine.query("start n=node(*) return count(n) as total", Collections.EMPTY_MAP); 

     Iterator<Map<String, Object>> iterator=result.iterator(); 

     if(iterator.hasNext()) { 

       Map<String,Object> row= iterator.next(); 

       System.out.print("Total nodes: " + row.get("total")); ` 

i have tested this code for localhost and got results but when i try this this Exception occurs!

Exception in thread "main" java.lang.RuntimeException: Error reading as JSON '<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 404 Not Found</title>
</head>
<body><h2>HTTP ERROR 404</h2>
<p>Problem accessing /db/data/cypher. Reason:
<pre>    Not Found</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>                                                
<br/>   

Answer:

Can you access your database manually using http://EC2_ENDPOINT:7474/db/data/ ?

Did you open the port in the AWS security config. And did you configure your Neo4j server in conf/neo4j-server.properties to listen on the public interface?

Question:

I have built a RESTful web service for Wildfly using Neo4j OGM, but when I access it I get a NullPointerException. It seems that a Map that should be populated with my model classes has not been initialized by the time it is accessed. Why is this happening?

Upfront I have to say that this module, salessupport-ui, is currently implemented as a fat client using javafx and it works fine connecting to the neo4j community edition 2.2.4, reading, writing, no problem. What I would like to do now and this is where I face problems, I want to use wildfly as a server which itself connects to neo4j, thus that the javafx client application sends requests only to the wildfly server. The protocol which I decided to use is REST, the implementation which is already kind-of provided on wildfly is resteasy.

Below are 1) the exception and some debugging info, 2) details about my context, project structure and the code for my classes.

1. Problem

Here are the exception and my findings when debugging.

Exception

Now when I call this REST service by entering http://localhost:8080/salessupport-restsvc/rest/address/list in the browser, the following exception is raised:

00:07:38,458 ERROR [io.undertow.request] (default task-5) UT005023: Exception handling request to /salessupport-restsvc/rest/address/list: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76)
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:212)
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:149)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:372)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:80)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:172)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:774)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at org.neo4j.ogm.metadata.MetaData.entityType(MetaData.java:231)
at org.neo4j.ogm.session.Neo4jSession.entityType(Neo4jSession.java:451)
at org.neo4j.ogm.session.delegates.LoadByTypeDelegate.loadAll(LoadByTypeDelegate.java:55)
at org.neo4j.ogm.session.delegates.LoadByTypeDelegate.loadAll(LoadByTypeDelegate.java:94)
at org.neo4j.ogm.session.Neo4jSession.loadAll(Neo4jSession.java:114)
at groupid.salessupport.db.core.ApplicationContext$GraphRepositoryImpl.findAll(ApplicationContext.java:74)
at groupid.salessupport.restsvc.impl.SimpleRestGraphRepositoryImpl.findAll(SimpleRestGraphRepositoryImpl.java:29)
at groupid.salessupport.restsvc.impl.AddressRestImpl$Proxy$_$$_WeldClientProxy.findAll(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:137)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:296)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:250)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:237)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356)
... 32 more
Debugging info
  • By debugging I can see that it goes, as expected, to my first breakpoint in class SimpleRestGraphRepositoryImpl, method findAll() calling repository.findAll();
  • 2nd also expected, it goes to the inner GraphRepositoryImpl class to method findAll(...) and line context.getSession().loadAll(clazz); which creates a Session.
  • A few steps later it tries in org.neo4j.ogm.metadata.MetaData class in method _classInfo(String,String,String) to call domainInfo.getClassInfosWithAnnotation(nodeEntityAnnotation); where nodeEntityAnnotation="org.neo4j.ogm.annotation.NodeEntity".
  • In the DomainInfo class method getClassInfosWithAnnotation which is then invoked the map annotationNameToClassInfo is empty. I expect it to be filled with my models, which obviously happens in the javafx environment, but not in the JavaEE env.

here is that method

public List<ClassInfo> getClassInfosWithAnnotation(String annotation) {
    return annotationNameToClassInfo.get(annotation);
}

For checking, if the REST mechanism works as is I put a class next to the AddressRestImpl>

@Path("dummy")
public class DummyImpl {
    @GET
    @Path("list")
    @Produces(MediaType.APPLICATION_JSON)
    public List<Amount> getAll() {
        return Arrays.asList(new Amount());
    }
}

Calling this in the browser by navigating to http://localhost:8080/salessupport-restsvc/rest/dummy/list results in the expected: [{"amount":null,"currency":null}]

I have plenty of simple stuff to improve here, I have tried quite a lot of approaches, also on Tomcat 8 the same exception happens, but there the Rest approach did not work even in the dummy case so I switched to wildfly. Did I find a bug here or is there something simply I have missed in my setup?

2) Project and Code Details

Here is information about my environment, project structure and the code I run when I have this problem.

Environment

My environment is as follows:

I have Neo4J community edition 2.2.4.

I downloaded wildfly-9.0.1.Final and, except for a management port which conflicted with my NVidia Driver Software I left everything untouched.

Project Structure

I have a maven multimodule application which consists of the following modules:

<modules>
    <module>salessupport-ui</module>
    <module>salessupport-intf</module>
    <module>salessupport-db</module>
    <module>salessupport-restsvc</module>
</modules>

The dependencies are as follows:

salessupport-intf <-- salessupport-db
                          ^
                          |-- salessupport-ui
                          |-- salessupport-restsvc
Dependencies

Let me explain the dependencies:

salessupport parent has a dependency management definition like this:

<dependencyManagement>
    <dependencies>

        ...

        <dependency>
            <groupId>org.neo4j</groupId>
            <artifactId>neo4j-ogm</artifactId>
            <version>1.1.2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.neo4j.app</groupId>
                    <artifactId>neo4j-server</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</dependencyManagement>

salessupport-intf uses the following dependencies:

<dependencies>
    <dependency>
        <groupId>org.neo4j</groupId>
        <artifactId>neo4j-ogm</artifactId>
    </dependency>

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.0.0.GA</version>
    </dependency>

    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>jsr311-api</artifactId>
        <version>1.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.12</version>
    </dependency>

</dependencies>

salessupport-restsvc pom.xml is

<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>groupid</groupId>
    <artifactId>salessupport</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>salessupport-restsvc</artifactId>
<name>salessupport-restsvc</name>
<url>http://maven.apache.org</url>
<properties>
    <jersey.version>1.19</jersey.version>
    <resteasy.version>3.0.11.Final</resteasy.version>
</properties>

<dependencies>
    <dependency>
        <groupId>groupid</groupId>
        <artifactId>salessupport-intf</artifactId>
    </dependency>
    <dependency>
        <groupId>groupid</groupId>
        <artifactId>salessupport-db</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>${resteasy.version}</version>
        <scope>provided</scope>
        <exclusions>
            <exclusion>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>jaxrs-api</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-multipart-provider</artifactId>
        <version>${resteasy.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
</dependencies>

<packaging>war</packaging>

<build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <version>${version.war.plugin}</version>
            <configuration>
                <!-- webXml>src\main\webapp\WEB-INF\web.xml</webXml -->
                <failOnMissingWebXml>false</failOnMissingWebXml>
                <packagingExcludes>
                    org.neo4j.server.rest.discovery,
                    org.neo4j.server.rest.web
                </packagingExcludes>
            </configuration>
        </plugin>
    </plugins>
</build>
</project>
Code

Here are the relevant classes.

GraphRepository interface

I defined my custom GraphRepository interface:

public interface GraphRepository<S> {

    Iterable<S> findAll(Iterable<Long> nodeIds);

    Iterable<S> findAll();

    void delete(S arg0);

    S save(S arg0);

}
Model Classes

There are some model classes, e.g.:

package groupid.salessupport.db.model;

import java.text.DecimalFormat;

import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;

@NodeEntity(label="Amount")
public class Amount {

    @GraphId Long id;

    private Double amount;

    private Currency currency;

    public Currency getCurrency() {
        return currency;
    }

    public void setCurrency(Currency currency) {
        this.currency = currency;
    }

    public Double getAmount() {
        return amount;
    }

    public void setAmount(Double amount) {
        this.amount = amount;
    }

    @Override
    public String toString() {
        return new DecimalFormat().format(amount)+" "+currency;
    }

}

and

@NodeEntity(label="Currency")
public class Currency extends BaseObject {
    @Override
    public String toString() {
        return getName();
    }
}
Generic Simple Rest Graph Repository interface
public interface ISimpleRestGraphRepository<T> {
    @DELETE
    @Path("delete")
    @Consumes(MediaType.APPLICATION_JSON)
    public void delete(T arg0);

    @PUT
    @Path("save")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public T save(T arg0);

    @GET
    @Path("list")
    @Produces(MediaType.APPLICATION_JSON)
    public Iterable<T> findAll();

    @POST
    @Path("listbyids")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Iterable<T> findAll(Iterable<Long> arg0);
}
REST Interface Definition for Amount
@Path("amount")
public interface AmountRest extends ISimpleRestGraphRepository<Amount> {
}
REST Activator
@ApplicationPath("/rest")
public class JaxRsActivator extends Application {
}
Generic implementation of my REST Service
@RequestScoped
public class SimpleRestGraphRepositoryImpl<T> implements ISimpleRestGraphRepository<T> {

    private final GraphRepository<T> repository;

    public SimpleRestGraphRepositoryImpl(GraphRepository<T> repository) {
        this.repository = repository;
    }

    @Override
    public void delete(T arg0) {
        repository.delete(arg0);
    }

    @Override
    public T save(T arg0) {
        return repository.save(arg0);
    }

    @Override
    public Iterable<T> findAll() {
        return repository.findAll();
    }

    @Override
    public Iterable<T> findAll(Iterable<Long> arg0) {
        return repository.findAll(arg0);
    }

}
... and the specific Implementation for Address:
public class AmountRestImpl extends SimpleRestGraphRepositoryImpl<Amount> implements AmountRest {

    public AmountRestImpl() {
        super(NeoRepositories.getInstance().getAmountRepository());
    }

}
DB Connection

in salessupport-db we connect to the database with some code:

public class ApplicationContext {
    private SessionFactory sessionFactory;
    private Session openSession;

    public ApplicationContext() {

    }

    public SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            sessionFactory = new SessionFactory("groupid.salessupport.db.model");
        }
        return sessionFactory;
    }

    public Session getSession() {
        if (openSession == null) {
            openSession = getSessionFactory().openSession("http://localhost:7474",
                    "username", "password"); // it is not really like this     
    }
        return openSession;
    }

    public <S,G extends GraphRepository<S>> GraphRepository<S> getGraphRepository(Class<S> clazz) {
        return new GraphRepositoryImpl<S>(this, clazz);
    }

    public static class GraphRepositoryImpl<S> implements GraphRepository<S> {
        private ApplicationContext context;
        private Class<S> clazz;

        public GraphRepositoryImpl(ApplicationContext context, Class<S> clazz) {
            this.context = context;
            this.clazz = clazz;
        }

        @Override
        public Iterable<S> findAll(Iterable<Long> nodeIds) {
            List<Long> listNodeIds;
            if (nodeIds instanceof List) {
                listNodeIds = (List<Long>) nodeIds;
            } else {
                listNodeIds = new LinkedList<>();
                for (Long l : nodeIds) {
                    listNodeIds.add(l);
                }
            }
            return context.getSession().loadAll(clazz,listNodeIds);
        }

        @Override
        public Iterable<S> findAll() {
            return context.getSession().loadAll(clazz);
        }

        @Override
        public void delete(S arg0) {
            Session session = context.getSession();
            Transaction transaction = session.beginTransaction();
            context.getSession().delete(arg0);
            transaction.commit();
            transaction.close();
        }

        @Override
        public S save(S arg0) {
            Session session = context.getSession();
            Transaction transaction = session.beginTransaction();
            session.save(arg0);
            transaction.commit();
            transaction.close();
            return arg0;
        }

    }

}
Usage

Implementors acquire an instance of this GraphRepository quick and dirty with a "singleton":

public class NeoRepositories {
private ApplicationContext context;

private static final NeoRepositories INSTANCE = new NeoRepositories();

private NeoRepositories() {
    context = new ApplicationContext();
}

public GraphRepository<Person> getPersonRepository() {
    return context.getGraphRepository(Person.class);
}

public static NeoRepositories getInstance() {
    return INSTANCE;
}

public GraphRepository<Amount> getAmountRepository() {
    return context.getGraphRepository(Amount.class);
}
...
}

P.S.: It is my first question on stackoverflow, I hope I wrote as little and as much as necessary to convey the problem ...


Answer:

Is this @NodeEntity from Spring Data Neo4j? If yes, Spring must be setup correctly, which I cannot find here.

Question:

I am working on a Spring Boot application that uses Neo4j for data storage,

I have a relationship of SkillCategory and Skills. So one SKillCategory contains many skills. Below is the Domain structure:

Skill.java

@NodeEntity
public class Skill extends BaseEntity {
    private String name;
    private boolean isVerified;
    private boolean isEnabled = true;
    @Relationship(type = SKILL_OF_LEVEL, direction = "OUTGOING")
    private SkillLevel skillLevel;

    public Skill() {
    }

    public Skill(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isEnabled() {
        return isEnabled;
    }

    public void setEnabled(boolean enabled) {
        isEnabled = enabled;
    }

    public boolean isVerified() {
        return isVerified;
    }

    public void setVerified(boolean verified) {
        isVerified = verified;
    }

    public SkillLevel getSkillLevel() {
        return skillLevel;
    }

    public void setSkillLevel(SkillLevel skillLevel) {
        this.skillLevel = skillLevel;
    }
}

SkillCategory.java

@NodeEntity
public class SkillCategory extends BaseEntity {
    private String name;
    private boolean isEnabled = true;
    @Relationship(type =  CONTAINS_SKILL,direction = "OUTGOING")
    private List<Skill> skillList;

    public SkillCategory() {
    }

    public SkillCategory(String name) {
        this.name = name;
    }

    public SkillCategory(String name, List<Skill> skillList) {
        this.name = name;
        this.skillList = skillList;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isEnabled() {
        return isEnabled;
    }

    public void setEnabled(boolean enabled) {
        isEnabled = enabled;
    }

    public List<Skill> getSkillList() {
        return skillList;
    }

    public void setSkillList(List<Skill> skillList) {
        this.skillList = skillList;
    }
}

I am using GraphRepository to perform CRUD operations. I am creating SkillCategory & Skills on application boot.

Here is the problem: if I delete the DB & start Spring Boot, everything works fine. But when I restart the Spring Boot application, skillList in SkillCategory is null.

If anyone have experience in Spring Data Neo4j, kindly help me narrow down the issue.

Repository Code :

@Repository
public interface SkillGraphRepository extends GraphRepository<Skill>{
List<SkillCategory> findAll();
}

I assume that if i fetch skillCategory it'll automatically eager load to fetch skills in SkillCategory also

I am simply using a Service that injects SkillCategoryRepository

skillCategoryService.create(new skillCategory("Category1"),Arrays.asList(new Skill("Skill 1"),new     SKill("Skill 2")));

Answer:

The data disappearance between start ups was caused by starting SDN with the embedded driver and an impermanent data store.

When setting the driver to: driver=org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver you must also make sure you set a location for the Neo4j datastore URI=file:///var/tmp/neo4j.db to make data persistable between start ups otherwise your data will only exist while the application is running.

More details can be found here.

Question:

I'm using Spring-data-neo4j 4.0.0 with Neo4j 2.3.1 and I'm wondering why when I do something like:

entityRepository.save(Iterable multipleObjects);

it actually does multiple REST calls on Neo4j server: - POST to create the transaction (done once, ok) - POST http://host:7474/db/data/transaction/id {"statements":[{"statement":"CREATE..."}]} (done once per object to save !) - POST to commit the transaction (done once, ok)

When it could group all entities creation into one REST POST call (with multiple statements).

I have performances issues with this use case, and I'm wondering if I don't use SDN correctly.

Or maybe this is a known problem that is planned to be improved in a near future ?


Answer:

You're using it correctly- it's a known issue and will be fixed in a future release.

Question:

I have two simple classes for testing a rest call on a neo4j server. I have placed the .jar file in the plugins directory with the path included such as:

gov/lanl/graphing/execute/rest/HelloWorldResource.class

I have modified the neo4j-server.properties file such as:

org.neo4j.server.thirdparty_jaxrs_class=
     gov.lanl.graphing.execute.rest=/gov/lanl/graphing/execute/rest

I think I have a lack of understanding regarding the above property.

Here are two classes, the HelloWorldResrource class is the one in the plugins direcotry. Note: there is some cooky cutter syntax so disregard the weird variable names and such.

This is extremely simple, and I think the problem is I don't understand how the path in the server.properties file is supposed to be represented in the Main class. Thanks for any help.

public class Resting {

    public static String URI = "http://localhost:7474/gov/lanl/graphing/execute/rest/helloworld/";
    public static void main (String[] args) {

        Client client = Client.create();
        client.addFilter(new LoggingFilter(System.out));
        WebResource cypher = client.resource(URI + "rico");
        ClientResponse cypherResponse = cypher.accept(MediaType.TEXT_PLAIN).get(ClientResponse.class);
        cypherResponse.close();
        System.out.println(cypherResponse);
    }
}


@Path("/helloworld")
public class HelloWorldResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/{name}")
    public Response hello(@PathParam("name") String name)
    {
        return Response.status(Status.OK).entity(
                ("hello there , " + name).getBytes(Charset.forName("UTF-8"))).build();
    }
}

Answer:

Ok, so after much wrangling of my j.v. code, I found a couple errors.

First off: org.neo4j.server.thirdparty_jaxrs_class= should be: org.neo4j.server.thirdparty_jaxrs_classes=

Secondly:

I didn't configure my .jar file correctly, I reconfigured this compilation to include the classpath and the descending directories, correctly. problem solved. on to more difficult problems....

Question:

I need to use Rest API to issue a merge query to execute for neo4j database. I am trying to refer the Neo4J manual, but it only defines for the case of creating nodes, relationships not executing queries of the like.

What needs to be done to execute a merge query? Is there any examples in the web? Thanks!!!

EDIT: I tried to use the following

 String response = resource.accept( MediaType.APPLICATION_JSON_TYPE )
                        .entity( query, MediaType.APPLICATION_JSON_TYPE )
                        .post( String.class );

With query = "{\"query\":\"MERGE (n:Person) RETURN n\"}", It creates the node

But when I try to add a property to the node like the following

  query = "{\"query\":\"MERGE (n:Person{name:"JRapid"}) RETURN n\"}"

I encountered the following error -

  Caused by: com.sun.jersey.api.client.UniformInterfaceException: POST http://localhost:7474/db/data/cypher returned a response status of 500 Internal Server Error

Is there any other way to specify the properties while issuing merge command in REST API?


Answer:

You should find a detailed error message in the response or logs

Double escape your quotes around the name or use single quotes

Better use parameters

And try to use the transactional endpoint

From Mobile, so w/o code or links

Question:

I am creating some nodes within a transaction in neo4j using the rest api. After all nodes have been created (typically between 3 and 5 in one transaction), I have to create some relationships between them. To do this I need, of course the location of the nodes, and this is the source of my problem. I can't figure out how to get this location.

According to documentation, I should be able to get the location of a node from the response-object, after creating the node, like so:

nodeLocation = response.getLocation();

But in a transaction, this of course returns the url of the transaction:

http://localhost:7474/db/data/transaction/108

Then I thought, if I query for the just created node, maybe in that response I can find the location. Again, according to documentation, the node location should be presented in the json-structure extensions in the field self.

 "self" : "http://localhost:7474/db/data/node/357",

But my response to the query does not seem to contain an extension structure.

This is the query I'm using:

 {"statements": [ {"statement": "MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p"} ] }

I send it to the open transaction, and I get this back:

 GET to http://localhost:7474/db/data/transaction/108 returned status code 200, returned data: {"commit":"http://localhost:7474/db/data/transaction/108/commit","results":[{"columns":["p"],"data":[]}],"transaction":{"expires":"Mon, 24 Nov 2014 20:40:34 +0000"},"errors":[]}

Just for completeness, this is the code for my query:

 String payload = "{\"statements\": "
                + "[ "
                    + "{\"statement\": "
                        + "\"MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p\""
                    + "} "
                + "] "
            + "}";


        logger.trace("sending cypher {} to endpoint {}", payload, endpointLoc);
        WebResource resource = Client.create().resource( endpointLoc );

        ClientResponse response = resource
                .accept( MediaType.APPLICATION_JSON )
                .type( MediaType.APPLICATION_JSON )
                .entity( payload )
                .get(ClientResponse.class);
                //.post( ClientResponse.class );

        String responseEntity = response.getEntity(String.class).toString();
        int responseStatus = response.getStatus();
        logger.trace("GET to {} returned status code {}, returned data: {}",
                endpointLoc, responseStatus,
                responseEntity);

        JSONParser reponseParser = new JSONParser();
            Object responseObj = reponseParser.parse(responseEntity);
            JSONObject jsonResponseObj = responseObj instanceof JSONObject ?(JSONObject)   responseObj : null;
            if(jsonResponseObj == null)
                throw new ParseException(0, "returned json object is null");

            String result = (String) jsonResponseObj.get("results").toString();
            logger.trace("result is {} ", result);

            String error = (String) jsonResponseObj.get("errors").toString();

Am I missing something? Do I need to use a special call?

Can someone help me with this? Thanks in advance,

Christian


Answer:

What do you need the node-URL for?

That's the old RESTful representation. You can either get it by using the old HTTP endpoint /db/data/cypher or better by specifying the (very verbose) resultDataContents type REST You can also specify other types like "row" and "graph" in parallel.

 {"statements": [ 
   {"statement": "MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p",
    "resultDataContents":["REST"]} 
 ] }