users@jax-rs-spec.java.net

[jax-rs-spec users] [jsr339-experts] Re: Using "anchor" attribute of "Link" header (was: Improving Hypermedia Support)

From: Santiago Pericas-Geertsen <Santiago.PericasGeertsen_at_oracle.com>
Date: Wed, 21 Dec 2011 14:15:49 -0500

Hi Markus,

> sorry for not being responsive for weeks, but we have completely renewed our infrastructure in the past weeks which bound all my time. So here is my proposal for improvements in Hypermedia Support. It is basing on yours found at http://java.net/projects/jax-rs-spec/pages/HypermediaExample, so I will not describe the business scenario again but just post a proposed alternative representation of the links.

 No problem, welcome back.

>
> Proposed Change #1: Representations and Links
> In contrast to the referenced hypermedia example, this proposal omits the use of a template but instead lists ready-to-use links for each machine. The benefit is that a client can use this links even if the actual entity's syntax would be unknown (i. e. the client cannot parse the machine IDs from the entitiy) or would not contain the list of machines at all (e. g. if it is a video stream showing the actual server rack, instead of a JSON description of the rack's state). Also the client is not forced to do any additional work like parsing and applying templates, but just can follow a static link. The original example is unable to deal with this problems. As JAX-RS should be as flexible as http itsels is, and as binary media more and more is used (like videos and audios), JAX-RS should be able to work without content parsing.
>
> Content-Type:application/json
> Link: </cluster>; produces="application/json"; method="GET"; rel="self"
> </cluster/offliner>; produces="application/json"; method="POST"; rel="offliner"
> </cluster/machine/alpha>; produces="application/json"; method="GET"; rel="item"
> </cluster/machine/beta>; produces="application/json"; method="GET"; rel="item"
> </cluster/machine/gamma>; produces="application/json"; method="GET"; rel="item"
>
> ...

 I have no objections with this proposal. I don't think there's anything in the current API that would prevent you from doing this. You could use Link.fromResourceMethod() and then call build() on the returned LinkBuilder. This should work and should be possible to create an invocation from a link using Client.invocation(), if so desired. There's also a suggestion to marshal/unmarshal links in representations for those cases in which that makes sense. Please check latest sources.

