Wednesday, January 2, 2013

Fun Week 2012 - Carte conversion to REST (Part 1)


During Pentaho Fun Week 2012 I converted Carte to using REST.
Carte fires up a Jetty server in WebServer.java.  This is the class we modify to mount all REST
endpoints under "/api".  To do this I used Jersey's PackagesResourceConfig with a Jersey ServletHolder.
The details of this code are as follows:

// setup jersey (REST)
ServletHolder jerseyServletHolder = new ServletHolder(ServletContainer.class);
jerseyServletHolder.setInitParameter("com.sun.jersey.config.property.resourceConfigClass", "com.sun.jersey.api.core.PackagesResourceConfig");
jerseyServletHolder.setInitParameter("com.sun.jersey.config.property.packages", "org.pentaho.di.www.jaxrs");
// mount all jersey REST under /api
root.addServlet(jerseyServletHolder, "/api/*");

The package "org.pentaho.di.www.jaxrs" is where all classes are scanned for JAX-RS annotations for example CarteResource.java.  This is a
general REST endpoint mounted to "/api/carte" and provides methods for getting system info, config details and a list of jobs or
transformations.  This file is really quite simple to understand and it replaces (or makes obsolete) several Carte servlets.  For example,
to get a list of transformations that are in Carte, you would invoke the url "http://carteserver:port/api/carte/transformations" with a
GET request (which means you can do this easily in a browser to preview the response).  The output is in JSON making it very easy for
JavaScript consumers to rehydrate.  XML can also be provided if so desired by putting this in the request header.  The code for Carte
REST to return a list of transformations is:

@GET
@Path("/transformations")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<CarteObjectEntry> getTransformations() {
List<CarteObjectEntry> transEntries = CarteSingleton.getInstance().getTransformationMap().getTransformationObjects();
return transEntries;
}

The @GET annotation specifies the HTTP method we use and the @Path annototation is the "add-on" to the service mount (The class itself
is mounted as "/carte"), so the combined path is "/carte/transformations" - the full path, since all resources in the "org.pentaho.di.www.jaxrs"
package or mounted in Jetty under "api" would be "/api/carte/transformations".  The @Produces annotation is a list of output types/formats
that can be provided by this service.  Jersey will handle the serialization from our List<CarteObjectEntry> to JSON/XML.

To keep things really simple, yet as complete as reasonable during a fun week timeframe, I created two additional REST endpoints which handle
job and transformation specifics.  JobResource.java and TransformationResource.java are the classes which provide the ability to add, remove,
pause, start, stop, get logs, and get status for jobs/transformations.  For example, to get the status of a job, you would invoke the url
"http://carteserver:port/api/carte/job/status/id" where id is the GUID for the Carte object (which can be obtained by listing from the
CarteResource.

There's still work to be done, I have not converted all of the CarteServlets to REST, for example, I don't have anything in the way of
slave server support or anything to list data services or server sockets.  This is not because it was difficult, in fact, it's probably
quite easy to do, I just didn't need it for the purposes of my funweek project.  Another thing that would be nice is to add the ability for
plugins to add REST services just as they can add Jetty servlets today.  I don't think this will be difficult either, I just did not have
time as I wanted to take what I had already written and write a mobile friendly UI for Carte.

1 comment:

  1. Hello Michael,
    I was hoping you would be so kind to help me out with an issue that I am facing currently. My question is documented here:
    http://stackoverflow.com/q/22877770/2671089

    Thanks a lot in advance.

    ReplyDelete