34.2. Unmanaged Extensions

Some projects want extremely fine control over their server-side code. For this we’ve introduced an unmanaged extension API.

[Warning]Warning

This is a sharp tool, allowing users to deploy arbitrary JAX-RS classes to the server and so you should be careful when thinking about using this. In particular you should understand that it’s easy to consume lots of heap space on the server and hinder performance if you’re not careful.

Still, if you understand the disclaimer, then you load your JAX-RS classes into the Neo4j server simply by adding a @Context annotation to your code, compiling against the JAX-RS jar and any Neo4j jars you’re making use of. Then add your classes to the runtime classpath (just drop it in the lib directory of the Neo4j server). In return you get access to the hosted environment of the Neo4j server like logging through the org.neo4j.server.logging.Logger.

In your code, you get access to the underlying GraphDatabaseService through the @Context annotation like so:

public MyCoolService( @Context GraphDatabaseService database )
{
  // Have fun here, but be safe!
}

Remember, the unmanaged API is a very sharp tool. It’s all to easy to compromise the server by deploying code this way, so think first and see if you could use one of the other APIs that come with Neo4j by default. However, a number of context parameters can be automatically provided for you, like the reference to the database.

In order to specify the mount point of your extension, a full class looks like this:

Unmanaged extension example. 

@Path( "/helloworld" )
public class HelloWorldResource
{
    private final GraphDatabaseService database;
    private final ExecutionEngine cypher;

    public HelloWorldResource( @Context GraphDatabaseService database, @Context ExecutionEngine cypher )
    {
        this.database = database;
        this.cypher = cypher;
    }

    @GET
    @Produces( MediaType.TEXT_PLAIN )
    @Path( "/{nodeId}" )
    public Response hello( @PathParam( "nodeId" ) long nodeId )
    {
        // Do stuff with the database
        return Response.status( Status.OK ).entity(
                ("Hello World, nodeId=" + nodeId).getBytes( Charset.forName("UTF-8") ) ).build();
    }
}

The full source code is found here: HelloWorldResource.java

Build this code, and place the resulting jar file (and any custom dependencies) into the $NEO4J_SERVER_HOME/plugins directory, and include this class in the conf/neo4j-server.properties file, like so:

[Tip]Tip

Make sure the directories listings are retained in the jarfile by either building with default Maven, or with jar -cvf myext.jar *, making sure to jar directories instead of specifying single files.

[Tip]Tip

You will need to include a dependency to JAX-RS API on your classpath when you compile. In Maven this would be achieved by adding the following to the pom file:

<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.0</version>
    <scope>provided</scope>
</dependency>
#Comma separated list of JAXRS packages containing JAXRS Resource, one package name for each mountpoint.
org.neo4j.server.thirdparty_jaxrs_classes=org.neo4j.examples.server.unmanaged=/examples/unmanaged

Which binds the hello method to respond to GET requests at the URI: http://{neo4j_server}:{neo4j_port}/examples/unmanaged/helloworld/{nodeId}

curl http://localhost:7474/examples/unmanaged/helloworld/123

which results in

Hello World, nodeId=123