Re: Removing _at_UnmatchedPath

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Mon, 09 Jul 2007 14:42:47 +0200

Hi Bill,

Bill de hOra wrote:
> I prefer the new version for the API. However, if I read the uri
> templates draft right, I think greedy is the default - it doesn't
> support any operators/quantifiers but says any legal URI tokens can go
> inside the brackets.

Interesting when used for matching as opposed to construction i read it
as unspecified whether templates were greedy or not (or reluctant or not).

As you point out below it is ambiguous when there is more than one
template value per template or more than one template to be matched
without some specification on the ordering.

> So if I had (assuming greedy)
> @UriTemplate(value="folders/{path}")
> I'll match this - "folders/*". if I added another tenmplate pattern
> @UriTemplate(value="folders/{path}")
> @UriTemplate(value="folders/{path}/{subpath}")
> then "folders/*" could go to either; ie, what gets called depends on the
> order they're invoked - unless we're saying implementations are expected
> to resolve this.

We currently specify an order for template matching as follows:

   Primary key: number of template values
Secondary key: number of non-template characters

It is specified in terms of regexes in the latest draft of the spec, see
section 2.6 of [1].

Each template value is converted to a reluctant regex so that given the
template "folders/{path}/{subpath}" and a URI path "folders/a/b", then
path="a" and not "a/b".

Also a "(/.*?)" is append if there are sub-resources specified,
otherwise it is (/?). This represents the last matching group of
right-hand-path for further matching. So by default are 'neutering' the
greediness :-)

For example, the URI template "folders/{path}/{subpath}" would be
converted to the following regex:


The idea behind greedy was to 'un-neuter' regex, and remove the "(/.*?)".

> With a greedy operator in play, the call order could be changed as well,
> assuming we did this
> @UriTemplate(value="folders/{path}")
> @UriTemplate(value="folders/{path}/{subpath}
> and this
> @UriTemplate(value="folders/{path}" greedy=true)
> @UriTemplate(value="folders/{path}/{subpath}
> what gets called changes subject to implementation details.

Good point. Given your examples and the currently specified ordering:

1) "folders/{path}/{subpath}"

2) "folders/{path}"

   "folders/a" matches 2
   "folders/a/b" matches 1
   "folders/a/b/c" matches 1 with r.h.p of "/c" if has sub-resources
      otherwise no match

If we add greedy to the mix but keep the same ordering:

1.g) "folders/{path}/{subpath}"

2.g) "folders/{path}" greedy=true"

   "folders/a" matches 2.g
   "folders/a/b" matches 1.g
   "folders/a/b/c" matches 1.g with r.h.p of "/c" if has sub-resources
      otherwise matches 2.g with path="a/b/c"

If we specify greedy as the primary key: "folders/{path}" greedy=true" "folders/{path}/{subpath}"

   "folders/a", "folders/a/b" and "folders/a/b/c" matche

The use-case behind greedy was to allow a sub-resource to consume all
the right-hand-path while allowing other sub-resources to continue using
the current algorithm. For example, in the RESTful Web Services book it
talks about a Bookmark example and Leonard wants to have the bookmark
URI as part of the actual URI rather than an MD5 hash of it. So we could do:

public class Bookmarks {
    @UriTemplate(value="uri/{uri}", greedy=true)
    Bookmark getBookmark(@UriParam("uri") URI uri) { ... }

Currently we do:

public class Bookmarks {
    Bookmark getBookmark(@UnmatchedPath String uri) { ... }

which seems hacky.

> I think this means a) order of template evaluation matters,


> b) we need
> test cases.

Yes, the RI impl has some unit tests but they are not exhaustive and
could do a lot be better here. Note that EG members can play with this
(not the greedy option) as well by writing a POJOs using the stable
stable RI [2].



| ? + ? = To question
    Paul Sandoz