neo4j-contrib / java-rest-binding

Java Bindings for the Neo4J Server REST API, providing an implementation of GraphDatabaseService
Other
120 stars 72 forks source link

getReferenceNode throws Error #19

Open wallacemann opened 12 years ago

wallacemann commented 12 years ago

We are trying to switch from running as an embedded DB to using a Neo4j server and hit a consistent problem. It's occurring frequently enough that there must be something obvious we are doing wrong. This error shows up lots of places, but this is the simplest example I have.

In a call to myRestGraphDb.getReferenceNode(), we get the following:

Exception in thread "main" java.lang.RuntimeException: Error reading as JSON '' at org.neo4j.rest.graphdb.util.JsonHelper.readJson(JsonHelper.java:57) at org.neo4j.rest.graphdb.util.JsonHelper.jsonToSingleValue(JsonHelper.java:62) at org.neo4j.rest.graphdb.RequestResult.toEntity(RequestResult.java:114) at org.neo4j.rest.graphdb.RequestResult.toMap(RequestResult.java:120) at org.neo4j.rest.graphdb.ExecutingRestAPI.getReferenceNode(ExecutingRestAPI.java:263) at org.neo4j.rest.graphdb.RestAPIFacade.getReferenceNode(RestAPIFacade.java:107) at org.neo4j.rest.graphdb.RestGraphDatabase.getReferenceNode(RestGraphDatabase.java:69) at com.rootmusic.data.hadoop.database.neo4j.NeoQueryHelper.clearReference(NeoQueryHelper.java:203) at com.rootmusic.data.hadoop.database.neo4j.BuildNeo.testRemote(BuildNeo.java:189) at com.rootmusic.data.hadoop.database.neo4j.BuildNeo.main(BuildNeo.java:34) Caused by: java.io.EOFException: No content to map to Object due to end of input at org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.java:2437) at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2389) at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1595) at org.neo4j.rest.graphdb.util.JsonHelper.readJson(JsonHelper.java:55) ... 9 more

This error also occurs when we call node.getSingleRelationship and there does not exist a relationship. The embedded code returns null. The rest API throws the same exceptions.

We are using:

 Neoj4 1.8.M07 for both embedded and on the server   
 jackson-mapper-asl 1.8.5
 java 1.6
 server is running on Amazon AWS linux, clients are mac w/ OS X and PC w/ linux (same error on both clients)

Any thoughts, suggestions or solutions would be appreciated.

Warm regards, Wallace

wallacemann commented 12 years ago

Here is an update from our explorations. This may be unrelated and deserving of it's own post, but I'll put it here for now.

CODE SNIPPET: Here is a simple code snippet. It just looks for a node, opens a transaction, and looks for the same node several times again. What is unusual is that the behavior inside and outside of a transaction are different.

public static void testRemoteRaw(GraphDatabaseService db) throws IOException {

 System.out.println("Simple test of remote db ...");

int key = 12345;

// LOOK FOR THE NODE 1st time

Index<Node> nodeIndex = db.index().forNodes("INDEX");

IndexHits<Node> hits = nodeIndex.get("key", key);

if (hits.size() > 0) {

    Node node = hits.getSingle();

    System.out.println("Node 1 = " + node);

}

Transaction tx = db.beginTx();

// LOOK FOR THE NODE 2nd time

nodeIndex = db.index().forNodes("INDEX");

hits = nodeIndex.get("key", key);

if (hits.size() > 0) {

    Node node = hits.getSingle();

    System.out.println("Node 2 = " + node);

}

 try {

    nodeIndex = db.index().forNodes("INDEX");

    hits = nodeIndex.get("key", key);

    if (hits.size() == 0) {

             // CREATE THE NODE

        String name = "Joe Bob Briggs";

        System.out.println("Creating the node");

        Node node = db.createNode();

        node.setProperty("name", name);

        // Put in index

        nodeIndex.add(node, "key", key);

           tx.success();

        }

}

finally {

         tx.finish();

}

// LOOK FOR THE NODE 3rd time

nodeIndex = db.index().forNodes("INDEX");

hits = nodeIndex.get("key", key);

if (hits.size() > 0) {

     Node node = hits.getSingle();

     System.out.println("Node 3 = " + node);

}

}

CODE OUTPUT: FIRST TIME RUN: This is as expected. It does not find the node, creates the node, and then finds the node after the transaction is complete.

 Simple test of remote db ...

 Creating the node

 Node 3 = http://<url-omitted>/db/data/node/94

SECOND TIME RUN: The Node 1 find is as expected, the node is still there. However, immediately after opening the transaction, the exact same statement (Node 2) fails to find the node, so the node is created again. Why does the starting of a transaction cause the node finding to fail?

Simple test of remote db ...

Node 1 = http://<url-omitted>/db/data/node/94

Creating the node

Node 3 = http:///<url-omitted>/db/data/node/94
jexp commented 12 years ago

Wallace,

good point, so I'll try to align the exception behavior with the core-API, if you find other places than just getReferenceNode() (which imho also throws an exception if there is none in the core-API) and getSingleRelationship() please let me know.

Regarding transactions, please note the readme. Transactions are not supported on the remote-API as such. What it does is too collect all your operations between db.beginTx() and tx.finish() and sends it over to the server as a single batch-reest-request, so that all read-operations are deferred and result object will actually only return data when the transaction is finished. This goes for all, findNodeById, getRelationships and index-lookups.

So this "transaction"-mode is not suitable to make decisions based on reads but only for batching operations into single requests which will also execute on the server-side as a single tx.

HTH

wallacemann commented 12 years ago

Ah! OK. Thanks for the reply.

For the API alignment, I think that node.getRelationships has the same issue.

But our real issue stems from the misunderstanding of how transactions work. Great. Thank you. That's very helpful.

But we do have one question. We were looking at the test code: https://github.com/neo4j/java-rest-binding/blob/master/src/test/java/org/neo4j/rest/graphdb/Neo4jDatabaseCleaner.java

And it has a read (Node refNode = graph.getReferenceNode();) inside of a transaction which, as you describe, fails. But, I presume the test code is supposed to work? Or maybe it used to work?

Thanks, Wallace

jexp commented 12 years ago

This class works on embedded databases in the test setup, it is only there to be used for testing in other projects that use java-rest-binding. Should probably be moved to the test folders.

jexp commented 12 years ago

@wallacemann according to the docs of GraphDatabaseService.getReferenceNode() it throws an NotFoundException on error. Could you specify the context in which you get the JSON exception?

I added tests for getSingleRelationship() and hasSingleRelationship() which both worked.

jexp commented 12 years ago

@wallacemann can you outline further inconsistencies?

wallacemann commented 12 years ago

Sorry. Got busy with work. I will follow up as soon as I can.