> Actually I think it is not an either-or decision, but I propose that the rendering of the links is by default non-templated, but can be optionally switched to templated rendering using an annotation.
>
> Please note that this representation is not my final proposal, but the actual rendering should use the "anchor" attribute instead. The explanation is dependent of the next change, so please read on to understand how the idea develops!
> Proposed Change #2: Separating navigation-target from transition-target
> In analogy to a human-readable web site that shows a list of machines's states and one pair of "startup" / "shutdown" buttons besides each machine, one might want to contain such "non-self" transition links in the cluster's representation (not in the machine's representation) to separate the navigation-target (= next entity to get) from the transition-target (= transitioned entity). (Side note: As a nice side effect, when using XML instead of JSON this would apparently allow to simply create the fully functional human-readable HTML page by just applying some XSLT ontop of our JAX-RS service, BTW).
>
> Content-Type:application/json
> Link: </cluster>; produces="application/json"; method="GET"; rel="self"
> </cluster/offliner>; produces="application/json"; method="POST"; rel="offliner"
> </cluster/machine/alpha>; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/alpha/stopper"; produces="application/json"; method="POST"; rel="stopper"
> </cluster/machine/beta>; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/beta/starter"; produces="application/json"; method="POST"; rel="starter"
> </cluster/machine/gamma>; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/gamma/stopper"; produces="application/json"; method="POST"; rel="stopper"

 This proposal I'm not thrilled about. I find this use of the anchor non-intuitive (as well as more difficult to process), even more so than the link templates on the wiki. Again, the current API will allow you to create such a link, but it won't be processable by Client.invocation() --yet you could still use Client.target() and build your request from there.

 So -1 on #2, but I'm curious what other experts think about it?

-- Santiago

>
> The above lines represent a cluster that has three machines: Alpha and gamma are online, so there is only a offline contained. Beta is offline, so an onliner is contained. In fact, we could just add more rel's for each machine to allow more actions to be done on the "front page" of our cluster: like "restart machine" as shown below:
>
> Content-Type:application/json
> Link: </cluster>; produces="application/json"; method="GET"; rel="self"
> </cluster/offliner>; produces="application/json"; method="POST"; rel="offliner"
> </cluster/machine/alpha>; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/alpha/stopper"; produces="application/json"; method="POST"; rel="stopper"
> </cluster>; anchor="machine/alpha/restarter"; produces="application/json"; method="POST"; rel="restarter"
> </cluster/machine/beta>; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/beta/starter"; produces="application/json"; method="POST"; rel="starter"
> </cluster/machine/gamma>; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/gamma/stopper"; produces="application/json"; method="POST"; rel="stopper"
> </cluster>; anchor="machine/gamma/restarter"; produces="application/json"; method="POST"; rel="restarter"
>
> Alpha and gamma are running, so can be restarted. Beta is down, so there is still only the starter.
>
> Following such a "non-self" transition link would startup / shutdown one single machine but produce the cluster (!) view again (not navigating to that machine). To reach the separation of transitioned object and navigation target, the above lines show that the transitioned object is rendered using the "anchor" as attribute described by RFC 5988. So, the invoked URI still is naming the cluster's URI, not the machine's.
>
> The last example shows that actually we could *always* use the anchor, even with no additional transitions methods. Even if we just want to describe the list of machines in the cluster:
>
> Content-Type:application/json
> Link: </cluster>; produces="application/json"; method="GET"; rel="self"
> </cluster/offliner>; produces="application/json"; method="POST"; rel="offliner"
> </cluster>; anchor="machine/alpha"; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/alpha/stopper"; produces="application/json"; method="POST"; rel="stopper"
> </cluster>; anchor="machine/alpha/restarter"; produces="application/json"; method="POST"; rel="restarter"
> </cluster>; anchor="machine/beta"; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/beta/starter"; produces="application/json"; method="POST"; rel="starter"
> </cluster>; anchor="machine/gamma"; produces="application/json"; method="GET"; rel="item"
> </cluster>; anchor="machine/gamma/stopper"; produces="application/json"; method="POST"; rel="stopper"
> </cluster>; anchor="machine/gamma/restarter"; produces="application/json"; method="POST"; rel="restarter"
>
> While it enlarges the header by a few bytes, it expresses more clearly the fact that there is not necesserily any difference in rendering transitions from navigations as Link headers, so the client does not need to handle them differently in any way -- just as a browser being unaware of the fact whether a button will transition state or navigate to a different resource (or both). The sole logic (whether it is a transition or a navigation) is completely under control of the server, so the client can be unaware of the application's business logic (or even rather generic like a browser).
>
> In fact, these lines above are my actual proposal how to render item lists (see change #1)!
>
> Regards
> Markus
>
> From: Santiago Pericas-Geertsen [mailto:Santiago.PericasGeertsen_at_oracle.com]
> Sent: Mittwoch, 16. November 2011 00:22
> To: jsr339-experts_at_jax-rs-spec.java.net
> Subject: [jsr339-experts] Re: [jax-rs-spec users] Re: Re: Re: Re: Re: Improving Hypermedia Support
>
> Markus,
>
> Inlined
>
> your proposal expects the client software to know the literals "onliner" and "offliner" and their actual meaning. No machine can ever understand that this will take machines offline. So at least these two words and their actual intention must be known to the programmer of the client.
>
> Loose coupling does not mean no coupling. All solutions would have some degree of coupling. However, a solution in which the client needs to understand the structure of all the links out-of-band simply does not satisfy the most basic requirement of hypermedia IMO.
>
>
> Also, he must know definitively how to apply the "item" template. As he must know that, I cannot see what is more "loosely" and more "hypermedia" than just sending the list of links directly? Just do not see the difference here wrt to "hypermedia" and "coupling". So I do not agree to your point here. What your proposal does better than mine is supporting "bad" design, as I described later. With my proposal, there is less chance to do "bad" design. And I think an API should prevent "bad" design if any possible.
>
> Unless you show me a completely fleshed out example (like the one in the wiki) using "your proposal", I simply cannot comment on whether mine is bad and yours is good.
>
>
> Please also not that my prosposal was not (a) and (b) as you cited, but using the "anchor" attribute, which, BTW, I actually understand as the intended solution to exactly this problem (separating target and method without the need to invent another means of tempting).
>
> As I said above, show us a complete example using "anchors" including the Client code and I (and perhaps others on this alias) will be happy to evaluate it.
>
> -- Santiago
>
>
>
> From: Santiago Pericas-Geertsen [mailto:Santiago.PericasGeertsen_at_oracle.com]
> Sent: Montag, 14. November 2011 16:06
> To: jsr339-experts_at_jax-rs-spec.java.net
> Subject: [jsr339-experts] Re: [jax-rs-spec users] Re: Re: Re: Re: Improving Hypermedia Support
>
>
> On Nov 12, 2011, at 9:53 AM, Markus KARG wrote:
>
>
>
> But, as a machine can neither guess nor understand tooltips, it just could pick one of two strategies: (a) It is explicitly written to orchestrate this particular service, so it just knows the syntax of the URI (I mean, if I write an eBay client I obviously know the API, which contains the particular URI syntax).
>
> This strategy seems to be against hypermedia and loose coupling. Ideally, we want clients to only know a single URI and then be dynamically informed of the rest (as these may change even from run to run). I'm not saying that URI templates is the best solution, but it's certainly better than clients needing to know the exact URI structure to follow a link. Templates only assume that clients know how to identify a machine and can call a method to instantiate the template.
>
> One doesn't need a template then (you only need a template, if you *do not* know the syntax and want some background magic to handle this).
>
> That's precisely the point, not knowing the syntax. If I know the exact syntax, then there's no point of including these links in the representations as they are already known to the client.
>
> (a) Polymorhy: Maybe there are "machine" instances that need to have differnent URIs! You would need to provide a different template, but how to?
>
> (b) Binary content: Maybe the machine "name" is not (or not easily) parseable from the content! How would your client software guess the machine name to pass into the template?
>
> Agree, it isn't perfect. But I can't agree that the strategy you outline above is better.
>
>
>
> But, actually, if I were you, I would provide a different model in fact to solve your task: Not sending all the transition links for all the machines inside of the cluster document, but let the cluster document contain only the machines "self" URIs
>
> This is certainly an option. In fact, given that what has been proposed are all API calls, you could design your application this way --this is the reason why I don't want to "bake" anything in annotations and framework logic.
>
> -- Santiago
>
>
>
> (so you only learn the list of machines in the first step -- maybe you neither want to know the state nor want to shut down a machine, so you don't really lose anything in the first step). If a link is needed for a machine (since you then want to know the status or want to shutdown one machine), I can request the machine's representation in a second roundtrip and find it's transition links inside that document. This imposes one more http request, but it provides self-controlled machines, which in fact solves not only the templates problem, the polymorphy problem and the binary content problem, but it is also more scalable as for lots of machines you would only ask for as much state as you can see on the screen (not requesting machines states you won't read ever), and it is much more object oriented: If I want to shut down a machine, I press it's power switch. I do not press a swith on a different device. :-)
>
> Regards
> Markus
>
> From: Santiago Pericas-Geertsen [mailto:Santiago.PericasGeertsen_at_oracle.com]
> Sent: Dienstag, 8. November 2011 20:09
> To: jsr339-experts_at_jax-rs-spec.java.net
> Subject: [jsr339-experts] Re: [jax-rs-spec users] Re: Re: Re: Re: Improving Hypermedia Support
>
>
> On Nov 8, 2011, at 12:39 PM, Markus KARG wrote:
>
>
>
>
> Can you please post the WIKI link again? Thanks.
>
> Here it is: http://java.net/projects/jax-rs-spec/pages/HypermediaExample
>
> -- Santiago
>
>
>
>
>
> From: Santiago Pericas-Geertsen [mailto:Santiago.PericasGeertsen_at_oracle.com]
> Sent: Montag, 7. November 2011 19:11
> To: jsr339-experts_at_jax-rs-spec.java.net
> Subject: [jsr339-experts] Re: [jax-rs-spec users] Re: Re: Re: Improving Hypermedia Support
>
> Hi Markus,
>
> Could you apply this to the example we have on the wiki? In particular, given a collection item Y, how can I get the link to Y? I may want to start machine A and stop machine B; so getting the links to all the machines in the cluster is not enough.
>
> -- Santiago
>
> On Nov 6, 2011, at 8:45 AM, Markus KARG wrote:
>
>
>
>
>
> Santiago,
>
> this way:
>
> Link: <absolute-uri-A1>; rel="name-of-collection-A"
> Link: <absolute-uri-A2>; rel="name-of-collection-A"
> Link: <absolute-uri-B1>; rel="name-of-collection-B"
> Link: <absolute-uri-B2>; rel="name-of-collection-B"
>
> Here you have four absolute URIs. A1 and A2 are part of collection A, B1 and B2 are part of collection B.
>
> If the client wants to visit all resources references by collection B, it would just have to invoke A1 and A2, identified via collection A.
>
> An alternative way would be using the anchor attribute to identify the resource as a fragment of the source resource (e. g. anchor="#name-of-collection-A").
>
> A third option would be a link-extension like "Link: <absolute-uri>; collection="name-of-collection".
>
> Where do you see a problem? No need for neither templates nor client side application logic.
>
> Regards
> Markus
>
> From: Santiago Pericas-Geertsen [mailto:Santiago.PericasGeertsen_at_oracle.com]
> Sent: Dienstag, 1. November 2011 20:17
> To: jsr339-experts_at_jax-rs-spec.java.net
> Subject: [jsr339-experts] Re: [jax-rs-spec users] Re: Re: Improving Hypermedia Support
>
> * I do not understand the problem with the collection. Why not sending just several URIs with the same relation in that case (one for each item of the collection)?
>
> As link headers? How would you know which one corresponds to which item in the collection? There's no ordering for link headers.
>
> -- Santiago
>
>
>
>
>
>
>
>
>
>
>