Hi,
I have just committed changes to support most of what i wrote below. The
Bookstore example has been updated (look at the web.xml for enabling of
implicit views, and note that in the resource classes there is no need
for the @View annotations, the templates are picked up dynamically).
The template processing interface is a bit limited and there is
currently only support for JSPs, see the:
com.sun.ws.rest.impl.container.servlet.JSPTemplateProcessor
But i hope the template interfaces can be iterated on without too much
impact on the end-user.
I plan to blog about it in more detail this week.
Stuff to think about:
- scoping of templates for media type and language
- Velocity and/or Freemarker template processors.
- I would like to integrate a template system (if it exists) whereby
the resource class provides 'snippets' of information to an HTML page,
much like the way snippets in the Scala lift web framework behave,
thus avoiding code creeping into the template.
- How to configure that an explicit template should not be used
implicitly?
- Should static files take precedence over HTTP methods?
- Should one use an annotation on the HTTP method to specify the
template name for explicit views?
Paul.
Paul Sandoz wrote:
> Hi,
>
> It was politely pointed out to me that what i wrote was a bit too much
> of a brain dump. So what follows below is a second try with a specific
> proposal that is hopefully clearer and more precise.
>
> Paul.
>
> Template structure layout
> -------------------------
>
> <context>/
> foo/
> Foo/
> super.jsp # an inheritable template
> override.jsp
> bar/
> BarResource/
> index.jsp
> item.jsp
> create.jsp
> baz/
> BazResource/
> static.html # a static file
> override.jsp # overrides that in foo/Foo/
>
> Classes
> -------
>
> package foo;
> public class Foo { ... }
>
> package bar;
> @Path("bar") public class BarResource extends foo.Foo {
>
> @Path("{id}") @GET public Viewable item(
> @PathParam("id") String id) {
> String model = ...;
> return new Viewable("item", model);
> }
>
> @POST public Response create() {
> URI cu = ...
> Viewable v = new Viewable("create", this);
> return Response.created(u).entity(v).build();
> }
>
> }
>
> package baz;
> @Path("baz") public class BazResource extends foo.Foo {
> @GET public String get() {
> return "content";
> }
> }
>
>
> Request Template Model
> ------------------------------------------------------------------------
> GET /bar /bar/BarResource/index.jsp instance of BarResource
>
> GET /bar/1 /bar/BarResource/item.jsp instance of String created
> by BarResource.item
> GET /bar/super " "
> GET /bar/index " "
> GET /bar/item " "
> GET /bar/create " "
>
> POST /bar /bar/BarResource/create.jsp instance of BarResource
> returned by
> BarResource.create
>
> GET /baz N/A N/A specific content is
> returned
>
> GET /baz/ N/A N/A the static file is
> static.html returned
>
> GET /baz/super /foo/Foo/super.jsp instance of BazResource
>
> GET /baz/ /bar/Baz/override.jsp instance of BazResource
> override
>
>
> Rules
> -----
>
> - The directory path of templates and static files for a resource class
> is specified by the fully qualified name of that class converted to a
> path.
>
> - A template, "xxxx.yyyy", consists of a template name "xxxx" and
> template meta-data "yyyy", where "yyyy" describes the template
> technology and potentially the media type and language.
>
> - A resource class will inherit the templates and static files from the
> direct and indirect super classes. A class can override the templates
> or static files of a direct or indirect super class.
>
> - If a request URI path matches a HTTP method on a resource then that
> method is processed. An HTTP method takes precedence over matching of
> template and static files associated with a resource.
>
> - A HTTP method may return a Viewable object that contains the
> template name to use and the instance of the model passed to the
> template.
>
> - If a request URI path does not match any HTTP methods but matches the
> template name of a template associated with the resource class then
> that template is selected and the model is the instance of the
> resource class.
>
> - If a request URI path does not match any HTTP methods or templates
> but matches a static file associated with the resource class then that
> static file is returned.
>
> - If a request URI path does not match a HTTP method, template or static
> file a 404 is returned.
>
>
> Questions/thoughts
> ------------------
>
> - Should static files take precedence over HTTP methods?
>
> - Should one use an annotation on the HTTP method to specify the
> template name?
>
> @Viewable("item")
> @Path("{id}") @GET public String show(
> @PathParam("id") String id) {
> String model = ...;
> return model;
> }
>
>
>
> Paul Sandoz wrote:
>> Hi,
>>
>> Below are some ideas on MVC support for Jersey. Sorry about the
>> length. I wanted to 'save' my ideas as well as giving people an
>> opportunity to comment and contribute if they so wish before i start
>> diving in and developing.
>>
>> Paul.
>>
>> Implicit use of templates with resource class as model
>> ------------------------------------------------------
>>
>> Given a class:
>>
>> foo.Resource
>>
>> And a template:
>>
>> <context>/foo/Resource/abc.jsp
>>
>> If the request path matches "abc" and is an HTTP GET request then the
>> instance of foo.Resource will be passed to the template "abc.jsp" to
>> produce the response.
>>
>> In general there can be a URI rule on a resource class that occurs
>> first for matching:
>>
>> (<expression for path segment>?)(/)?
>>
>> The rule is accepted if:
>>
>> 1) the matching path segment is empty, there is an 'index' template and
>> there is no @GET method implemented on the associated resource class;
>>
>> 2) the matching path segment is non-empty, and the encoded characters of
>> that segment match a template with the same name, and there is no
>> @GET method with an @Path value that has the same name as the
>> template; or
>>
>> 3) the matching path segment matches a static resource of the same name.
>>
>>
>> Explicit use of templates with resource class returning a model
>> ---------------------------------------------------------------
>>
>> If there is a GET method on foo resource
>>
>> @GET
>> Model get() { ... }
>>
>> and there is a template:
>>
>> <context>/foo/Resource/index.jsp
>>
>> Then the Model instance is the input to the template index.jsp
>>
>> If there is a GET method on foo resource
>>
>> @GET
>> @Path("abc")
>> Model getAbc() { ... }
>>
>> and there is a template:
>>
>> <context>/foo/Resource/abc.jsp
>>
>> Then the Model instance is the input to the template abc.jsp
>>
>> If there is a GET method on foo resource
>>
>> @GET
>> @Path("abc/{id}")
>> Model getAbc() { ... }
>>
>> and there is a template:
>>
>> <context>/foo/Resource/abc%2F{id}.jsp
>>
>> Then Model is the input to the template abc%2F{id}.jsp
>>
>> This is a little odd. It sort of breaks the hierarchical model. This
>> path will not be matched by the implicit URI rule.
>>
>> The existence of such templates can be verified at initiation time and
>> can be input into the implicit approach to determine acceptance.
>>
>> If a GET method has a template associated with it then it returns a
>> model that is passed to the template for processing.
>>
>>
>> Template inheritance
>> --------------------
>>
>> If there are classes:
>>
>> @Path("foo")
>> class foo.Resource
>>
>> @Path("bar")
>> class bar.Resource extends foo.Resource { ... }
>>
>> And templates:
>>
>> <context>/foo/Resource/abc.jsp
>>
>> <context>/foo/Resource/xyz.jsp
>>
>> Then class bar.Resource will inherit templates from foo.Resource
>> unless it overrides them. So a path "bar/abc" will match the template
>> abc.jsp and use the model that is an instance of bar.Resource.
>>
>>
>> Choice of template name
>> -----------------------
>>
>> @Path("foo")
>> @Template("welcome")
>> class foo.Resource {
>>
>> @GET String get() { ... }
>>
>> @GET @Path("abc") @Template("xyz") String getAbc() { ... }
>>
>> }
>>
>> A path matching "foo" would pass the String instance returned from the
>> "get" method to the template "<context>/foo/welcome".
>>
>> A path matching "foo/abc" would pass the String instance returned from
>> the "getAbc" method to the template "<context>/foo/xyz".
>>
>>
>> Templates for other HTTP methods
>> --------------------------------
>>
>> @Path("foo")
>> class foo.Resource {
>>
>> @POST @Template("post") String post() { ... }
>>
>> }
>>
>> A path matching "foo" with the HTTP method POST would pass the String
>> instance returned from the "post" method to the template
>> "<context>/foo/post".
>>
>> It seems appropriate to support implicit use of templates for only GET
>> methods i.e. since JAX-RS separates out HTTP methods the same should
>> be encouraged for templates.
>>
>>
>> Programmatic use
>> ----------------
>>
>> @Path("foo")
>> class foo.Resource {
>>
>> @HttpContext TemplateContext context;
>>
>> @GET Response get() {
>> String m = ...
>> return context.forwardTo("welcome", m);
>> }
>>
>> }
>>
>> A path matching "foo" with the HTTP method GET would obtain a String
>> instance "m" as the model and obtain a response from the
>> TemplateContext instance that represents a response to forward "m" to
>> the template "<context>/foo/welcome".
>>
>> Alternatively we can use a specific Java type:
>>
>> @Path("foo")
>> class foo.Resource {
>>
>> @GET Viewable get() {
>> String m = ...
>> return new Viewable("welcome", m);
>> }
>>
>> }
>>
>> or:
>>
>> @Path("foo")
>> class foo.Resource {
>>
>> @GET Viewable get() {
>> String m = ...
>> return new Viewable(m);
>> }
>>
>> }
>>
>> In the latter case the template is implicitly determined. A Response
>> builder can be used with Viewable as well. I think i prefer the
>> Viewable instance approach. There will be a message body writer for
>> the Viewable type. This writer will defer to template implementations
>> themselves that are an extension of message body writer.
>>
>>
>> Issues/TODO
>> -----------
>>
>> If using the non-programmatic approach should template support always
>> be explicit using the @Template annotation (it does not have to have a
>> value by default) ? Then the behavior of the resource classes will be
>> consistent rather than behaving differently if templates are present
>> or not. I think i prefer that the programmatic approach always be used
>> for HTTP resource methods and the non-annotated implicit approach
>> takes lesser precedence that the former and works for paths that don't
>> match the paths on HTTP resource methods and only works for HTTP GET.
>>
>> Registration of template implementations. Use @Provider.
>>
>> Support for localization, for example templates for French, Spanish
>> and English, or a properties mechanism for one template with
>> translated property files.
>>
>> Support for content types, for example templates returning XML, HTML
>> etc. based on client accept header.
>>
>>
>
--
| ? + ? = To question
----------------\
Paul Sandoz
x38109
+33-4-76188109