dev@jsr311.java.net

Re: JSR311: Issue 1 - Proposal for new conneg APIs

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Fri, 12 Oct 2007 09:52:30 -0400

On Oct 11, 2007, at 8:43 PM, Ryan McDonough wrote:
>
> The example you've provided seems a bit isolated and I'm having a
> bit of
> difficulty understanding how it would work in practice. Assuming the
> following code:
>
> @UriTemplate("/people/{id}")
> class PersonResource {
>
> public Person getPersonAsXmlEn(@UriParam("id) String id) {...}
>
> public Person getPersonAsXmlFr(@UriParam("id) String id) {...}
>
> public Person getPersonAsJsonEn(@UriParam("id) String id) {...}
>
> public Person getPersonAsJsonFr(@UriParam("id) String id) {...}
> }
>
You could either collapse those 4 methods into one:

@UriTemplate("/people/{id}")
class PersonResource {

   List<RepresentationVariant> variants;
   @HttpContext RequestHelper req;

   public PersonResource() {
     RepresentationVariant.ListBuilder b =
RepresentationVariant.ListBuilder.newInstance();
     b.languages("en", "fr");
     variants = b.add().build();
   }

   @HttpMethod
   public Response getPerson(@UriParam("id) String id) {
     // check we have a representation that is acceptable
     RepresentationVariant v = req.narrowChoices(variants);
     if (r==null)
       return Response.Builder.notAcceptable(variants);

     // have a representation
     return Response.Builder.representation(getPerson(v), v);
   }

   private Person getPerson(RepresentationVariant v) {
     if (v.getLanguage().equals("fr")) {...}
     else {...}
   }
}

or you could use @ProduceMime as follows:

@UriTemplate("/people/{id}")
class PersonResource {

   List<RepresentationVariant> variants;
   @HttpContext RequestHelper req;

   public PersonResource() {
     RepresentationVariant.ListBuilder b =
RepresentationVariant.ListBuilder.newInstance();
     b.languages("en", "fr");
     variants = b.add().build();
   }

   @HttpMethod
   @ProduceMime("application/xml")
   public Response getPersonXml(@UriParam("id) String id) {
     // check we have a representation that is acceptable
     RepresentationVariant v = req.narrowChoices(variants);
     if (r==null)
       return Response.Builder.notAcceptable(variants);

     // have a representation
     return Response.Builder.representation(getPerson(v.getLanguage
()), v);
   }

   @HttpMethod
   @ProduceMime("application/json")
   public Response getPersonJson(@UriParam("id) String id) {
     // check we have a representation that is acceptable
     RepresentationVariant v = req.narrowChoices(variants);
     if (r==null)
       return Response.Builder.notAcceptable(variants);

     // have a representation
     return Response.Builder.representation(getPerson(v.getLanguage
()), v);
   }

   private Person getPerson(String language) {
     if (language.equals("fr")) {...}
     else {...}
   }
}

> On additional item: we should be able to specify the Q value of the
> media
> type and also also sort the the media types by this value. If the
> client is
> sending an accept header with a q value, we should be including
> that in the
> selection process.
>
Right. I should have made it clear that the narrowChoices method
selects the variant that most closely matches the accept* headers in
the request.

We could also add a q value to the ProduceMime and make order of the
variants significant if we want to support server side "tie-breaking"
where two representations are equally desirable from the client
perspective.

Marc.

> On 10/11/07, Marc Hadley <Marc.Hadley_at_sun.com> wrote:
>>
>> Issue 1[1] asks about additional support for content negotiation.
>> I've uploaded a sketch of some new APIs to aid with content
>> negotiation beyond the media type support we currently have:
>>
>> https://jsr311.dev.java.net/nonav/sketches/conneg/index.html
>>
>> RepresentationVariant represents an available combination of media
>> type, language, charset and encoding. Its ListBuilder static inner
>> class is a builder that makes creation of a list of variants
>> straightforward.
>>
>> RequestHelper would replace the existing PreconditionEvaluator and
>> adds support for conneg to the existing precondition methods. I also
>> added a notAcceptable method to Response.Builder and an extra
>> representation method to directly support RepresentationVariant.
>>
>> The idea is that you use RepresentationVariant.ListBuilder to create
>> a list of variants that describe all of the possible representations
>> that can be produced. You then use RequestHelper.narrowChoices to
>> select a variant that matches the preferences in the request. Once
>> you've narrowed the choices you can then proceed to evaluate
>> preconditions for the chosen variant.
>>
>> Here's an example of how it could be used.
>>
>> @HttpContext RequestHelper req;
>>
>> @HttpMethod
>> public Response getFoo() {
>> RepresentationVariant.ListBuilder b =
>> RepresentationVariant.ListBuilder.newInstance();
>> b.mediaTypes("application.xml", "application.json");
>> b.languages("en", "fr");
>> List<RepresentationVariant> variants = b.add().build();
>>
>> // check we have a representation that is acceptable
>> RepresentationVariant v = req.narrowChoices(variants);
>> if (r==null)
>> return Response.Builder.notAcceptable(variants);
>>
>> // check preconditions
>> Response r = req.evaluatePreconditions(getTag(v), v);
>> if (r!=null)
>> return r;
>>
>> // have a representation and preconditions were met
>> return Response.Builder.representation(getEntity(v), v);
>> }
>>
>> I can see the above pattern being repeated over and over and I'm
>> wondering if there's some way we can automate it to make it more
>> convenient - perhaps via a callback interface or something. Either
>> way I suspect we need the lower level approach above for maximum
>> flexibility.
>>
>> BTW, RepresentationVariant is somewhat similar to the Variant class
>> in the RESTlet API. The main difference is that a variant in RESTlet
>> includes all the representation metadata whereas
>> RepresentationVariant only includes metadata used for conneg.
>>
>> Let me know what you think.
>>
>> Marc.
>>
>> [1] https://jsr311.dev.java.net/issues/show_bug.cgi?id=1
>> [2] http://www.restlet.org/documentation/1.0/api/
>>
>> ---
>> Marc Hadley <marc.hadley at sun.com>
>> CTO Office, Sun Microsystems.
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_jsr311.dev.java.net
>> For additional commands, e-mail: dev-help_at_jsr311.dev.java.net
>>
>>
>
>
> --
> Ryan J. McDonough
> http://www.damnhandy.com

---
Marc Hadley <marc.hadley at sun.com>
CTO Office, Sun Microsystems.