dev@jsr311.java.net

Re: Issue 1: Adding additional conneg metadata to _at_Produce/ConsumeXXX

From: Dhanji R. Prasanna <dhanji_at_gmail.com>
Date: Sun, 8 Jul 2007 22:06:27 +1000

I prefer #2 as well but not terribly happy about the AcceptabilityEvaluator
(seems like an unnecessary dep on a framework artifact).
How about if we flip the apis:

public class Widget {
    @Accepts public boolean canAccept(@Lang lang, @MediaType String type) {
... }

    @HttpMethod public Response get(@Lang String lang, @MediaType String
type) {
          return Response.Builder.entity(widget.getStream(lang, type)
).build();
     }
}

This lets it be dynamic as well as reducing any large set of artifacts or
dependency on a framework API.

I haven't thought about how it compares to the list of Variants case
thoroughly... comments?

Dhanji.

On 7/4/07, Marc Hadley <Marc.Hadley_at_sun.com> wrote:
>
> Trying to weigh the possible approaches for supporting content
> negotiation based on dynamic metadata, I came up with the example of
> a set of widgets that are available in few different media types and
> languages but the availability differs for each widget (i.e. some are
> available in one language, some in two, some have html, some just a
> jpeg).
>
> The first approach is my interpretation of what Jerome is suggesting
> (Jerome if this isn't what you meant then please correct - I looked
> at the Variant class in Restlet but I might have missunderstood its
> use):
>
> @UriTemplate("widgets/{widget}")
> public class Widget {
>
> WidgetEntity widget;
>
> public Widget(@UriParam("widget") String widgetId) {
> widget = findWidgetEntity(widgetId);
> }
>
> @Variants
> List<Variant> getVariants(@HttpMethod String method) {
> List<Variant> variants = new ArrayList<Variant>();
> for (MediaType type: widget.getTypes()) {
> for (String lang: widget.getLanguages()) {
> Variant v = new Variant(type, lang);
> variants.add(v);
> }
> }
> return widget.getTypes();
> }
>
> @HttpMethod
> public InputStream getWidget(@HttpContext Variant v) {
> return widget.getStream(v.type, v.lang);
> }
> }
>
> In the above, the runtime:
>
> (i) calls the constructor,
> (ii) calls the getVariants method to obtain a list of possible
> variants for the current request (I added a @HttpMethod since it
> seems possible that you'd want to return different things depending
> on the method though that isn't shown above, you could also use any
> of the other annotations that can be used on a resource method).
> (iii) perform the conneg matching and either returns an appropriate
> error if there's no acceptable variant or
> (iv) calls the getWidget method passing in the selected variant (note
> there's no need to set the negotiated metadata since the runtime can
> do that automatically. If an application wanted to add metadata then
> it would need to return Response and create one from the passed in
> Variant.
>
> An alternate approach is my interpretation of what Paul is suggesting:
>
> @UriTemplate("widgets/{widget}")
> public class Widget {
>
> WidgetEntity widget;
> @HttpContext AcceptabilityEvaluator ae;
>
> public Widget(@UriParam("widget") String widgetId) {
> widget = findWidgetEntity(widgetId);
> }
>
> @HttpMethod
> public Response getWidget() {
> Response.Builder rb = ae.evaluate(widget.getTypes(),
> widget.getLanguages());
> if (rb.getStatus() < 300)
> rb.entity(widget.getStream(rb.getType(), rb.getLanguage()));
> return rb.build();
> }
> }
>
> In the above, the runtime calls the constructor followed by the
> getWidget method and the application uses the
> "AcceptabilityEvaluator" to determine if there is an acceptable
> response or not. The ae.evaluate method returns an appropriate error
> response if there's no acceptable combination or a prefilled OK
> response if there is. The application adds an entity if required and
> return the response.
>
> Personally I prefer the second approach for the following reasons:
>
> - There's no need to build a list of variants every time
> - The context of the request is implicit since the conneg occurs
> directly in the method that will service the request
> - The application gets a chance to tweak or override the default
> error response when no matching variant is found
>
> Thoughts, comments ?
> Marc.
>
>
> On Jun 30, 2007, at 3:02 AM, Jerome Louvel wrote:
>
> >
> > Hi Mark,
> >
> >>> It seems that you mix the ability to expose dynamic representation
> >>> metadata
> >>> and the content negotiation algorithm (interpreting the Accept*
> >>> headers).
> >>>
> >> I don't think its really a matter of mixing them, rather the runtime
> >> hands off to the application when there isn't sufficient static
> >> information to make a determination.
> >
> > The conneg algo doesn't need to rely on static metadata only. It could
> > perfectly work on dynamic metadata too (like we do in Restlet).
> >
> >>> For the first one, we should just have annotation ways to
> >> expose those metadata, and for some rare cases rely on an
> >> "EntityProvider" service.
> >>>
> >> I don't think EntityProvider is related to dynamic metadata. You can
> >> associate some static metadata with one (ConsumeMime, ProduceMime)
> >> but by the time an EntityProvider enters the process all of the
> >> conneg will have already taken place.
> >
> > Why does it have to be processed this way? If you design the API for a
> > stricter separation between the resources/representations and
> > conneg algo,
> > this perfectly possible IMHO.
> >
> >> For "annotation ways to expose those metadata" do you mean something
> >> like an annotated method that would return, say, the list of
> >> available languages ?
> >
> > Yes, and not only for languages. The notion of variant (consistent
> > set of
> > metadata) is important too.
> >
> > Best regards,
> > Jerome
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: dev-unsubscribe_at_jsr311.dev.java.net
> > For additional commands, e-mail: dev-help_at_jsr311.dev.java.net
> >
>
> ---
> 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
>
>