Creating an Extension

stephen mallette edited this page Dec 22, 2013 · 22 revisions

This section will demonstrate how to create an Extension for Rexster. Lets start by creating a PingExtension and then modify it over the course of the documentation. The code for the PingExtension can be found in the Extension samples within Rexster Kibbles.

Dependencies

To build an extension, the following dependencies are necessary:

<dependency>
  <groupId>com.tinkerpop.rexster</groupId>
  <artifactId>rexster-core</artifactId>
  <version>??</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>com.sun.jersey</groupId>
  <artifactId>jersey-server</artifactId>
  <version>1.11</version>
  <scope>provided</scope>
</dependency>

Note that both of these dependencies can be scoped as provided, as Rexster will have these dependencies available when th extension is deployed. In addition to these dependencies, it would be difficult to build a meaningful extension without at least also including:

<dependency>
  <groupId>com.tinkerpop.blueprints</groupId>
  <artifactId>blueprints-core</artifactId>
  <version>??</version>
  <scope>provided</scope>
</dependency>

A Simple Ping Extension

@ExtensionNaming(namespace = "ex", name = "ping")
public class PingExtension extends AbstractRexsterExtension {

    @ExtensionDefinition(extensionPoint = ExtensionPoint.GRAPH)
    @ExtensionDescriptor(description = "Ping me.")
    public ExtensionResponse evaluatePing(@RexsterContext RexsterResourceContext context,
                                          @RexsterContext Graph graph) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("ping", "pong");
        return ExtensionResponse.ok(map);
    }
}

The extension is named using @ExtensionNaming annotation where a namespace and name is provided. The extension must implement the RexsterExtension interface (or simply extend from AbstractRexsterExtension which implements it itself). A method is provided called evaluatePing. This method is attached to the ExtensionPoint.GRAPH. Thus, when

http://localhost:8182/graphs/mygraph/ex/ping

is resolved, a JSON object is returned that has the key/value ping/pong.

{
  "ping": "pong"
  "version": "*.*"
  "queryTime": 3.765
}

Of course, you can (and probably will) interact with the graph and perform some calculation. In these simple examples, no graph manipulations are discussed.

Automatic Parameter Parsing and Self-Documenting Extensions

@ExtensionNaming(namespace = "ex", name = "ping")
public class PingExtension extends AbstractRexsterExtension {

    @ExtensionDefinition(extensionPoint = ExtensionPoint.GRAPH)
    @ExtensionDescriptor(description = "A simple ping extension.")
    public ExtensionResponse evaluatePing(@RexsterContext RexsterResourceContext context,
                                          @RexsterContext Graph graph,
                                          @ExtensionRequestParameter(name="reply", description="a value to reply with") String reply) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("ping", reply);
        return ExtensionResponse.ok(map);
    }
}

There are two new add-ons to the PingExtension.

  1. @ExtensionDescriptor: An annotation to provide documentation to the user when the extension fails.
  2. @ExtensionRequestParameter: An annotation to parse the JSON request object and provide value as a parameter.

Note what is returned when http://localhost:8182/graphs/mygraph/ex/ping is resolved:

{
  "message": null
  "api": {
    "description": "A simple ping extension."
    "parameters": {
      "reply": "a value to reply with"
    }
  }
  "success": false
}

By annotating the method and its parameters, an API is created. Next, resolve http://localhost:8182/graphs/mygraph/ex/ping?reply=ping-a-ling and what is returned is:

{
  "ping": "ping-a-ling"
  "version": "*.*"
  "queryTime": 4.281
}

Getting the Request Object and Returning a Result Object

In Rexster, JSON comes in and JSON goes out (see Mapping a URI to JSON). Its possible to get the values of the JSON request object using @ExtensionRequestParameter annotations. You can also get the JSON object directly with:

JSONObject requestObject = context.getRequestObject()

Next, building up the result in a JSONObject is as easy as using Java Map. When the result object has been constructed, return it with a ExtensionResponse method (e.g. ok, error). That is all there is to it.