RESTEasy 1.0-RC1 Released: Need help finalizing GA!

Leave a comment

RESTEasy 1.0-RC1 has just been released.  Please see our main project page and follow links to documentation and downloads.  Not much new functionality in this release.  After 77 days of waiting for Sun to allow us to download the JAX-RS TCK, I was able to pass all TCK tests after a fixing a few minor bugs.  1.0-RC1 reflects these changes.

Onward to 1.0 GA!

After a 2 week incubation of RC1, 1.0 GA will be released (sometime January 21st) and will be fully certified with Sun as a JAX-RS implementation.  I need your help finalizing the GA release! Specifically

  • I need existing RESTEasy users to upgrade and test their applications.
  • I need pointers on improving usability
  • Documentation improvements
  • Bugs reports and patches are always welcome too!

Since the window for the GA is only 2 weeks, there’s not a lot of features I can accomodate in the usability department, but I will try.

Web Apps vs. Web Sites

4 Comments

I’ve been excited for awhile now about going retro.  Going retro to the days of 3-tiered GUI applications and substituting VB+DCE/CORBA+DB with AJAX+REST+DB.  We got to talking about this quite extensively today in a Red Hat internal mailing list after the announcement of Red Hat’s participation in the Google GWT project.

One problem I had problems reconciling with was the search engine problem.  If your web application is rendered dynamically through AJAX and GWT-controlled pages how will a search engine index your site?  Michael Neale came to the rescue with:

If you want search engine crawling – then its not a web app, its a web site.

This statement is simple but profound.  It makes sense because a web app is highly interactive, dynamic, and usally un-indexable.  He’s on to something.  He talks a little more in detail about it here.  Thanks Mike!

Wrong Documentation in RESTEasy beta-9. Redownload please.

Leave a comment

I accidentally bundled the old beta-7 documentation with the binary release of 1.0-beta-9.  Please re-download to get updated documentation.

Apologies!

RESTEasy Beta 9 Released

5 Comments

Follow documentation and download links from our main project page.  View our full release notes from JIRA.  Special thanks goes out to Solomon Duskis for helping me nail down the Spring integration and for implementing the Spring MVC bridge.  This is a pretty extensive release with a lot of new features:

  • Asynchronous HTTP (Comet) support via Tomcat 6, JBoss Web, or Servlet 3.0 (Jetty 7).  This is a tiny, but simple abstraction over these APIs
  • Expanded Multipart support.  You can now marshal collections(Maps and Lists) of objects to and from multipart/mixed and multipart/form-data.
  • Atom + JAXB support.  I wrote a few JAXB annotated classes to represent the Atom format.  You can embed JAXB classes within Atom content as well as marshall Atom to and from XML, JSON, and Fastinfoset.
  • Atom support via Apache Abdera
  • Arrays and Collections of JAXB objects marshalled automatically.
  • Enhanced Spring support.  We now support autoproxied beans as well as some nice Spring MVC support and the ability to output ModelAndView objects.  Thanks Solomon!!!

This will hopefully be the last beta.  I’ve been waiting patiently (since October 1st) for Red Hat and Sun to hammer out the licensing terms so I can download the JAX-RS TCK and get RESTEasy certified.  I should be getting it any day now and so the next release of RESTEasy will be RC1 and certified.  I’m not sure how long the TCK will take as I don’t have my hands on it yet, but I’m hoping around 6-8 weeks.  Shortly after RC1 will be 1.0.

JAX-RS Atom Support with Resteasy

3 Comments

I have implemented Atom support which will be available with the next release of RESTEasy.

Although the Atom format is used primarily for the syndication of blogs and news, many are starting to use this format as the envelope for Web Services, for example, distributed notifications, job queues, or simply a nice format for sending or receiving data in bulk from a service.

RESTEasy has defined a simple object model in Java to represent Atom and uses JAXB to marshal and unmarshal it. The main classes are in the org.jboss.resteasy.plugins.providers.atom package and are Feed, Entry, Content, and Link. If you look at the source, you’d see that these are annotated with JAXB annotations. The distribution contains the javadocs for this project and are a must to learn the model. Here is a simple example of sending an atom feed using the Resteasy API.

