Friday Aug 31, 2007

Building URIs

At first sight building URIs using Java SE appears deceptively simple. Beware!

Say for example i have an instance of java.net.URI, baseUri, that is the following:

"http://localhost:8080/base"

and i want to append the following relative path to that URI:

"a:b;param=matrix/hello world"

such that i would like my URI to be:

"http://localhost:8080/base/a:b;param=matrix/hello%20world"

It is not possible to create a URI with the relative path like this:

new URI("a:b;param=matrix/hello world");
new URI(null, null, "a:b;param=matrix/hello world", null);

because, in the first case, there is an illegal character, the space character in "hello world", and therefore resorting to string concatenation will also result in an invalid URI:

baseUri.toString() + '/' + "a:b;param=matrix/hello world"

Further more, for both cases java.net.URI correctly assumes the "a:" is a scheme (although it gets very confused about the rest of the URI!).

We could do this:

uri = baseUri.resolve(
    new URI(null, null, "/a:b;param=matrix/hello world", null);

but because a '/' is prefixed to the path we will loose the path of baseUri. [Update: the path of baseUri will be lost regardless of prefixing because it does not end with a '/']

The only reliable way of doing this using java.net.URI is if a new URI is created from the components of baseUri:

URI u = new URI(base.getScheme(),
    base.getUserInfo(), base.getHost(), base.getPort(),
    base.getPath() + "/a:b;param=matrix/hello world",
    base.getQuery(), base.getScheme());

What a PITA! If the baseUri was "http://localhost:8080/base/" then i would end up with two '/' in between the base path and the appended path so in general i should ensure that only a single '/' occurs.

This is why the JSR-311 expert group is specifying the UriBuilder class as part of JAX-RS so you can do this:

UriBuilder.fromUri(baseUri).
    path("a:b;param=matrix/hello world").build();

or if i would like to be explicit about the matrix parameters:

UriBuilder.fromUri(baseUri).
    path("a:b").
    matrixParam("param", "matrix").
    path("hello world").build();

to create the desired URI intuitively and safely.

UriBuilder also supports URI templates so i could do:

UriBuilder.fromUri(baseUri).
    path("a:{p1}").
    matrixParam("param", "{p2}").
    path("hello {p3}").build("b", "matrix", "world");

You can find an implementation of UriBuilder in the latest build of Jersey. however, since we have yet to pull in the latest 311 API into Jersey i have made a clone you can find it at com.sun.ws.rest.api.core.UriBuilder if you want to have a play.

Tuesday Nov 14, 2006

URI templates

The URI template IETF draft specifies a very simple mechanism for representing embedded template variables in a URI. A URI template is transformed into a URI by subsituting the embedded template variables.

For example the following URI template:

http://employees/{id}

can be transformed to the following URI:

http://employees/paul

where id=paul

That is essentially it. Simple and very useful for machine processing! No regular expressions, no complex matching choices.

Initially i tending to think of just URI templates being transformed to URIs. Flipping things the other around, a URI can also be matched against one or more URI templates. 

Given the simplicity of URI templates it is really easy ascertain whether a URI matches a URI template by doing some pre-processing of the URI template using regular expressions.

1) search for patterns in the URI template that match the expression{([\\w-._~]+?)}

2) replace all matches in 1) with the expression (.\*?)

3) escape as appropriate all characters in 2) that are not regular expression characters

and what you end up with at 3) is a string that is regular expression that can be used to match against URIs. Essentially the URI template is transformed into a regular expression. In addition to matching against a URI what you get for free is the capturing of template variables in the URI template and corresponding strings in a matching URI (because group matching is used)!

A nice elegant solution that is only possible because URI templates are simple.
About

sandoz

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today