I'll only say that without caching somewhere along the line, making any 
kind of front-facing UIs with Restlet is going to be painful. When this 
comes (Restlet 2.1?), the proper Restlety route for this may suggest 
itself. fetchCalendar may cache, but does wrapIfHtml cache?


Though, I do like the basic approach -- I did something similar and 
simpler with my pure-Java Restlet applications that speak to Ext-JS 
REST-aware widgets. I just had to return JSON, but very specific JSON.


I think you can improve your own idea by automatically handling etags or 
modification dates in wrapIfHtml, perhaps storing a timestamp in the 
calendar data itself. If you can't cache, at least conditionalize the HTTP.


-Tal


On 10/20/2010 07:58 AM, Tim Peierls wrote:

> I went ahead and did this as I outlined (see quoted message below), 
> for Freemarker and Jackson only, no Atom. there were several issues 
> along the way.
>
> I had to replace the built-in ConverterHelpers that come with the 
> Restlet extensions with my own subclasses of those ConverterHelpers. 
> (The JacksonConverter is fine, except I needed to provide a custom 
> ObjectMapper to use "materialized beans") That meant running through 
> the list of registered converters looking for one of the right type 
> and removing it, then adding my own.
>
> I have to return different objects depending on whether the client is 
> expecting HTML or JSON. For JSON, I just return the plain domain 
> object. For HTML, I wrap the domain object with a dynamic proxy that 
> adds support for a special interface that names a Freemarker template 
> -- this interface is detected by my custom FreemarkerConverter and 
> used to produce the TemplateRepresentation by combining the template 
> with the domain object data model.
>
> Since I have to use that wrapping logic in every resource 
> implementation that supports HTML representations, I bundled it into a 
> method, wrapIfHtml, of a common superclass that extends 
> ServerResource. Now my @Get method can look like this:
>
>     // Request URI is something like /calendar/{calendar} -- 
> fetchCalendar does the heavy lifting.
>     @Get("html|json") public Calendar getCalendar() {
>         String id = (String) getRequest().getAttributes().get("calendar");
>         Calendar calendar = fetchCalendar(id); // throws 404 
> ResourceException if id not found
>         return wrapIfHtml(calendar, Calendar.class, "Calendar.html");
>     }
>
> You might think I could just wrap _always_, even for JSON, but it 
> turns out that the Jackson materialized bean logic doesn't work on 
> dynamic proxies. I want to use the materialized bean stuff because it 
> saves me having to write and expose implementations for my domain 
> interfaces.
>
> But two of my questions remain: Is there (or will there soon be) a 
> better way? (Tal, aren't you going to mention Prudence? ;-))  Am I 
> going against the Restlet grain?
>
> --tim
>
>
> On Thu, Oct 14, 2010 at 10:07 PM, Tim Peierls <t...@peierls.net 
> <mailto:t...@peierls.net>> wrote:
>
>     On Sat, Sep 11, 2010 at 11:47 AM, Jerome Louvel
>     <jerome.lou...@noelios.com <mailto:jerome.lou...@noelios.com>> wrote:
>
>         Good news, is that we are planning to simplify this binding in
>         version 2.1 but associating the template files with
>         representation beans based on the bean qualified class name.
>         The converter service would allow the developer to indicate
>         where the template lives, for example in the classpath next to
>         the bean class or in a separate directory.
>
>
>     That sounds great. I'm impatient, though, and I want to implement
>     my own version of this in 2.0.x, with some additional design
>     constraints:
>
>     I want to write resource interfaces like this:
>
>     public interface CalendarResource {
>         @Get("html|atom|json") Calendar getCalendar();
>         @Post("form|atom|json:html|atom|json") Event addEvent(Event
>     event);
>     }
>
>     where Calendar is a domain-level interface with some associated
>     mechanisms for converting a Calendar instance into a
>     (Freemarker) TemplateRepresentation (looking up the template file
>     based on the class name, as Jerome describes), Feed,
>     or JacksonRepresentation; and Event is a domain-level interface
>     with some associated mechanisms for converting from a Form, Entry,
>     or JacksonRepresentation to an Event instance and from an Event
>     instance to a TemplateRepresentation, Entry, or JacksonRepresentation.
>
>     I want to implement CalendarResource on the server side with:
>
>     public class CalendarServerResource extends ServerResource
>     implements CalendarResource {
>         public Calendar getCalendar() {
>             Calendar calendar = lookupCalendar(getRequest()); //
>     actual domain logic in here
>             return calendar;
>         }
>
>         public Event addEvent(Event event) {
>             Calendar calendar = lookupCalendar(getRequest());
>             Event event = addNewEventToCalendar(calendar, event); //
>     actual domain logic in here
>             return event;
>         }
>     }
>
>     And I'd like to be able to make and use client proxies like this:
>
>         CalendarResource calendarResource = ClientResource.create(uri,
>     CalendarResource.class);
>         Calendar calendar = calendarResource.getCalendar();
>         // ...
>         event = calendarResource.addEvent(event);
>
>     I have these questions:
>
>     Can I create my own ConverterHelpers for Freemarker, Atom, and
>     Jackson that have access to the conversion mechanisms mentioned
>     above, and add them to the Engine on the server side (and, where
>     supported, on the client side) using this code:
>
>         List<ConverterHelper> converters =
>     Engine.getInstance().getRegisteredConverters();
>         converters.add(new MyFreemarkerConverter());
>         converters.add(new MyAtomConverter());
>         converters.add(new MyJsonConverter());
>
>     Can I make my converters outscore the ones that come with the
>     Freemarker, Atom, and Jackson extensions by returning scores of
>     greater than 1.0?
>
>     Is there (or will there be) a better way to replace or overrule
>     the converter logic that comes packaged with the extensions with
>     my own logic?
>
>     Am I asking for too much? Should I give up and just use
>     Representations in all my annotated signatures, and put the
>     conversion logic in those methods, like this?
>
>     public interface CalendarResource {
>         @Get("html") Representation asHtml();
>         @Get("atom") Representation asAtom();
>         @Get("json") Representation asJson();
>         @Post("form:html") Representation addEventForm(Representation
>     eventForm);
>         @Post("atom") Representation addEventEntry(Representation
>     eventEntry);
>         @Post("json") Representation addEventJson(Representation
>     eventJson);
>     }
>
>     public class CalendarServerResource extends ServerResource
>     implements CalendarResource {
>         public Representation asHtml() {
>             return new TemplateRepresentation(...,
>     lookupCalendar(getRequest()), ...);
>         }
>         public Representation asAtom() { return new Feed(...); }
>         public Representation asJson() { return new
>     JacksonRepresentation(...); }
>         public Representation addEventForm(Representation eventForm) {
>     ... }
>         public Representation addEventEntry(Representation eventEntry)
>     { ... }
>         public Representation addEventJson(Representation eventJson) {
>     ... }
>     }
>
>     That's a lot of verbosity that would have to be repeated for each
>     one of my resource classes.
>
>     --tim
>
>

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2673876

Reply via email to