import org.jboss.resteasy.plugins.providers.atom.Content;
import org.jboss.resteasy.plugins.providers.atom.Feed;
import org.jboss.resteasy.plugins.providers.atom.Link;
import org.jboss.resteasy.plugins.providers.atom.Person;

@Path("atom")
public class MyAtomService
{

   @GET
   @Path("feed")
   @Produces("application/atom+xml")
   public Feed getFeed()
   {
      Feed feed = new Feed();
      feed.setId(new URI("http://example.com/42"));
      feed.setTitle("My Feed");
      feed.setUpdated(new Date());
      Link link = new Link();
      link.setHref(new URI("http://localhost"));
      link.setRel("edit");
      feed.getLinks().add(link);
      feed.getAuthors().add(new Person("Bill Burke"));
      Entry entry = new Entry();
      entry.setTitle("Hello World");
      Content content = new Content();
      content.setType(MediaType.TEXT_HTML_TYPE);
      content.setText("Nothing much");
      feed.getEntries().add(content);
      return feed;
   }
}

Because Resteasy’s atom provider is JAXB based, you are not limited to sending atom objects using XML. You can automatically re-use all the other JAXB providers that Resteasy has like JSON and fastinfoset. All you have to do is have “atom+” in front of the main subtype. i.e. @Produces(“application/atom+json”) or @Consumes(“application/atom+fastinfoset”)

Using JAXB with the Atom Provider

The org.jboss.resteasy.plugins.providers.atom.Content class allows you to unmarshal and marshal JAXB annotated objects that are the body of the content. Here’s an example of sending an Entry with a Customer object attached as the body of the entry’s content.

