I need a Java HTTP server/client framework for my next project. I have to work at a low-level first and integrate it with Cling, so I need access to raw HTTP messages, headers, entities, and so on. After that I need higher level abstractions and resources, so easy content negotiation, URI routing, and even XHTML representations (HATEOAS) are important. In fact, the last thing I need is a servlet container, and I absolutely do not want any WAR, deployment, classloader, web.xml stuff.
Here is my shortlist of projects which I'm evaluating:
- Restlet - Simply because I never had the time to really try it and I didn't know what distinquishes it from a servlet or JAX-RS container.
- Apache Wink - Never tried it, but seems to be focused on plain JAX-RS without any baggage. Even comes with an HTTP client framework, which I definitely want. Shouldn't take too long to figure out if it's a viable candidate.
- RESTEasy and Weld - Well, I've worked on Seam and RESTEasy integration last year, so this would be the comfortable option. The problem is: I know this stuff, so it's a safe fallback - I can always use that combination if everything else fails. But the grass always looks greener on the other side. So I definitely want to look at other solutions first, see what they have to offer. Also, Bill just now started talking about a non-servlet deployment option for RESTEasy, which is what I'd use.
Important factors that also come into play are: I need a WebDAV implementation and I'm fine with integrating Milton myself, however, if the HTTP framework provides it already or some extension points, that would be good. Secondly, I need something LGPL and GPL compatible, so Jersey is out. I'm going to switch Cling to LGPL with the next release, by the way.
Back to last week. I've now spent 10 days with Restlet and wrote a small integration project.
The big picture
Restlet reminds me of Hibernate 0.8: It's a kind of middleware that I guess many developers need and many projects could benefit from. It avoids the established standardized approaches (Servlet, JAX-RS), so it might actually move faster and offer better features without legacy cruft and wasting time on TCKs and similar fun activities. I'd even say that REST/HTTP as a background is comparable to thinking within the Relational Model but working with SQL. There are a couple of dedicated developers behind it who try to make a living from supporting open source software. They are writing a book with Manning as a publisher, which would probably be the first book about their software.
Unfortunately, there are also similarities between Restlet and early Hibernate that are not all good. The Restlet website needs work. This is rather significant if you are trying to sell a web framework. Navigating the five or so different wiki sub-sections is awkward, you get lost all the time. The sparse documentation is just some randomly linked pages. Here is an excercise: There is a way to download the Restlet 1.1 and the 2.0 documentation in a single HTML or PDF document. Find the link.
Restlet documentation content is an issue. You have to read the Restlet code, you'll only find the most simple examples and "getting started" hints in the documentation. Restlet has an extensive and often convoluted API, for one simple task there are ten different possible solutions. If at all you will find an example for one or two of them, and you will never find an explanation why a particular approach should be preferred. Much of the API and usage is completely undocumented except for one-line Javadoc. The authors probably think that their Restlet in Action book will improve the documentation situation. I don't think it will. First, I've been reading the available chapters several times and I still don't know much more than before - show me more than one way to solve a problem, please. Secondly, you can of course improve an open source project's documentation with a book that goes into much more detail than the reference documentation of the software. But you absolutely have to provide good reference documentation! A book is not a substitute.
The Restlet community/collaboration setup should be simplified. The variety of mailinglists, archives, and forums is confusing and deterrent. You need to register with the extremely popular tigris.org website to subscribe to a mailinglist. You have to pray that when you post on the Restlet Nabble forum, an e-mail will be send to the right mailinglist (it worked a few times, now it's broken). You can't reply via e-mail to Nabble messages, someone forgot to finish the integration. My recommendation: Stop all of this, archive what you have, and start over with a straightforward and simple setup that requires no website registration for mailinglist subscription, and one forum for users. Considering the low traffic, I think a single Nabble forum/mailinglist would do just fine.
But it works, no?
Hibernate 0.8 had one thing going for it that made all other concerns irrelevant: It worked immediately on my first evaluation test case. Back then, no other alternative even passed this simple test. I really wanted to believe that Restlet would be the same and that at least the software is great, even without documentation.
My results are mixed. Some features of Restlet could obviously be very nice, others are just not well thought out. This is by no means a complete evaluation of all aspects of Restlet! It's just what I experienced for my particular use cases.
I first tried to understand the concepts behind a Restlet Component, Application, Connector, and Resource. I don't agree with the separation of concerns between these artifacts but since this would lead to a rather longer design discussion, I'll accept that this is how the Restlet folks are interpreting Fielding's holy words. I definitely needed the Restlet in Action book for this, there is no other documentation about Component and Application.
Next I had to filter an HTTP request, read the headers and body, process it internally in Cling, and then
create and return a response. Or, let the request pass through the filter if it doesn't have the right
headers, etc. This was my first contact with the Router and Filter API. The Filter swallowed any
RuntimeException in the beforeHandle() method silently, fortunately that was fixed with the
released Restlet 2.0.0 last week.
Moving on to URI mapping with the Router: It took me at least an hour to get some very very simple requests routed properly, again suffering with no documentation. Then I had to read HTTP headers of a request, all of them. Oh, there is no API for that? In an HTTP/REST framework? You can't be serious... and making it the first question in your FAQ is really not the right solution.
I've tried to use the @Get, @Put, etc. annotations on interfaces, with
server-side implementation subclasses and automatically created client proxies. I understand that this
seems like a major feature but it is the minimum I expect today from a high-level HTTP framework. I
don't like the annotation design, @Get("xml") is not a good idea. This is
not a MIME type but another Restlet-owned mapping string which I have to look up in some Javadoc
(not in the @Get Javadoc no less). There is not much wrong with the JAX-RS annotations, this
looks like NIH.
Converting resource representations is another major feature I expect in a REST framework. I have a Java
instance and I want an XML document, or a JSON representation. A submitted HTML form shoud be available
as a multi-valued Java map. The Restlet converter service unfortunately looks like an afterthought and
from what I understand was even much improved in version 2.0. You still have to write two classes,
a ConverterService which will determine what conversion to use and a subclass of
ConverterHelper, which does the actual conversion. (Naming something
FoobarHelper is a sign that you should rethink what you are doing.) Note that this is one annotation and a simple
implementation of two methods in JAX-RS. I understand that Restlet gives you more flexibility over
content negotiation scoring, etc. but that should all be optional. I really don't want to
implement three slightly different "write this to string" methods for a single conversion.
So after a rather long while I had organized my Component, Application, Router, and Filter in such a way that requests could be processed. Next I wanted to write a Resource with negotiated content representation. One method should return an XHTML for browsers, the other method an XML representation for some other clients. It turns out that content negotiation is broken with anything but the built-in server connector.
I'm moving forward with the built-in server connector that is provided "not for production use". I
soon know why: Non-persistent HTTP connections from the JDK 1.6 HttpURLConnection are
timing out.
I've already decided that I can't continue at this point and I have to look for an alternative. But to
complete my evaluation, I want to at least write some unit tests to see how the mockups work.
Most of the Restlet artifacts, such as Request, Response, Form, etc. can be directly instantiated so that is nice for testing. With a bit of documentation, unit testing could be a strong side of Restlet, no messing around with fake WAR deployments, servlet contexts, and so on.
What now...
The project has potential and there is definitely a need for a comprehensive HTTP framework that offers flexible request routing, filtering, and content negotiation and marshalling. Go easy on the Component and Application stuff, people might not agree with how you think software should be organized. The big selling point beyond a plain JAX-RS implementation is most likely the client-side request and response handling. But when JAX-RS frameworks like RESTEasy and Wink already move in that direction, the space for Restlet gets smaller if it ignores JAX-RS. And, JAX-RS is really not that bad so if your project is pushing hard for an alternative approach, you need some absolute killer features. I haven't found them with Restlet in the last 10 days. My conclusion is that I'll have to look at alternatives and can't continue with Restlet at this time.
P.S. Putting new releases of Restlet only in a private Maven repository and making people wait 15 days for an udpate of the public repository is not a good way to make money with Free Software. It's a different story if your private repository provides an enhanced version, e.g. with extensive QA, certified, etc. I might be willing to pay for that extra value if I'm a corporation. I'm not going to pay you if I can drop the same unzipped JAR into my local repo with a single command, it's just inconvenient and developers don't like it.
