Earthly Powers

Friday Jun 27, 2008

Services are clients too

RESTful services can also be clients that make RESTful requests to other services. Jersey has a client API and resource classes can use that to efficiently make such requests.

Following on from my last blog entry on injection i can combine injection with a client API to make things a little easier. So i can have a resource class that does the following:

    @Path("/")
    public static class Resource {        
        @GET
        public String get(
                @WebResourceRef("http://localhost:9999/one") AsyncWebResource r1,
                @WebResourceRef("http://localhost:9999/two") AsyncWebResource r2) 
                throws InterruptedException, ExecutionException { 
            Future<String> c1 = r1.path("foo").get(String.class);
            Future<String> c2 = r2.path("bar").get(String.class);
            return c1.get() + c2.get();
        }       
        @GET
        @Path("one/{stuff}")
        public String getOne(@PathParam("stuff") String stuff) { 
            return stuff;
        }       
        @GET
        @Path("two/{stuff}")
        public String getTwo(@PathParam("stuff") String stuff) { 
            return stuff;
        }
    }

The get method has two parameters that are annotated with @WebResourceRef that declares client-based URIs. I wrote an InjectableProvider for that annotation that creates instances of AsyncWebResource or WebResource (see end of this entry for complete source that should work with Jersey 0.8) based on the URI. When that method is invoked it makes two asynchronous requests, to sub-resource methods of the same resource class, and returns the result.

I think this is interesting enough to include support for this in Jersey.

import com.sun.grizzly.http.SelectorThread;
import com.sun.jersey.api.client.AsyncWebResource;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.container.grizzly.GrizzlyServerFactory;
import com.sun.jersey.api.core.HttpContext;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import com.sun.jersey.spi.service.ComponentContext;
import com.sun.jersey.spi.service.ComponentProvider.Scope;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Type;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.ext.Provider;

public class Main {
    @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public static @interface WebResourceRef {
        String value();
    }

    @Provider
    public static class WebResourceProvider implements InjectableProvider<WebResourceRef, Type> {
        private final Client client;        
        public WebResourceProvider() {
            this.client = Client.create();
        }
        public Scope getScope() { 
            return Scope.PerRequest;
        }

        public Injectable getInjectable(ComponentContext cc, final WebResourceRef wrr, Type t) {
            if (!(t instanceof Class)) return null;
            Class c = (Class)t;            
            if (WebResource.class == t) {
                return new Injectable<WebResource>() {
                    public WebResource getValue(HttpContext c) {
                        return client.resource(wrr.value());
                    }                    
                };                            
            } else if (AsyncWebResource.class == t) {
                return new Injectable<AsyncWebResource>() {
                    public AsyncWebResource getValue(HttpContext c) {
                        return client.asyncResource(wrr.value());
                    }
                };                                            
            } else {
                return null;
            }            
        }
    }
    @Path("/")
    public static class Resource {        
        @GET
        public String get(
                @WebResourceRef("http://localhost:9999/one") AsyncWebResource r1,
                @WebResourceRef("http://localhost:9999/two") AsyncWebResource r2) 
                throws InterruptedException, ExecutionException { 
            Future<String> c1 = r1.path("foo").get(String.class);
            Future<String> c2 = r2.path("bar").get(String.class);
            
            return c1.get() + c2.get();
        }
        @GET
        @Path("one/{stuff}")
        public String getOne(@PathParam("stuff") String stuff) { 
            return stuff;
        }        
        @GET
        @Path("two/{stuff}")
        public String getTwo(@PathParam("stuff") String stuff) { 
            return stuff;
        }
    }    
    public static void main(String[] args) throws Exception {        
        SelectorThread st = GrizzlyServerFactory.create("http://localhost:9999/");        
        try {
            Client c = Client.create();
            WebResource r = c.resource("http://localhost:9999/");
            String s = r.get(String.class);
            System.out.println(s);
        } catch (UniformInterfaceException e) {
            System.out.println(e.getResponse().getStatus());
            e.printStackTrace();
        } finally {
            st.stopEndpoint();
            System.exit(0);        
        }
    }
}

Thursday Jun 26, 2008

@EJB injection

Jersey has a simple injection provider SPI for injecting instances for annotated fields, method/constructor parameters or setter methods. So it is possible to plug-in your own injection functionality.

Out of the box there is currently no EE-based functionality supported in Jersey but using the injection provider SPI it is very easy to have basic support for @EJB in one small class.

If you have the following resource:

@Path("foo")
public class FooResource {
    @EJB private FooSessionRemote fooSessionRemoteBean;
    
    @GET
    @ProduceMime("text/plain")
    public String get() throws Exception {
        return fooSessionRemoteBean.fooMethod();
    }
}

then the field fooSessionRemoteBean should get injected with an instance of the remote EJB interface.

The following provider class supports this behaviour:

@Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {

    public Scope getScope() {
        return Scope.Singleton;
    }

    public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
        if (!(t instanceof Class)) return null;
        
        try {
            Class c = (Class)t;        
            Context ic = new InitialContext();

            final Object o = ic.lookup(c.getName());
            
            return new Injectable<Object>() {
                public Object getValue(HttpContext c) {
                    return o;
                }                    
            };            
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

The EJB reference is looked up using JNDI then an Injectable instance is returned with that reference. This is efficient for per-request resources as the JNDI look up is only performed once. Since the above class is annotated with @Provider it will get picked up and treated like any other provider.

Obviously this could do with some polish to fully implement @EJB injection functionality but i think this example is instructive how one could support other annotations.

Friday Jun 20, 2008

Jersey 0.8 is released

We have just released version 0.8 of Jersey (see the stable download directory). This aligns with the 0.8 release of the JAX-RS API and the public review draft.

We made excellent progress in this time trial and we are releasing at least a week earlier than expected. This is good as it lets me show off 0.8 at Jazoon next week and lets us concentrate on the 0.9 etape over the summer period.

This version will be available soon from the Glassfish v2 and v3 update centers, and will be making it's way into NetBeans 6.5.

Thanks to the work of Jakub, Martin, Doug and others we are now pushing snapshot releases to here in the java.net maven 2 repository. This occurs automatically thanks to Hudson. Jakub shows how easy it is to use embedded Glassfish with Jersey from the maven 2 repository. The stable version has also been pushed, but as of writing there is an issue with the java.net maven repository infrastructure causing things to be delayed. When it appears we will send out another blog.

Martin has contributed Spring-based servlet support that is here in java.net maven 2 repository. This is great, now developers don't have to copy old code from mine and Marc's blog entries. Anybody willing to contribute support for Guice?

I refactored the container SPIs. Now it is much cleaner and easier, but more importantly it provides the basis for better Comet support and filtering that i hope to progress in 0.9. I also managed to unify the injection framework, make it more pluggable, and much more efficient for per-request resources.

It is a significant effort to transform a project from ant to maven and we are currently in an "interesting" transitional phase we hope to complete for the 0.9 release. As part of this we plan to split Jersey up into components as well as providing bundles, just like Grizzly does. So, hopefully, a developer can reduce the overall size of the jars required. For example, if a developer wants to use just the client API  they are currently required to use the jar with all the unused server-side functionality. I believe this may also be advantageous for those wanting a smaller footprint for embedded servers.

After the successful Spring integration Martin is now working on a very interesting development combining JavaDoc doclets and WADL. The upshot of this work is that JavaDoc comments in resource classes will be pulled into the generated WADL document meaning that a developer does not have to separate documentation from the code of their RESTful Web services. See here for more details. I want to get this functionality merged into snapshot builds as soon as possible!

Friday Jun 06, 2008

JavaOneDemo in Scala

For some light entertainment I converted the JavaOneDemo over to a Scala-based version, see here. It is by no means complete, there is still some Java code (which shows how one can mix the two in the same project) and i know it can be improved by using Scala's native XML support.

I am getting increasingly grumpy with the verbosity of Java and the reduction that Scala offers is good (i wish i could write Jersey completely in Scala, i would be more productive and i think the code would be better, but the downside is it would limit adoption for those wishing to mess around with the code base).

Here is a bit of the Java code:

@ProduceMime("application/xhtml+xml")
public class SystemProperty {
    Properties properties;
    String name;    
    String value;
    SystemProperty(Properties properties, String name) {
        this.properties = properties;
        this.name = name;
        this.value = properties.getProperty(name);
        if (value == null)
            throw new WebApplicationException(Response.Status.NOT_FOUND);
    } 
    @GET
    public Property getProperty() {
        return new Property(name, value);
    }    
    @PUT
    @ConsumeMime("text/plain")
    public void updateProperty(String newValue) {
        properties.setProperty(name, newValue);
    }    
    @DELETE
    public void deleteProperty() {
        properties.remove(name);
    }
}

Now compare that with the equivalent Scala code:

@ProduceMime(Array("application/xhtml+xml"))
class SystemProperty(properties : Properties, name : String) {
    val value = properties.getProperty(name)
    if (value == null)
        throw new WebApplicationException(Response.Status.NOT_FOUND)
    @GET
    def getProperty = new Property(name, value)
    @PUT
    @ConsumeMime(Array("text/plain"))
    def updateProperty(newValue : String) : unit = 
        properties.setProperty(name, newValue)    
    @DELETE
    def deleteProperty() : unit = properties.remove(name)
}

This class uses Scala concise constructors and the Scala compiler is smart enough to know whether the constructor parameters need to be fields on the class. Unfortunately Scala does not perform auto-boxing of arrays, which is why you see Array("application/xhtml+xml") in the @ProduceMime annotation (this gets more annoying when using the JAX-RS builder-related methods). Notice how you can write the equivalent constructor logic directly in the class.

For first @GET method Scala does not require that you declare the return type, it works it out. So this can be written concisely in one line.

I would like to write some "Scala-sugar" for classes like UriInfo and Response to improve EOU in Scala in addition to further investigating use of Scala features like closures as experimented with previously.

Tuesday May 27, 2008

@FormParam

I have been unifying the injection mechanism in Jersey, making it more modular and improving the performance of injection (now it is possible to plug-in your own injectable behavior for injecting on to fields, constructors and resource methods, including overriding or augmenting existing behavior... more later in another entry perhaps...).

As a serendipitous consequence of those changes it was so easy to implement the support for form parameters i could not resist (in fact the implementation is pluggable so i could have provided the functionality as a separate jar if so desired). In less than 2 hours it was in the main trunk :-)

So by popular request (many have requested this on the users list) I introduce @FormParam.

You can write a resource as follows:

@Path("/")
public class Resource {
  @POST
  @ConsumeMime(MediaType.APPLICATION_FORM_URLENCODED)
  public String post(
     @FormParam("a") String a,
     @FormParam("b") String b) {
   return a + b;
  }

and test it with the client API: 

WebResource r = Client.create().resource("/")'

Form form = new Form();
form.add("a", "foo");
form.add("b", "bar");

String s = r.post(String.class, form);

Form parameters will only work with resource methods where each parameter is annotated and at least one parameter is annotated with @FormParam. The same rules apply as for the other parameters, such as @QueryParam (with the exception that the encoded form is not currently supported). 

Monday May 26, 2008

JavaOne slides and demo

Here are the JavaOne slides Marc and I presented.

Here is the zip of the completed demo written in Java as a NetBeans project.

MVCJ

Or Model, View, Controller and Jersey

Perhaps a little know fact (i should have blogged about it sooner) is that Jersey has support for the MVC paradigm and pluggable template processing.

A Controller is a resource class, a model is returned by a resource method, and a view is a template (which is processed by an associated template processor) that operates on the model.

The MVC approach taken by Jersey was inspired by the mechanism in Hudson and it's underlying framework, Stapler.

Jersey supports two types of MVC: explicit; and implicit.

Explcit MVC

A resource method can explicitly return a reference to a template and a model. For example, given the following resource class:

package com.foo;

@Path("foo")
public class Foo {
  @GET
  public Viewable get() {
   return new Viewable("index", "FOO");
  }
}

Foo is the controller, and when the method get is invoked, it returns the model "FOO" and a reference to the view (the template) "index", both of which are encapsulated in the Viewable instance.

The template reference "index" is a relative so Jersey will resolve it to an absolute template reference, using the fully qualified class name of Foo, to the following:

"/com/foo/Foo/index"

Then Jersey will search the registered template processors (more detail on this later) to find a template processor that can resolve it further to a processable template reference. If a template processor is found then the processable template is processed using the model.

If instead the get method is as follows:

  @GET
  public Viewable get() {
   return new Viewable("/index", "FOO")
  }

Jersey will not resolve the template reference as it is considered resolved, since it begins with "/". The reference will however be resolved to a processable template reference as previously described.

All HTTP methods may return Viewable instances. Thus a POST method may return a template reference to a template that produces a view that is the result of processing a form.

Implicit MVC

A resource class can have templates implicitly associated (this is the style used by Hudson). For example, given the following resource class:

@Path("foo") 
public class Foo {
  public String getFoo() {
   return "FOO";
  }
}

if there exists a template reference "index" that resolves to an absolute template reference "/com/foo/Foo/index" that in turn resolves to a processable template reference then a @GET method will be implicitly added to the Foo controller that performs the equivalent of the following explicit resource method:

  @GET
  public Viewable get() {
   return new Viewable("index", this)
  }

Notice that the model is the controller. In this case the template reference "index" is special, it is the template reference associated with the controller itself.

Implicit sub-resources are also allowed, for example, if there is a template reference "bar"  that resolves to an absolute template reference "/com/foo/Foo/bar" that in turn resolves to a processable template reference then a @GET method will be implicitly added to the Foo controller that performs the equivalent of the following explicit sub-resource method:

  @Path("bar") @GET
  public Viewable get() {
   return new Viewable("bar", this);
  }

This all works dynamically (as is the case for explicit MVC) so it is possible (if the deployment system is configured correctly) to add or modify templates while the application is running.

To enable implicit MVC it is necessary to set the following configuration feature to true:

"com.sun.jersey.config.feature.ImplicitViewables"

Furthermore this only works for HTTP GET requests and only if there are no equivalent explicit @GET resource methods (namely explicit resource methods take precedence over implicit resource methods).

The Bookstore example in the Jersey distribution contains a working example using implicit MVC with JSP pages.

JSP support

Jersey provides MVC support for JSP pages. There is a JSP template processor that resolves absolute template references to processable template references that are JSP pages as follows:

  • if the absolute template reference does not end in ".jsp" append it to the reference; and
  • if Servlet.getResource returns a non-null value for the appended reference then return the appended reference as the processable template reference otherwise return null. 

Thus the absolute template reference "/com/foo/Foo/index" would be resolved to "/com/foo/Foo/index.jsp" if there exists the JSP page "/com/foo/Foo/index.jsp" in web the application.

Jersey will assign the model instance to the attribute named "it". So in the case of the implicit example it is possible to access the foo property on the Foo controller as follows:

<h1>${it.foo}</h1> 

Pluggable template processors 

Template processors are providers so it is possible to implement a processor as follows:

@Provider 
public MyTemplateProcessor implements TemplateProcessor {
  String resolve(String path) { ... }

  void writeTo(String resolvedPath, Object model, OutputStream out)
    throws IOException { ... }
}

If using the class or package scanning techniques then such a provider will get automatically registered. In addition such a component can be managed by a registered IoC framework and injection of standard JAX-RS and Jersey components is possible.

If i recall correctly (from the Jersey users list) a developer successfully plugged in Freemarker support in a couple lines in addition to supporting JAXB to XSLT translations. One interesting aspect of using template engines such as Freemarker or Velocity is it is possible to write a set of resource classes that provide their own templates, thus potentially allowing easy way to plug-in extensions to a web application (ala the Hudson style).

When writing template processors it is recommend that you use an appropriate unique suffix for the processable template references. Then it is possible to easily intermix multiple template processors without any conflict.

The implementation of the JSP template processor is presented at the end of this blog entry.


public class JSPTemplateProcessor implements TemplateProcessor {
    @Context ServletContext servletContext;

    public JSPTemplateProcessor() {
        Class<?> c = ServletContext.class;
    }
   
    public String resolve(String path) {
        if (servletContext == null)
            return null;
       
        if (!path.endsWith(".jsp"))
            path = path + ".jsp";

        try {
            if (servletContext.getResource(path) == null) {
                // TODO log
                return null;
            }
        } catch (MalformedURLException ex) {
            // TODO log
            return null;
        }
       
        return path;       
    }

    @Context HttpContext hca;
   
    public void writeTo(String resolvedPath, Object model, OutputStream out) throws IOException {
        HttpResponseContext response = hca.getResponse();
        ((HttpResponseAdaptor)response).forwardTo(resolvedPath, model);
    }
}

Friday Apr 18, 2008

Jersey 0.7 is released

Jersey

We have just released version 0.7 of Jersey (see the stable download directory). This aligns with the 0.7 release of the JAX-RS API and the March editors draft.

This version will be available soon from the Glassfish Update Centre.

Phew! this was a tough one. There were many additions and clarifications to the API. The email statistics for the 311 EG list looks like a climb profile (maybe up Alpe D'Huez like Lance if you squint your eyes).

So most of our time was spent on API aspects.

However, Jakub got some good feedback on the JSON support and fixed related bugs.

Martin Grotzke has been working on improving Spring, and in general IoC integration, support in a branch. The plan is to make this part of the 0.8 distribution, and hopefully we will manage to solve some difficult issues w.r.t. mixing IoC-based and Jersey-based components when injecting parameters of constructor/methods that Jersey is responsible for invoking.

I finally managed to play around with the latest JavaRebel and SDK and formalize the reloading of the Jersey runtime when resource classes are added, modified or removed. 

As a nice bonus Jean Francois kindly visited Grenoble for a day and we hashed out a Grizzly/Comet/Jersey prototype. I think we may have a very interesting and simple way of integrating Comet functionality with resource classes. Jean Francois has created a branch and we will work from that to progress such support. Unfortunately i did not have time to move to Grizzly 1.7.3 but i am very excited about prospects for 1.8.0 and an asynchronous client-side API based on Grizzly as i can make good use of that with the Jersey client-side API. 

Now it is time to prepare for JavaOne. Marc and I have a technical session on JAX-RS @ Tuesday 12:10. Jakub and I have a BOF on Jersey @ Tuesday 20:30. I should be around for the GF unconference on the Sunday before, and will be partially around for the CommunityOne event on the Monday before (Marc and I have to prepare for the session so we cannot attend for the whole day).

I am thinking of two possible dates for the 0.8 release, 20th June or the 25th of July. The reason being is the Jazoon conference is at the end of June, we need to relax a bit (i go on holiday a week after Jazoon for 2 weeks), and there are more API changes to implement although not of Alpe D'Huez proportions.

Wednesday Apr 16, 2008

JavaRebel and Jersey: Take 2

Since i last played with JavaRebel it has been through one or more updates and now has an SDK. It is also been a while since i blogged, from the graph generated by Marc you should be able to determine why.

Finally i managed to get some time to revisit JavaRebel (many thanks to Jevgeni Kabanov for updating me on the progress of JavaRebel and sending pointers to relevant information). This entry explains how to dynamically reload the Jersey deployed web application in response to callbacks from JavaRebel when in detects changes to class files. Because Jersey caches runtime information about classes, for performance reasons, it needs to be informed to update information about classes that have changed. So adding a new HTTP method or a new resource class can be detected.

The code at the end of the blog shows a complete example that can work with the latest build of Jersey 0.7, JavaRebel 1.1 M3 and the JavaRebel SDK 1.1 M3. 

To connect JavaRebel to Jersey we need to implement two interfaces, the JavaRebel inteterface ReloadListener and the Jersey interface ContainerNotifier:

01 private static class Reloader implements ContainerNotifier,
02         ReloadListener {
03     private final List<ContainerListener> ls;
04
05     private final ClasspathResourceConfig rc;
06
07     public Reloader(ClasspathResourceConfig rc) {
08         ls = new ArrayList<ContainerListener>();
09         this.rc = rc;
10     }
11
12     public void addListener(ContainerListener l) {
13         ls.add(l);
14     }
15
16     public void reloaded(Class arg0) {
17         rc.reload();
18         for (ContainerListener l : ls) {
19             l.onReload();
20         }
21     }
22 }

The method reloaded on line 16 will get invoked every time JavaRebel detects a change to a Java class. The method addListener will get called by a Jersey container that wants to listen to container-based notifications. All containers shipped with Jersey will add a ContainerListener to a ContainerNotifier (if one is present, see later). When the reloaded method is invoked the class path is rescanned for classes then each listener registered with the container notifier will notified by an invocation of the onReload method (see line 19).

Next the ReloadListener and the ContainerNotifier need to be registered:

01 ClasspathResourceConfig rc = new ClasspathResourceConfig();
02 Reloader r = new Reloader(rc);
03       
04 rc.getProperties().put(
05     ResourceConfig.PROPERTY_CONTAINER_NOTIFIER, r);
06 ReloaderFactory.getInstance().addReloadListener(r); 
07
08 HttpServer s = HttpServerFactory.create("http://localhost:9999/",
09     ContainerFactory.createContainer(HttpHandler.class, rc));
10 s.start();

Lines 1 and 2 create the resource configuration (that scans class paths) and creates the reloader as previously shown. Lines 4 and 5 register the ContainerNotifier with Jersey by adding a property to the resource configuration. Line 6 registers the ReloadListener with JavaRebel. Finally lines 8, 9 and 10 start the Light Weight HTTP Server.

So if we configure to use JavaRebal, build and run the app, then change the code of the simple web application, recompile while still running, then Jersey will update accordingly.

I think the general concept works OK but it does require some finessing as currently it could be described as a rather brutish approach. A reload will occur for every class that has changed so Jersey will perform unnecessary reloads. I don't know how JavaRebel works but it may be useful to provide reloading within an a scope of "startReload" and "endReload". Furthermore Jersey needs to know about classes that have been removed and not just those that have been modified or added (i have not tested what JavaRebel does when classes are removed). On the Jersey side i think we can refine this to support add/update or deletion of classes. For resource classes this is probably fairly easy. For provider classes it is a little more work.

I could imagine such reloading capability might be useful not just for rapid development but for dynamic deployment of additional root resource classes as and when they are required.
 



import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.ws.rest.api.container.ContainerFactory;
import com.sun.ws.rest.api.container.httpserver.HttpServerFactory;
import com.sun.ws.rest.api.core.ClasspathResourceConfig;
import com.sun.ws.rest.api.core.ResourceConfig;
import com.sun.ws.rest.spi.container.ContainerListener;
import com.sun.ws.rest.spi.container.ContainerNotifier;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.zeroturnaround.javarebel.ReloadListener;
import org.zeroturnaround.javarebel.ReloaderFactory;

public class Main {
    @Path("/{id}")
    public static class RebelResource {
        @GET
        public String getOne(@PathParam("id") int id) {
            return Integer.toString(id) + "x";
        }
    }

    private static class Reloader implements ContainerNotifier,
            ReloadListener {
        private final List<ContainerListener> ls;

        private final ClasspathResourceConfig rc;

        public Reloader(ClasspathResourceConfig rc) {
            ls = new ArrayList<ContainerListener>();
            this.rc = rc;
        }

        public void addListener(ContainerListener l) {
            ls.add(l);
        }

        public void reloaded(Class arg0) {
            rc.reload();
            for (ContainerListener l : ls) {
                l.onReload();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        ClasspathResourceConfig rc = new ClasspathResourceConfig();
        Reloader r = new Reloader(rc);

        rc.getProperties().put(
            ResourceConfig.PROPERTY_CONTAINER_NOTIFIER, r);

        ReloaderFactory.getInstance().addReloadListener(r);

        HttpServer s = HttpServerFactory.create("http://localhost:9999/",
                ContainerFactory.createContainer(HttpHandler.class, rc));
        s.start();

        try {
            System.in.read();
        } finally {
            s.stop(0);
        }
    }
}


Friday Mar 07, 2008

Jersey 0.6 is released

Jersey

We have just released version 0.6 of Jersey (see the stable download directory). This aligns with the 0.6 release of the JAX-RS API and the latest editors draft.

This version will be available soon from the Glassfish Update Centre and as part of the NetBeans RESTful Web service plugin from the NetBeans Beta Update Centre.

We managed to achieve most things we highlighted in the schedule (more on the missing bits later).

Jakub added improved JSON un/marshaling to JAXB so one can produce JSON from JAXB beans that is much easier to consume by applications like jMaki (see the jMakiBackend example in the Jersey distribution). (I wonder if it is applicable to applications like GWT ?).

We improved on the work Marc did integrating Jersey with IoC containers, like Spring or Guice. Most developer-based things in Jersey are now components that defer to a "component provider" for instantiation and injection. This enables the life-cycle of resource classes to be independent of the IoC container. A developer on the Jersey users list has already experimented with Guice. There are some friction points that still need to be resolved: the main one being constructors where the IoC framework chooses the constructor but only knows about some constructor parameters and Jersey knows about others (especially request-based parameters like those from the request URI).

It is now very easy to register implementations of MessageBodyReader/Writer (the same underlying mechanism scanning for resource classes is reused). Marc and I show (here and here) how such readers/writers can be used with Abdera to create simple Atom-based services.

I promoted the client API used for Jersey unit testing to a public API of Jersey, see here (note that the class ResourceProxy has now been renamed to WebResource as suggested by Stefan Tilkov). This API focuses on the uniform interface constraint and i have found it very productive when writing unit tests. Some of the existing APIs focus on the lower-level request/response which as a consequence makes them more clunky to use. It also borrows from ease of use aspects of JAX-RS and the runtime, especially the message body readers/writers.

Finally i managed to put into code a very simple SPI for plugging in template processors and enabling a flexible model view controller approach. Essentially a resource class can return a template name and a model. The template name gets resolved to a template file in the class path that can be processed by a registered template processor that in turn processes the template with the given the model. I plan to blog about this in more detail later. The Bookstore example in the Jersey distribution provides an example of implicit views using JSPs. A developer on the user list has enabled Freemarker templates in a couple of lines of code and has experimental XSTL translations with JAXB beans (see this thread, which also attempts to explain the difference between implicit and explicit views).

The two areas where we did not make as much progress were adding servlet-based unit tests and evaluating a transition to using Maven.

However, recently on the users list there were requests about using Jetty with Jersey. That gave me just enough information to work things out fairly quickly so now i think we can get good unit tests in place for Jersey's servlet support and increase the code coverage percentages.

As for Maven, we just ran out of time. I believe it is likely to be a significant overhaul of the Jersey build process to transition to Maven and i have heard some Maven-hell stories that make me pause before diving in... so if there are any Maven experts out there with some free time of their hands and would like to help just drop me an email.

In terms of what's next:

  • align with 0.7 of the JAX-RS API and fill in all those missing little gaps (this may be a lot of work);
  • improve the scope of the JSON support (namely supporting XML attributes);
  • refine the MVC and template processor support to manage content types and language;
  • (if time permits) experiment with Grizzly and comet;
  • (if time permits) provide as part of the Jersey distribution component providers for Guice and Spring. This may be popular judging from the comments we have received; and
  • (if time permits) give some more Scala and Groovy TLC to Jersey; 

As usual feedback and participation are most welcome, just send email to the users list and/or log issues.

Friday Feb 08, 2008

Jersey Client API

Yesterday i finished refactoring the Jersey Client API and sprinkling it with some JavaDoc. This API was originally being used for Jersey unit testing but i think it is applicable in the larger context of a general RESTful client API.

With some HTTP-based client APIs you have to do a lot of crufty work to make even the simplest request and process a response. In addition they do not really capture the concept of resources and the uniform interface. I think this may be one reason why client-side code generation for creating a 'proxy' to a HTTP-based service is more prevalent than i think it should be. With this client API it is very easy to produce requests and consume responses with resources and the uniform interface at the fore of the API. Hopefully if you play with this API you will see how easy it is to use and why code-generation (and in general relying statically on specific server-side artifacts) is of less importance in this respect.

At the end of this blog is a complete example showing the basic features of the client-side API. This works with the latest Jersey 0.6 build. It contains a resource, called PropertiesResource, a message body reader/writer for reading and writing properties, and some client code in the Main.run method. When this code is executed it should complete successfully with no exception thrown. The example tests simple create, read, update and delete of properties where the server is in control of the property names and the client chooses the property values.

Let's go through the statements of the Main.run method.

Setting up the client:

ClientConfig cc = new DefaultClientConfig();
cc.getProviderClasses().add(PropertiesProvider.class);
Client c = Client.create(cc);

The client can utilize message body readers and writers just like the server-side (in addition to IoC frameworks). I have yet to implement the client-scanning parts so for now it is necessary to explicitly register readers and writers.

Create a resource proxy to the properties resource:

ResourceProxy pResource = c.proxy("http://localhost:9998/");

Now we can start calling methods on the resource proxy:

Properties p = pResource.get(Properties.class);
assertTrue(p.size() == 0);

A GET request should return a Properties instance that has no properties. Notice how the HTTP method is used a bit like RMI but since the interface is uniform it never varies for standard HTTP-based resources. Like the server-side the client side can easily avail of Java types for representations.

Creating a new property resource:

ClientResponse cr = pResource.
  type("text/plain").
  post(ClientResponse.class, "some stuff");
assertTrue(cr.getStatus() == 201);

A POST method is called on the properties resource. The builder pattern is used to set the content type of the request (it is possible for the client to specify what is acceptable using the accept method) and the post method is invoked with the requested return type and the request entity (a String instance). The status code of the response should be 201 (Created). Notice that the client can choose to get all the response information or the representation previously shown for the GET request. The same methods are used as it is the return type that specifies such behavior.

Verify the created property resource: 

ResourceProxy vResource = c.proxy(cr.getLocation());
String content = vResource.get(String.class);
assertTrue("some stuff".equals(content)); 

The response to the POST request (if successful) will contain the location to the newly created property resource. This can be used to create a new resource proxy. A get method is called on that resource proxy and it should return the same information that was POSTed.

Verify the contents of the created property resource are also present in the properties resource:

p = pResource.get(Properties.class);
assertTrue(p.size() == 1);
assertTrue(p.contains("some stuff"));

Delete the created resource:

try {
    vResource.delete();
} catch (UniformInterfaceException e) {
    assertTrue(false);
}

The DELETE method on the property resource is invoked. In this case the client does not send anything and does not request a response. If something other than a successful response occurs an exception will be thrown.

Verify that the property resource has been deleted: 

try {
    content = vResource.get(String.class);
} catch (UniformInterfaceException e) {
    assertTrue(e.getResponse().getStatus() == 404);
}

In this case we expect an exception to be thrown. The ClientResponse can be obtained from the exception to check the status code, which should be 404 (Not Found). But we can also do it like this if we wish:

cr = vResource.get(ClientResponse.class);
assertTrue(cr.getStatus() == 404);

So it is possible to verify the status code explicitly or work under the assumption that success is the norm and errors are the exception.

Hopefully that gives you a flavor of how to use the API from a resource and uniform interface perspective. Given the recent blogs on Jersey and Abdera (see here and here) it should be easy to apply Abdera on the Jersey client side as it was on the server side.

If you want you can still build client requests independently and pass them to the Client instance. You can also add filters for say performing authentication. There is a lot that still can be done. For example, a client requesting a CreatedResponse could verify the status code and location header and throw an exception if it does not conform. Asynchronous requests may be possible by the client requesting say Future<String> or Future<ClientResponse>. I already have a feature request to add request/response progress listeners. Since services may be clients too there is lots of opportunity for such clients to share resources with the server making things more efficient and scalable. So much to do! If you would like to help out just contact me :-)


import com.sun.net.httpserver.HttpServer;
import com.sun.ws.rest.api.client.Client;
import com.sun.ws.rest.api.client.ClientResponse;
import com.sun.ws.rest.api.client.ResourceProxy;
import com.sun.ws.rest.api.client.UniformInterfaceException;
import com.sun.ws.rest.api.client.config.ClientConfig;
import com.sun.ws.rest.api.client.config.DefaultClientConfig;
import com.sun.ws.rest.api.container.httpserver.HttpServerFactory;
import com.sun.ws.rest.spi.resource.Singleton;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.Properties;
import java.util.UUID;
import javax.ws.rs.ConsumeMime;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.ProduceMime;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpContext;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

public class Main {

    @ProduceMime("text/plain")
    @Provider
    public static class PropertiesProvider implements
            MessageBodyWriter<Properties>,
            MessageBodyReader<Properties> {

        public void writeTo(Properties p, MediaType mediaType,
                MultivaluedMap<String, Object> headers, OutputStream out)
                throws IOException {
            p.store(out, null);
        }

        public boolean isWriteable(Class<?> type) {
            return Properties.class.isAssignableFrom(type);
        }

        public long getSize(Properties p) {
            return -1;
        }

        public boolean isReadable(Class<?> type) {
            return Properties.class.isAssignableFrom(type);
        }

        public Properties readFrom(Class<Properties> type, MediaType mediaType,
                MultivaluedMap<String, String> headers, InputStream in)
                throws IOException {
            Properties p = new Properties();
            p.load(in);
            return p;
        }
    }
   
    @Path("/")
    @ProduceMime("text/plain")
    @ConsumeMime("text/plain")
    @Singleton
    public static class PropertiesResource {
        @HttpContext UriInfo uriInfo;
       
        Properties p = new Properties();
       
        @GET public Properties get() {
            return p;
        }
       
        @POST public Response post(String in) {
            String id = UUID.randomUUID().toString();
           
            p.setProperty(id, in);
           
            URI u = uriInfo.getAbsolutePathBuilder().path(id).build();
            return Response.created(u).build();
        }
       
        @Path("{id}") @GET public synchronized String getContent(
                @PathParam("id") String id) {
            String content = p.getProperty(id);
            if (content == null) throw new WebApplicationException(404);
           
            return content;
        }
       
        @Path("{id}") @PUT public synchronized void updateContent(
                @PathParam("id") String id) {
            String content = p.getProperty(id);
            if (content == null) throw new WebApplicationException(404);
           
            p.setProperty(id, content);
        }
       
        @Path("{id}") @DELETE public synchronized void deleteContent(
                @PathParam("id") String id) {
            String content = p.getProperty(id);
            if (content == null) throw new WebApplicationException(404);
           
            p.remove(id);
        }
    }
   
    public static void run() throws Exception {
        // Create the client
        ClientConfig cc = new DefaultClientConfig();
        // Include the properties provider
        cc.getProviderClasses().add(PropertiesProvider.class);
        Client c = Client.create(cc);
       
        // Create the resource proxy to the resource
        ResourceProxy pResource = c.proxy("http://localhost:9998/");
       
        // Get the current properties and verify it is empty
        Properties p = pResource.get(Properties.class);       
        assertTrue(p.size() == 0);
       
        // Create a new property
        ClientResponse cr = pResource.
                type("text/plain").
                post(ClientResponse.class, "some stuff");
        assertTrue(cr.getStatus() == 201);

        // Verify the created resource
        ResourceProxy vResource = c.proxy(cr.getLocation());
        String content = vResource.get(String.class);
        assertTrue("some stuff".equals(content));
       
        // Get the current properties and verify the contents
        p = pResource.get(Properties.class);
        assertTrue(p.size() == 1);
        assertTrue(p.contains("some stuff"));
       
        // Delete the created resource
        try {
            vResource.delete();
        } catch (UniformInterfaceException e) {
            // This will occur when a status >= 300 occurs
            assertTrue(false);
        }
       
        // Verify resource is deleted
        try {
            content = vResource.get(String.class);
        } catch (UniformInterfaceException e) {
            // This will occur when a status >= 300 occurs
            assertTrue(e.getResponse().getStatus() == 404);
        }
       
        // Verify resource is deleted using ClientResponse
        cr = vResource.get(ClientResponse.class);
        assertTrue(cr.getStatus() == 404);
       
        // Verify properties resource contains no properties
        p = pResource.get(Properties.class);
        assertTrue(p.size() == 0);       
    }
   
    private static void assertTrue(boolean v) {
        if (v == false) throw new RuntimeException();
    }
   
    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServerFactory.create("http://localhost:9998/");
        server.start();
       
        try {
            run();
        } finally {
            server.stop(0);
        }
    }
}

Thursday Feb 07, 2008

Jersey and Abdera with a twist of JSON

Marc recently blogged on integrating Jersey with Abdera. Marc shows how easy it is to integrate, especially if using the latest Jersey 0.6 builds (see the comments) as there is no need to use the messy and error prone META-INF/services for registration of message body readers/writes.

I am going to extend Marc's example to add a twist of JSON to the mix. James shows here how to use Abdera with JSON (in the larger context of mapping between Atom documents encoded in XML and JSON). If you want to play with this code you will need to use the latest Jersey 0.6 build.

Lets refactor the AbderaSupport class to be as follows:

public abstract class BaseAbderaSupport implements
        MessageBodyWriter<Object>,
        MessageBodyReader<Object> {

    private final static Abdera abdera = new Abdera();

    public static Abdera getAbdera() {
        return abdera;
    }
    public long getSize(Object arg0) {
        return -1;
    }
    public boolean isWriteable(Class<?> type) {
        return Feed.class.isAssignableFrom(type) ||
                Entry.class.isAssignableFrom(type);
    }
    public void writeTo(Object feedOrEntry, MediaType mediaType)
            MultivaluedMap<String, Object> headers,
            OutputStream outputStream) throws IOException {
        if (feedOrEntry instanceof Feed) {
            Feed feed = (Feed) feedOrEntry;
            write(feed.getDocument(), outputStream);
        } else {
            Entry entry = (Entry) feedOrEntry;
            write(entry.getDocument(), outputStream);
        }
    } 
    public boolean isReadable(Class<?> type) {
        return Feed.class.isAssignableFrom(type) ||
                Entry.class.isAssignableFrom(type);
    }
    public Object readFrom(Class<Object> feedOrEntry, MediaType mediaType,
            MultivaluedMap<String, String> headers,
            InputStream inputStream) throws IOException {
        Document<Element> doc = read(inputStream);
        Element el = doc.getRoot();
        if (feedOrEntry.isAssignableFrom(el.getClass())) {
            return el;
        } else {
            throw new IOException("Unexpected payload, expected " +
                    feedOrEntry.getName() +
                    ", received " + el.getClass().getName());
        }
    } 
    protected abstract void write(Document<? extends Base> doc,
            OutputStream outputStream) throws IOException;

    protected abstract Document<Element> read(InputStream inputStream)
            throws IOException;
}

Notice the protected abstract methods at the end. Then lets extend this base class for XML support:

@Provider
@ProduceMime("application/atom+xml")
@ConsumeMime("application/atom+xml")
public class XMLAbderaSupport extends BaseAbderaSupport {

   protected void write(Document<? extends Base> doc,
           OutputStream outputStream)  throws IOException {
       doc.writeTo(outputStream);
   }
  
   protected Document<Element> read(InputStream inputStream) throws IOException {
       return getAbdera().getParser().parse(inputStream);      
   }
}

and extend for JSON support:

@Provider
@ProduceMime("application/json")
@ConsumeMime("application/json")
public class JSONAbderaSupport extends BaseAbderaSupport {

   protected void write(Document<? extends Base> doc,
           OutputStream outputStream)  throws IOException {
       Writer w = getAbdera().getWriterFactory().getWriter("json");
       doc.writeTo(w, outputStream);
   }
   
   protected Document<Element> read(InputStream inputStream) throws IOException {
       Parser p = getAbdera().getParserFactory().getParser("json");
       return p.parse(inputStream);       
   }
}

Notice that the JSONAbderaSupport class uses the "application/json" media type.

Now lets create a very simple resource that returns an empty Atom feed:

@ProduceMime({"application/atom+xml", "application/json"})
@Path("myfeed")
public class FeedResource {
   @HttpContext
   private UriInfo uriInfo;

   @GET
   public Feed getFeed() {
       Feed f = BaseAbderaSupport.getAbdera().getFactory().newFeed();
       f.setTitle("TITLE");
       URI feedLink = uriInfo.getRequestUri();
       f.addLink(feedLink.toString(),"self");      
       return f;
   }
}

Notice that the feed resource declares that it produces the "application/atom+xml" and the "application/json" media types. 

Penultimately lets deploy all this using the light weight HTTP server:

HttpServer server = HttpServerFactory.create("http://localhost:9998/");
server.start();

Notice that there is no need to explicitly reference the classes XMLAbderaSupport, JSONAbderaSupport and FeedResource. By default they are found automatically by scanning the Java classes files in the java.class.path for the appropriate annotations.

Finally lets test the feed resource using curl (i have formatted the output):

curl -v -H "Accept: application/atom+xml" http://localhost:9998/myfeed
* About to connect() to localhost port 9998
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 9998
> GET /myfeed HTTP/1.1
> User-Agent: curl/7.15.5 (i386-pc-solaris2.11) libcurl/7.15.5
OpenSSL/0.9.8a zlib/1.2.3 libidn/0.6.8
> Host: localhost:9998
> Accept: application/atom+xml
>
< HTTP/1.1 200 OK
< Date: Thu, 07 Feb 2008 10:48:35 GMT
< Content-type: application/atom+xml
< Transfer-encoding: chunked
* Connection #0 to host localhost left intact
* Closing connection #0
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title type="text">TITLE</title>
<link href="http://localhost:9998/myfeed" rel="self" />
</feed>


curl -v -H "Accept: application/json" http://localhost:9998/myfeed
* About to connect() to localhost port 9998
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 9998
> GET /myfeed HTTP/1.1
> User-Agent: curl/7.15.5 (i386-pc-solaris2.11) libcurl/7.15.5
OpenSSL/0.9.8a zlib/1.2.3 libidn/0.6.8
> Host: localhost:9998
> Accept: application/json
>
< HTTP/1.1 200 OK
< Date: Thu, 07 Feb 2008 10:49:02 GMT
< Content-type: application/json
< Transfer-encoding: chunked
* Connection #0 to host localhost left intact
* Closing connection #0
{
"contributors":[],
"title":"TITLE","categories":[],
"entries":[],
"authors":[],
"links":[
{
"href":"http://localhost:9998/myfeed",
"rel":"self"
}]
}

In less than an hour of playing around and writing this blog I have XML and JSON support for servicing Atom documents. Of course it helps that Abdera made it easy to integrate. My first impressions of playing around with Jersey and Abdera are that they are very complimentary for building Atom-based services.

Tuesday Feb 05, 2008

JavaOne and Jazoon

We submitted a technical session on JAX-RS and a BOF on Jersey to JavaOne and both have been accepted.

In terms of the technical session our current thinking is we would like to describe the REST style (grounded in the Resource Oriented Architecture terminology), how it connects to the JAX-RS API,  and how you code to that API in a series of logical steps (for example the Resource Oriented Architecture properties) to build an example. I think this would be better than lots of talk (cue hand waving) followed by a 5 to 10 minute demo. Intermixing these three things is a tricky balancing act but i think its worth the effort to better communicate about JAX-RS. We need to choose an example, if you have any ideas on what you would like to see, write a comment or send me some email.

In terms of the BOF i deliberately made the abstract "loose" and would like to drive the content based on feedback before or at the BOF. We can come up with some pre-prepared slides on the Jersey architecture, additional features, JAX-RS, and some demos but i would really like things driven by what developers want to see. So again if you have any ideas/requests write a comment or send me some email.

I have also been invited to present at Jazoon08 (and very much enjoyed Jazoon07 last year). I suspect we are going to reuse a lot of material that was prepared for JavaOne :-) but we will endeavor to improve it based on feedback we receive.

Friday Feb 01, 2008

Integrating Jersey and Spring: Take 2

Marc previously described how to integrate Spring with Jersey 0.4 for the instantiation of root resources. This was an great first step but it fell short in a couple of areas:

  • there was some initialization code that could not be performed at initialization stage;
  • it was necessary to annotate (or specify the default provider for) all resources with a Spring specific life-cycle annotation, thus it was not possible to write 'vanilla' resources for use with Spring; and
  • this was only applicable to root resource classes. Jersey has other components, such as instances of MessageBodyReader/Writer, and it would be useful if those components could also be Spring-enabled.

I have spent this week unifing the instantiation of components (in addition to removing the requirement of META-INF/services for registration, it is all dynamic like for root resource classes). Instantiation of any component managed in Jersey is deferred to a ComponentProvider. By default Jersey provides a basic implementation but it is possible to  provide an application-specific implementation for say Spring. Jersey will then adapt that implementation so that Spring-registered and non-Spring-registered components can be instantiated.

(All code referenced below only works with the latest build of Jersey.)

I am still pondering the best way to declare an application-specific ComponentProvider but for now i am experimenting specifically with a Spring aware Servlet. Jersey ships with a servlet that can be extended to configure the WebApplication, which makes it very easy to extend for Spring support. Below is the code for the SpringServlet:

public class SpringServlet extends ServletContainer {
   
    private static class SpringComponentProvider implements ComponentProvider {
        private ApplicationContext springContext;

        SpringComponentProvider(ApplicationContext springContext) {
            this.springContext = springContext;
        }
       
        private String getBeanName(Class c) {
            String names[] = springContext.getBeanNamesForType(c);
            if (names.length == 0) {
                return null;
            } else if (names.length > 1) {
                throw new RuntimeException("Multiple configured beans for "
                        + c.getName());
            }
            return names[0];           
        }
       
        public Object getInstance(Scope scope, Class c)
                throws InstantiationException, IllegalAccessException {           
            String beanName = getBeanName(c);
            if (beanName == null) return null;
           
            if (scope == Scope.WebApplication &&am