dev@jersey.java.net

RE: [Jersey][WebDAV] Fluent API of WebDavBuilder

From: Markus KARG <markus.karg_at_gmx.net>
Date: Tue, 27 Jan 2009 17:49:43 +0100

Craig,

 

thanks for your comments and helping us in this issue. Yes, I share your
opinion about the need for a client side WebDAV API, but on the other hand,
I actually want to wait with that -- possibly Paul and Marc can be convinced
to add JAX-RS client API in JAX-RS 2.0...? :-)

 

Have Fun

Markus

 

From: Craig.McClanahan_at_Sun.COM [mailto:Craig.McClanahan_at_Sun.COM]
Sent: Montag, 26. Januar 2009 22:07
To: dev_at_jersey.dev.java.net
Subject: Re: [Jersey][WebDAV] Fluent API of WebDavBuilder

 

Markus KARG wrote:

Craig,
 
thank you so much for your comments. More inlined.
 
  

For example, how to add multiple instances of the same class to a
      

root
    

element?
 
return new MultiStatus(new Result(x), new Result(y)); (non-fluent)
 
return WebDavBuilder.multiStatus().result(x).result(y); ?
 
return WebDavBuilder.multiStatus(new Result(x), new Result(y)); ?
 
      

Technically, either of these can work.
    

 
Sure. But none of the two fluent variants is easier to write or read than
the non-fluent variant, so what does the user win? A longer code and the
confusion how to add something to the result, obviously!
 
  

Personally, I find the second alternative shown above to be much nicer ...
not only is it fewer characters to type, it probably saves me having to
import Result or understand anything about its API.



One important principle illustrated in my example above (and sometimes
violated in the JAX-RS and Jersey instances of the pattern) is that the
"this" object you are building up should not change as the expression
gets evaluated. In your first pattern, I'm assuming that the result(x)
and result(y) methods return the MultiStatus instance you are adding
to,
so that would be obeying the pattern. However, what if result() was
itself a builder that let you construct a Result? That would be
confusing to the user, because the "." connectors in the expression
after this would refer to that Result, and you could never get back to
adding things to the MultiStatus.
    

 
Ok, this will work for HelloWorld, but to tell the whole truth about WebDAV
and demonstrate the dilemma of a fluent API: A valid WebDAV Result is not
constructed by just code and message (Result(int, String)) but a lot of
other objects which again have a lot of references... This code line shows
what currently is typical for WebDAV and must be replaced by a fluent API:
 
-- SNIP --
 
// Excerpt from webdav-addressbook sample
 
final Response folder = new Response(new HRef(uriInfo.getRequestUri()),
null, null, null, new PropStat(new Prop(new MicrosoftRedirectorPatch2(), new
DisplayName("My Collection"), new CreationDate(new Date()), new
GetLastModified(new Date()), COLLECTION), new Status(OK)));
 
if (depth.equals(DEPTH_0))
       return new MultiStatus(folder);
 
final Collection<Response> responses = new
LinkedList<Response>(Collections.singletonList(folder));
for (final Contact c : (List<Contact>)
this.em().createNamedQuery("ListContacts").getResultList())
       responses.add(new Response(new
HRef(uriInfo.getAbsolutePathBuilder().path(String.format("%s.adr",
c.getMatchCode())).build()), null, null, null, new PropStat(new Prop(new
MicrosoftRedirectorPatch2(), new DisplayName(String.format("%s %s",
c.getLastName(), c.getFirstName())), new CreationDate(c.getCreationDate()),
new GetLastModified(c.getLastModified()), new GetContentLength(0), new
GetContentType(ADDRESS_MIME)), new Status(OK))));
 
return new MultiStatus(responses.toArray(new Response[0]));
 
-- SNIP --
 
This is NOT an overly complex example -- it demonstrates the MINIMUM that is
needed to construct a valid MultiStatus instance. Have a look at the
contrib/webdav source and you'll notice that we're talking about dozens of
XML elements that must be combined only in the valid schema (and the builder
shall enforce and support that).
 
  

Now you know why I care so much about a nice client side API for WebDAV :-).




So how to turn THIS into a fluent API without using a lot of different
builders or split up into a lot of lines (and in both cases blow up the
content by far)? Cannot imagine a solution.
 
Any suggestions...? I do not see that it is possible AND useful to the
user... :-(
 
  

I suspect we'll need some combination of multiple builders and lots of
alternatives on the fluent pattern builders to accomodate different
combinations of parameter signatures for the various builder methods.
You're absolutely right, though, WebDAV in its full glory is a pretty
complicated beast.

I will take a look at the specs again, but I'm going to be travelling this
week so won't have a heck of a lot of time to work on this.



Thanks
Markus
 
  

Craig