How to get GraphDatabaseService instance from Bolt Driver - neo4j

I wrote some codes that used java Api of GraphDatabaseService to access an embedded database before. But now I want to switch the database to a remote one, so I have to use Driver and Session class to write and run cyphers. I don't like cyphers and I don't want to change the old codes.
So I'm looking for a way so that I can get GraphDatabaseService from Driver, but none is found.
I think a possible way is to make up a GraphDataBaseService delegate that wraps a Driver and converts Api calls to cyphers. Is that feasible? Is there already some libraries which can do this?

You won't get a direct equivalent of GraphDatabaseService since that's the embedded API.
You can however run Cypher queries like this:
var driver = GraphDatabase.driver(
"some://address",
AuthTokens.basic("username", "password")
);
// [...]
try (var session = driver.session() {
return session.writeTransaction(tx -> {
Result result = tx.run(
"CYPHER QUERY",
Map.of(/* query parameters */)
);
// do something with result
});
}
// [...]
driver.close(); // (driver is usually a singleton - closes when application shuts down)

I tried to make a project to solve this problem by wrapping Driver to GraphDatabaseService.

Related

How to deal with json data read from a database with RPC package

I try to implement an API using the RPC dart package.
In all the example I found, response are build manually (ie new Response()..message = "hello").
In my case, i read JSON data from mongodb and want to return them with minimal transformation (basically picking only external properties).
The fromRequest of the method schema can be used to do this :
class QueryResult {
//my props
}
#ApiMethod(path: "myMongoQuery")
Future<List<QueryResult>> myMongoQuery() async {
var schema = _server.apiMap["/query/v1"].schemaMap["QueryResult"];
var results = await coll.find();
return results.map(schema.fromRequest).toList();
}
The problem in my code is the first line (_server.apiMap["/query/v1"].schemaMap["QueryResult"]) it's a pure hack to retrieve the schema of my method.
I tried to use mirror to retrieve the schema in an elegant/generic way but did not succeed.
Anyone can help me on this ?
Cheers,
Nicolas

Can I write a Neo4j Plugin to intercept and modify CYPHER queries

In my system, I would like to intercept and change Cypher queries as they come in, one alternative is to modify them before sending them from my middle layer to the graph - but is there a way to have a plugin do the conversion for me in the graph itself?
I'd like to do some of the following:
If someone identifying themselves as members of group A, imagine I'd like to change their request from:
MATCH(f:Film)-[r:REVIEWED_BY]-(u:User {id:"1337"})
to:
MATCH(p:Product)-[p:PURCHASED_BY]-(u:User {id:"1337"})
Is something like this possible? Or do I have to write the traversals in Java directly to achieve this?
Of course you can. You can do ANYTHING in Neo4j. Just grab the cypher string in an unmanaged extension that receives a post request, alter it any way you want, execute it with the graphdb.execute method and return the result as normal.
#POST
#Path("/batch")
public Response alterCypher(String body, #Context GraphDatabaseService db) throws IOException, InterruptedException {
ArrayList<Result> results = new ArrayList<>();
// Validate our input or exit right away
HashMap input = Validators.getValidCypherStatements(body);
ArrayList<HashMap> statements = (ArrayList<HashMap>)input.get("statements");
for (HashMap statement : statements) {
// write the alterQuery method to change the queries.
String alteredQuery = alterQuery((String)statement.get("statement"));
Result result = db.execute(alteredQuery, (Map)statement.getOrDefault("parameters", new HashMap<>()));
results.add(result);
}
// or go the results and return them however you want
// see https://github.com/dmontag/neo4j-unmanaged-extension-template/blob/master/src/main/java/org/neo4j/example/unmanagedextension/MyService.java#L36
return Response.ok().build();
}
At this time it's not possible to extend or modify Cypher queries.
If you need that I recommend you to use Transaction Event API - http://graphaware.com/neo4j/transactions/2014/07/11/neo4j-transaction-event-api.html
With that you should be able to change what query returns.

Dropwizard Stored Procedure Example

I am new to dropwizard. I am going through different tutorial but I couldnt find good example/tutorial on how to call stored procedure in dropwizard using JDBI.
With JDBI it is possible to specify an object SQL query as a method annotation. This string is treated by the DB as normal SQL. An example DAO to execute a stored procedure might look like:
public interface SomeQueries
{
#SqlQuery("call find_name_procedure(:id)")
String findName(#Bind("id") int id);
}
Where find_name_procedure has been previously defined.
For more information see http://jdbi.org/sql_object_api_queries/
Jooq is an elegant way to call stored procedures from java (See https://dzone.com/articles/using-stored-procedures-with-jpa-jdbc-meh-just-use). You also have a thirdparty module integrating Jooq into Dropwizard
(See http://modules.dropwizard.io/thirdparty/)
So if you're familiar with Maven, you can set up the combination quickly and start validating if it works in your case.
DropWizard JDBI provides two options to make a stored procedure call. Depending on what you want from Stored proc.
If you want resultset from Stored Proc, Andy has answered that already:
public interface DAO
{
#SqlQuery("call sp_name(:id)")
String query(#Bind("id") int id);
}
The other scenario is that your stored proc doesn't return resultset but gives out some output parameters. Here is what you can do:
#SqlCall("{ CALL sp_name(:id, :id2) }")
#OutParameter(name = "out", sqlType = Types.INTEGER)
OutParameters spCal(#Bind("id") long id, #Bind("id2") long id2);
OutParameter annotation may not work in DropWizard as the annotation was introduced in v3, you can use the following for accessing OutParameters:
try (Handle handle = dbi.open()) {
parameters = handle.createCall("CALL sp_name(:IN_Field1,:OUT_field2)")
.bind("IN_Field1", filed1)
.registerOutParameter("OUT_field2", Types.INTEGER)
.invoke();
}
And for some real freaky situations where you will need both Outparameters and resultset - DropWizard currently doesn't provide any direct way (Because the JDBI version with dropwizard is old). So, you can get connection by doing below:
handle = jdbi.open()
handle.getConnection()
And then do what you want to do with the connection.
Also, one more thing - I will not try to use Hibernate for Stored Proc call. Its just more pain.
I used Zalando Sprocwrapper. I like it and was widely used in the Zalando company to call PostgreSQL functions.
https://github.com/zalando-incubator/java-sproc-wrapper

Not able to access iterator() from RestTraverser, it gives exception java.lang.IllegalAccessError

I am implementing traversal framework using neo4j java-rest-binding project.
Code is as follows:
RestAPI db = new RestAPIFacade("http://localhost:7474/db/data");
RestNode n21 = db.getNodeById(21);
Map<String,Object> traversalDesc = new HashMap<String, Object>();
traversalDesc.put("order", "breadth_first");
traversalDesc.put("uniqueness", "node_global");
traversalDesc.put("uniqueness", "relationship_global");
traversalDesc.put("returnType", "fullpath");
traversalDesc.put("max_depth", 2);
RestTraverser traverser = db.traverse(n21, traversalDesc);
Iterable<Node> nodes = traverser.nodes();
System.out.println("All Nodes:"); // First Task
for(Node n:nodes){
System.out.println(n.getId());
}
Iterable<Relationship> rels = traverser.relationships();
System.out.println("All Relations:"); // Second Task
for(Relationship r:rels){
System.out.println(r.getId());
}
Iterator<Path> paths = traverser.iterator(); // Third Task
while(paths.hasNext()){
System.out.println(paths.next());
}
I need to do 3 tasks as commented in the code:
Print all the node IDs related to node no. 21
Print all the relation IDs related to node no. 21
Traverse all the paths related to node no. 21
Tasks 1 & 2 are working fine.
But when I try to do traverser.iterator() in 3rd task it throws an Exception saying:
java.lang.IllegalAccessError: tried to access class org.neo4j.helpers.collection.WrappingResourceIterator from class org.neo4j.rest.graphdb.traversal.RestTraverser
Can anyone please check why this is happening or if I am doing wrong then what is the right method to do it.
Thanks in Advance.
I don't believe using the Neo4j Traversal Framework via the REST DB binding is properly supported, nor is it advisable. If you traverse via REST, each node and each relationship will be retrieved over the network as the traversal proceeds, incurring a tremendous overhead for the traversal.
Edit: The above is not true, the REST traverser is smarter than I thought.
In general, it will be faster to use Cypher, and access the Neo4j Server using JDBC. Read more about JDBC here: https://github.com/neo4j-contrib/neo4j-jdbc
If you really want to use the Traversal Framework, you should use Server Extensions, which allow you to design a traversal to run on the server itself, and then only move the result of the traversal over the network. Read more about server extensions here: http://docs.neo4j.org/chunked/stable/server-unmanaged-extensions.html

Calling JBoss MBean functions to get threaddump

An application is using JBoss 4.2.2, and I have found it necessary to call listThreadDump(), and I expect it is in ServerInfo.
I am thinking the jar I need to find this information is jboss-jmx.jar.
So, how do I programmatically duplicate what is done by calling something similar to http://localhost:8080/jmx-console/HtmlAdaptor?action=invokeOpByName&name=jboss.system:type=ServerInfo&methodName=listThreadDump?
This is how I have accessed the ServerInfo MBean. I'm using JBoss AS 5.1, but this method should be the same.
To call listThreadDump(), you can invoke() the method on the ServerInfo MBean using an MBeanServer instance.
Additionally, you can access attributes of MBeans using the same MBeanServer.
Sample code:
// imports
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.jboss.mx.util.MBeanServerLocator;
try {
MBeanServer server = MBeanServerLocator.locate();
ObjectName name = new ObjectName("jboss.system:type=ServerInfo");
// invoke the listThreadDump method and capture its output
String threadDumpHtml = (String) server.invoke(name, "listThreadDump", null, null);
// access a simple attribute of the ServerInfo object
String jvmName = (String) server.getAttribute(name, "JavaVMName");
} catch (Exception e) {
// Ideally catch the 3 exact exceptions
}
Finally, I find it handy when MBeans expose an 'instance' attribute, so you can then access the object directly (CastToType) server.getAttribute(name, "instance") instead of always going through the MBeanServer. For example, when using JMS, the ServerPeer instance is nice to have as you can get message counters on your queues and topic subscribers.

Resources