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);
    }
}
Comments:

[Trackback] Bookmarked your post over at Blog Bookmarker.com!

Posted by jersey on May 26, 2008 at 09:50 AM CEST #

Sounds interesting. How are content-types related to views? I only skimmed through the Jersey docs, so I might have missed the important piece, but I got the impression that template processors are not selected with taking the content-type or to content negotiation into account, right? I actually expected to have an MVC-like approach underlying to abstract representations for all methods. But it seems that resources have to be annotated in a hard-coded fashion with the mime-types it can produce and/or consume. Is this really the best way to implement RESTful services?

In my understanding of REST, resources are independent of their representation/rendering, i.e. they are so to say normalized and can be rendered into all kind of representation. In Java such a normalized resource could be simply a object, and it could be up to the view layer to decide which processor should render the representation. This way resources are decoupled from representations and representation processors can be added like plugins later in the development process. Such a processor has of course to be capable of a bi-directional transformation (marshalling/unmarshalling). That way, GET and PUT are always idempotent, even if a GET has returned another representation as the PUT received, as long as the state information has been the same. Imagine requesting the state of resource in JSON but updating its state with XML. The same applies to POST, the processor translates the request into the normalized format that can then be used to create a resource, etc.

So, am I reinventing the wheel and it's already there? Otherwise I think this is a more flexible/extensible way to map resources to java methods (using an MVC approach). What do you think?

Posted by Tammo van Lessen on May 26, 2008 at 04:59 PM CEST #

Hi Tammo,

I should of mentioned that the template processing depends on another layer of MVC (that is not template oriented that most people might understand in terms of Web applications), using the MessageBodyWriter, a standard JAX-RS interface, that operates given a media type and a Java type (in the case of templates that is the Viewable type). A template processor operates given a template reference and a model (see later on media type).

It is possible say for a resource method to return a JAXB bean that may be serialized as XML, JSON or FastInfoset as determined by the @ProduceMime on the resource method, one or more MessageBodyWriter's annotated with @ProduceMime, and when the client makes a request what it declares is are media types for the returned representation, using the Accept header. (The same is possible the other way using @ConsumeMime and MessageBodyReader).

The @ProduceMime acts as an identifier for the method selection mechanism, an identifier to select a MessageBodyWriter, and also for the runtime to determine that nothing is acceptable and it should return a 406 (Not Acceptable) response. Further this information is really useful for creating documentation and machine processable representations like WADL.

In reality resources will only implement a set of supported representations. Using @ProduceMime does not really hard-code things, it can be modified, new resource methods added as and when use-cases require it (one can also support things dynamically if need be). When implementing a service you need to ask "what media types will i support?", and the use of certain Java types will also depend on this (e.g. JAXB beans or Abdera Atom types etc). The important thing is whether you can modify and adapt the resources to support new requirements as and when required. IMHO with JAX-RS this is possible when using @ProduceMime.

In terms of explicit/implicit MVC with media types, it is something i need to work on. I think it is a matter of allowing @ProduceMime on the template processor to declare what media types it produces (just like MessageBodyWriter). This requirement has been less pressing as the motivation has been focused around templates that produce (X)HTML.

Hope this helps,
Paul.

Posted by Paul Sandoz on May 27, 2008 at 02:15 AM CEST #

Thank you for this blog post, it helps a lot understanding what happens with the TemplateProcessor.

What I still don't get is why a specific TemplateProcessor is used. I can see in the source code that the JSPTemplateProcessor is added to the Singletons list, in the configuration bean, but I don't understand why (for instance, if I would like to replace the JSPTemplateProcessor by my implementation).

What I would like to do is to add a prefix to the resolved path for JSP: I really would like to put my JSP in WEB-INF/jsp/, so that it wouldn't be accessible directly by users. Is there a simple way to do this, instead of explicitly returning Viewable ?

Thank you !

Posted by Julien Wajsberg on November 20, 2008 at 05:20 PM CET #

Hi Julien,

Am i correct in understanding that you want to change the default base directory location of where the JSP views belong? If so i can easily add a fix such that the base directory can be configured.

Also you can override the default implementation by registering your own template provider. It will get called before any that are supplied by Jersey.

For further detailed discussion i recommend we communicate via email on:

mailto:users@jersey.dev.java.net

Paul.

Posted by Paul Sandoz on November 21, 2008 at 03:42 AM CET #

Also really interested in config to move jsp's into WEB-INF.. Is there any follow up to that? Cheers! ian.

Posted by Ian Ibbotson on September 08, 2009 at 10:13 AM CEST #

Hi Ian

[I am just back from holiday hence the delay replying].

See:

https://jersey.dev.java.net/nonav/apidocs/1.1.2-ea/jersey/com/sun/jersey/spi/container/servlet/ServletContainer.html#JSP_TEMPLATES_BASE_PATH

that can be set in the web.xml to change the default location.

Posted by Paul Sandoz on September 23, 2009 at 02:18 AM CEST #

Hi, thanks for the article!

I was wondering, do you have any info on how to access the session object using Jersey MVC? Like you said, there's not much doco out there :)

Posted by denise on October 01, 2009 at 09:28 AM CEST #

@Denise: can you describe a bit more about what you want to do?

The (servlet) session can be accessed using Servlet APIs. See the following for more details on accessing the servlet API:

https://jersey.dev.java.net/nonav/documentation/1.1.2-ea/user-guide.html#d4e412

Is that sufficient?

An alternative is to annotate a resource class with @PerSession [1] and thus one instance of that resource class will be created per session. So state can be stored on that instance.

[1] https://jersey.dev.java.net/nonav/apidocs/1.1.2-ea/jersey/com/sun/jersey/spi/container/servlet/PerSession.html

Posted by Paul Sandoz on October 02, 2009 at 03:43 AM CEST #

Thanks for the reply!

I want to be able to access a session attribute from the velocity template page. Is there a standard way to access the session or request object from my template?

Posted by Denise on October 02, 2009 at 10:49 PM CEST #

See the following link for the pre-defined variables available to a JSP:

http://www.nakov.com/inetjava/lectures/part-3-webapps/InetJava-3.7-JSP-Predefined-Variables.html

Does that help?

You can also access the Jersey resource class instance using the pre-defined "it" variable.

Posted by Paul Sandoz on October 05, 2009 at 02:40 AM CEST #

Thanks for your post. I made a simple example and post it in french here http://www.opikanoba.org/java/rest-jersey-jsp

Posted by Fred on February 27, 2010 at 11:28 AM CET #

@Denise:
You can use the following to access sessions in Jersey:

@GET
@Path("/getsession") @Produces(MediaType.APPLICATION_JSON)
@Consumes("application/x-www-form-urlencoded")
public String testSession(@Context HttpServletRequest req)
{
String jsessionid = req.getSession().getId();

logger.info("JSESSIONID is: " + jsessionid);

return jsessionid;
}

Posted by Tulio Domingos on April 07, 2010 at 10:45 AM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

sandoz

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today