@XmlRootElement(namespace = "http://jboss.org/Customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer
{
   @XmlElement
   private String name;

   public Customer()
   {
   }

   public Customer(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return name;
   }
}

@Path("atom")
public static class AtomServer
{
   @GET
   @Path("entry")
   @Produces("application/atom+xml")
   public Entry getEntry()
   {
      Entry entry = new Entry();
      entry.setTitle("Hello World");
      Content content = new Content();
      content.setJAXBObject(new Customer("bill"));
      entry.setContent(content);
      return entry;
   }
}

The Content.setJAXBObject() method is used to tell the content object you are sending back a Java JAXB object and want it marshalled appropriately. If you are using a different base format other than XML, i.e. “application/atom+json”, this attached JAXB object will be marshalled into that same format.

If you have an atom document as your input, you can also extract JAXB objects from Content using the Content.getJAXBObject(Class clazz) method. Here is an example of an input atom document and extracting a Customer object from the content.

@Path("atom")
public class AtomServer
{
   @PUT
   @Path("entry")
   @Produces("application/atom+xml")
   public void putCustomer(Entry entry)
   {
      Content content = entry.getContent();
      Customer cust = content.getJAXBObject(Customer.class);
   }
}

JAX-RS Multipart support with RESTEasy

7 Comments

I just finished implementing some “multipart/*” and multipart/form-data support within RESTEasy.  It will be out with the next release.  Highlights?

A JAX-RS compatable API

Our current support for multipart is through the MimeMultipart classes within the Java Mail library.  They are limited because they do not use the MessageBodyReader/Writers available in JAX-RS.  I have written two parallel APIs that provide multipart support in a JAX-RS way:

package org.jboss.resteasy.plugins.providers.multipart;

public interface MultipartInput {
   List<InputPart> getParts();
   String getPreamble();
}

public interface InputPart {
   MultivaluedMap<String, String> getHeaders();
   String getBodyAsString();
   <T> T getBody(Class<T> type, Type genericType) throws IOException;
   <T> T getBody(org.jboss.resteasy.util.GenericType<T> type) throws IOException;
   MediaType getMediaType();
}

MultipartInput is a simple interface that allows you to get access to each part of the multipart message. Each part is represented by an InputPart interface. Each part has a set of headers associated with it.  You can unmarshall the part by calling one of the getBody() methods. The Type genericType parameter can be null, but the Class type parameter must be set. Resteasy will find a MessageBodyReader based on the media type of the part as well as the type information you pass in. The following piece of code is unmarshalling parts which are XML into a JAXB annotated class called Customer.

   @Path("/multipart")
   public class MyService   {
      @PUT
      @Consumes("multipart/mixed")
      public void put(MultipartInput input)
      {
         List<Customer> customers = new ArrayList...;
         for (InputPart part : input.getParts())
         {
            Customer cust = part.getBody(Customer.class, null);
            customers.add(cust);
         }
      }
   }

There’s a similar API for outputing multipart.

Multipart with vanilla Lists and Maps

Another feature I’ve added is the ability to use regular instances of java.util.List(any multipart format) or Map (form-data only) to represent multipart data.  Its only usable when your parts are uniform though.

Here’s an example of using it:

parameter of the List type declaration. Here’s an example again of unmarshalling a list of customers.

   @Path("/multipart")
   public class MyService
   {
      @PUT
      @Consumes("multipart/mixed")
      public void put(List<Customer> customers)
      {
         ...
      }
   }

That’s using input.  The problem with output is that RESTEasy has no idea what mime type you want to marshal or List or Map into.  So, the @PartType annotation is used.  Here’s an example of outputing multipart/form-data with a map:

@Path("/multipart")
   public class MyService
   {
      @GET
      @Produces("multipart/form-data")
      @PartType("application/xml")
      public Map<String, Customer> get()
      {
         ...
      }

Multipart-Formdata with POJOs

Finally, I added the ability to map POJO form classes to multipart/form-data.  You re-use @FormParam on fields and/or properties of a user-provided POJO.  Here’s an example:

   public class CustomerProblemForm {
      @FormData("customer")
      @PartType("application/xml")
      private Customer customer;

      @FormData("problem")
      @PartType("text/plain")
      private String problem;

      public Customer getCustomer() { return customer; }
      public void setCustomer(Customer cust) { this.customer = cust; }
      public String getProblem() { return problem; }
      public void setProblem(String problem) { this.problem = problem; }
   }

After defining your POJO class you can then use it to represent multipart/form-data. Here’s an example of sending a CustomerProblemForm using the RESTEasy client framework

   @Path("portal")
   public interface CustomerPortal {

      @Path("issues/{id}")
      @Consumes("multipart/form-data")
      @PUT
      public void putProblem(@MultipartForm CustomerProblemForm,
                             @PathParam("id") int id);
   }

   {
       CustomerPortal portal = ProxyFactory.create(CustomerPortal.class, "http://example.com");
       CustomerProblemForm form = new CustomerProblemForm();
       form.setCustomer(...);
       form.setProblem(...);

       portal.putProblem(form, 333);
   }

You see that the @MultipartForm annotation was used to tell RESTEasy that the object has @FormParam and that it should be marshalled from that. You can also use the same object to receive multipart data. Here is an example of the server side counterpart of our customer portal.

   @Path("portal")
   public class CustomerPortalServer {

      @Path("issues/{id})
      @Consumes("multipart/form-data")
      @PUT
      public void putIssue(@MultipartForm CustoemrProblemForm,
                           @PathParm("id") int id) {
         ... write to database...
      }
   }

JAX-RS + Asynch HTTP

10 Comments

A RESTEasy user (and JBoss customer) asked about 6 weeks ago if we were planning on supporting Resteasy with Asynchronous HTTP.  For those of you not familiar with Asynchronous HTTP, take a look at Servlet 3.0, Tomcat Comet APIs, or Jetty’s continuations.  I decided to add some limited support after doing some research.

The primary (and IMO, the only) usecase for Asynchronous HTTP is in the case where the client is polling the server for a delayed response.  The usual example is an AJAX chat client where you want to push/pull from both the client and the server.  These scenarios have the client blocking a long time on the server’s socket waiting for a new message.  What happens in synchronous HTTP is that you end up having a thread consumed per client connection.  This eats up memory and valuable thread resources.  No such a big deal in 90% of applications, but when you start getting a lot of concurrent clients that are blocking like this, there’s a lot of wasted resources.

As for Resteasy and asynchronous HTTP, I don’t want to create a COMET server.  Maybe I’m totally wrong, but it seems that the idea of COMET is to use HTTP solely for the purpose of initiating a dedicated socket connection to your server.  After the initial connection is made, the client and server just tunnel their own message protocol across the socket for any number of requests.

Now, this isn’t necessarily a bad idea.  Its actually a good one for performance reasons.  As a JBossian David Lloyd explained to me in private email, what this API allows you to do is create a direct connection to your service so that you don’t have to redispatch with every message that is exchange from the client and server.  Sure, HTTP Keep Alive allows you to avoid re-establishing the socket connection, but you don’t have to worry about all the other path routing logic to get the message to the Java object that services the request.

Still, this is something I don’t want or need to provide through RESTEasy.  Its really using HTTP to tunnel a new protocol and something that is very unRESTful to me.  Basically it requires that the client knows how to communicate the COMET protocol, which IMO, makes ubiquity very hard.  Besidesk, Tomcat, JBoss Web, and Jetty will probably do a fine job here.  There are also already a number of COMET servers available on the web.  No, I will focus on giving asynchronous HTTP features to a pure HTTP and JAX-RS request.

What I will initially provide through RESTEasy is a very simple callback API.

@Path("/myresource")
@GET
public void getMyResource(@Suspend AsynchronousResponse response) {

   ... hand of response to another thread ...
}

public interface AsynchronousResponse {

   void setResponse(javax.ws.rs.core.Response response);

}

The @Suspend annotation tells Resteasy that the HTTP request/response should be detached from the currently executing thread and that the current thread should not try to automaticaly process the response.  The AsynchronousResponse is the callback object.  It is injected into the method by Resteasy.  Application code hands off the AsynchronousResponse to a different thread for processing.  The act of calling setResponse() will cause a response to be sent back to the client and will also terminate the HTTP request.

Servlet 3.0 has asynchronou APIs.  When you suspend a request, the request may be redelivered when a timeout occurs.  I don’t want to have a Resteasy replacement for these APIs.  What I want is something that complements these APIs and makes a specific usecase easier to write.  The use case I want to solve is detaching the processing of an HTTP response from the current thread of execution so that another thread can do the work when ready.  That’s it.  So, there will be no redelivery of a request.

Initially I plan to work with the asynchronous apis within the Tomcat 6.0 NIO transport as this is what is distributed with JBoss 4.2.3.  Next I plan to work with the JBoss Web asynchronous apis, then Jetty 6, then finally with a Servlet 3.0 implementation.

If you have any ideas on this subject, please let me know.  I can work them into the prototype I’m developing.

Atom too SOAPy for me

6 Comments

I’ve heard a lot of talk lately about using the Atom protocol for something other than a better RSS feed, like using it as a messaging protocol.  For instance, I was reading this excellent article on using REST to design a workflow on Infoq.com where they use the Atom format to describe and interact with a work queue.  The example was that a order fulfilment worker would the server and would get back an Atom feed of what jobs needed to be fulfilled.  Other, like James Strachan, had talked about using atom as well.

For me, the value of Atom haven’t really clicked with me yet.  Its just too SOAPy for me.  If you look at ATOM, the ATOM protocol, and how people are talking about using it, they’re really using it as an envelope.  One of the things that attracted me to REST was that I could focus on the problem at hand and ignore bulky middleware protocols (like SOAP) and lean on HTTP as a rich application protocol.

For example, if you want to get a list of messaging, why not just multipart/mixed?  Its a very simple format.  Its easy to parse.  You can assign specify headers to each body and use well-known headers like Content-Location if you want to replace actual content with a link. Its all much more compact.  Better yet, why not just send back a comma-delimited list of URLs.

Maybe I just haven’t seen the light yet.  It took me months to accept REST as a viable way of doing things.  Maybe I just need somebody to yell at me about ATOM.

RESTEasy DZone articles and Beta 8

6 Comments

If you’re wondering why I haven’t done a signficant blog since June, wonder no more.  Instead of creating content for my blog, I’ve written a couple of articles for DZone.com:

Also, today I put out RESTEasy 1.0 Beta 8.  I small tiny bug was found by the community which I rolled up quick into a release.  Follow the downloads link at http://jboss.org/resteasy to check it out.

RESTEasy 1.0-beta-7: quick bug fixes

2 Comments

A quick release from our beta-6 to fix a few quick bugs that users found.  See our main project page at:

http://jboss.org/resteasy

to download and browse docs.  Have fun.

Older Entries Newer Entries