Warning: Trying to access array offset on value of type bool in /home/www/blog/wp-content/themes/catch-box/functions.php on line 1079

Neo4j REST Server, GWT and JIT Part 1

This is a Proof of Concept (from GTUG BootCamp 2010), which is: Try to code a complete client side data-load (from some REST services) and graph visualization using Neo4j REST server, the Java Script Visualization Framework JIT and Google Web Toolkit.

[update] this is how it looks like today

[/update]

What to read to understand of what I am talking about:

And – since I am new to GWT and JavaScript all this can be complete bullshit 😉 This is just a description how I got it work.

To use JIT we have to fill a JSON object that defines the whole structure of the graph. The Graph is defined by an Array of Nodes. These Nodes itself are containing a link-between-nodes structure called adjacencies.

[{
    "id": "3",
    "name": "\"Trinity\"",
    "adjacencies": [{
        "nodeTo": "1",
        "nodeFrom": "3",
        "data": {
            "nodeAttr": "LOVES"
        }
    },
    . . .]
},
. . .]

The above example defines a Node with Id “3” and the name “Trinity”. The association is Node “3” to Node “1” (which is Neo of course) and the relation attribute “LOVES”.

The thing is now, that we have to do a sequence of REST calls to get the whole graph. We will use a traversal path call to get all the relations between Nodes (starting from f.e. Node “3”) and all the Node Ids that are edges. JavaScript does not provide Worker threads (until now, but the major Browser provider are planning to implement them). Instead of threads JS uses CallBacks – excessively. But all these CallBacks have to be synchronized, which is a somehow tricky thing.

Loading all Nodes and wait for it

        void loadAllNodes(HashSet listOfNodes) {
            Set listOfNodesClone = (Set) listOfNodes.clone();
            for (String fetchId : listOfNodesClone)
                loadNode(fetchId, listOfNodes);
        }

loadAllNodes will get all Nodes Ids to load in a Set of Strings (Set to eliminate doubles and is filled by the get traversal path method). The method clones the Set and iterates through the Nodes.

        void loadNode(final String fetchId, final Set listOfNodes) {
           
            String url = "neo4j-rest/node/" + fetchId;

            RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
            builder.setHeader("Accept", "application/json");
            try {
                builder.sendRequest(null, new RequestCallback() {
                    public void onError(Request request, Throwable exception) {
                    }

                    public void onResponseReceived(Request request, Response response) {
                        if (200 == response.getStatusCode()) {
                            JSONObject json = new JSONObject(buildJavaScriptObject(response.getText()));
                            
                            // fill the graph data object
                            String nodeName = json.get("data").isObject().get("name").toString();
                            getNode(fetchId, nodeName, "#C74243", "star", 30);
                            listOfNodes.remove(fetchId);
                        }
                    }
                });
            } catch (RequestException e) {}
        }

loadNode is called by loadAllNodes for every Node in the Set. The method loadNode returns immediately but starts a REST call for every Node. The corresponding CallBack handler onResponseReceived are removing the loaded Node Id (fetchId). If this Set is empty, all Nodes are loaded.

        void waitForLoadingNodesAndLoadRelations(final Set listOfNodes, final List listOfRelations) {
            Timer t = new Timer() {
                @Override
                public void run() {
                    if (!listOfNodes.isEmpty()) {
                        waitForLoadingNodesAndLoadRelations(listOfNodes, listOfRelations);
                        return;
                    }
                    loadAllRelations(listOfRelations);
                }
            };
            t.schedule(500);
        } 

Method waitForLoadingNodesAndLoadRelations uses a Timer object to wait for the loading of the Nodes. It calls itself recursively till the listOfNodes Set is empty (that means all Nodes are loaded) and calls the method loadAllRelations to load the relations between the Nodes.

Part 2 will cover this.