New HornetQ REST Interface

6 Comments

After being distracted a lot with RESTEasy releases over the past few months, I finally have something usable (and more importantly, documented) for the HornetQ REST Interface I’ve been working on.  The interface allows you to leverage the reliability and scalability features of HornetQ over a simple REST/HTTP interface. Messages are produced and consumed by sending and receiving simple HTTP messages containing the XML or JSON (really any media type) document you want to exchange.

Other than being buzzword compliant here are some of the reasons you might want to use the HornetQ REST Interface:

  • Usable by any programming language that has an HTTP client library.
  • Zero client footprint. We want HornetQ to be usable by any client/programming language that has an adequate HTTP client library. You shouldn’t have to download, install, and configure a special library to interact with HornetQ.
  • No envelope (i.e. SOAP) or feed (i.e. Atom) format requirements. You shouldn’t have to learn, use, or parse a specific XML document format in order to send and receive messages through HornetQ’s REST interface.
  • Lightweight interoperability. Since interactions are RESTful the HTTP uniform interface provides all the interoperability you need to communicate between different languages, platforms, and even messaging implementations that choose to implement the same RESTful interface as HornetQ (i.e. the REST-* effort.)
  • Leverage the reliability, scalability, and clustering features of HornetQ on the back end without sacrificing the simplicity of a REST interface.

HornetQ REST Features

  • Duplicate detection when producing messages
  • Pull and Push consumers
  • Acknowledgement and Auto-acknowledgement protocols
  • Create new queues and topics
  • Mix and match JMS and REST producers and consumers
  • Simple transformations

Visit the HornetQ REST Interface web page to find links for downloading and browsing docs, source code, and examples.

RESTEasy 2.0.0 Released!

1 Comment

Our first major release of 2010.  After a bunch of betas, I’m pleased to announce that RESTEasy 2.0.0.GA has been released.  A lot of work within the RESTEasy community has been done to improve on our last successful GA.  Follow the links from the RESTEasy website to download the new release.  Special thanks to Jozef Hartinger for the CDI integration, Eoghan Glynn for fixing a bunch of bugs, Stef Epardaud for the new Javascript client, and many others for their continuing support.  Some highlights:

  • CDI Support
  • Spring 3.0 Support
  • TCK 1.1 Compliance
  • Async Servlet 3.0 Support
  • A new Javascript API.  A javscript servlet scans JAX-RS deployments and generates Javascript code that can be downloaded that can be used as stubs.
  • Relicensed under ASL 2.0.  We switched to be compatible with HornetQ and Drools as we’re developing REST interfaces for these guys.
  • Tons of bugfixes and performance improvements reported by the community over the past 8 months.

Browse our release notes for the last few betas to look at all the bugs and features implemented.

The upcoming JBoss AS 6-Milestone 4 release will also have deeper integration with RESTEasy so that you can do automatic scanning, EJB injection, CDI injection, etc.  All the stuff you’d expect from a JAX-RS integrated EE 6 solution.

RESTEasy 2.0-beta-2 released

1 Comment

I don’t usually blog about beta or RC releases, but people have had a few problems with Apache Client 4.0 integration with RESTEasy, specifically, a bunch of connection cleanup bugs.  I have fixes those bugs reported for this.  Also, this release ran successfully against the JAX-RS 1.1 TCK.  I had to make a bunch of encoding fixes here.

You can download from the usual places.  Go to our home page for more info.

Webinar on REST, RESTEasy, JBoss – March 23rd

Leave a comment

I’m doing a webinar tomorrow on REST, JAX-RS, RESTEasy, and REST-*.  I only have 40 minutes, so it will be a brief overview of all those subjects and how they fit into our EAP product.  I’ll be giving it twice:

9am – EST

2pm – EST

For more information, click here

Mapping response on client side

8 Comments

I’ve been prototyping a bit lately for the REST-* effort, specifically for BPM.  I rely heavily on Link headers to pass links around.  RESTEasy has become pretty decent at handling links on the client side.  Here’s an example of client request/responses and link following via link headers:

      InputStream jpdl = Thread.currentThread().getContextClassLoader().getResourceAsStream(file);
      ApacheHttpClientExecutor executor = new ApacheHttpClientExecutor();

      ClientRequest request = executor.createRequest("http://localhost:8081/bpm/definitions");
      request.body(mediaType, jpdl);
      Link definition = request.create();
      Assert.assertNotNull(definition);
      ClientResponse response = null;

      response = definition.request().head();
      Assert.assertEquals(200, response.getStatus());
      Link instanceFactory = response.getLinkHeader().getLinkByTitle("instances");

      MultipartFormDataOutput form = new MultipartFormDataOutput();
      form.addFormData("order", "$199.99", MediaType.APPLICATION_XML_TYPE);
      response = instanceFactory.request()
              .body(MediaType.MULTIPART_FORM_DATA_TYPE, form)
              .post();
      Assert.assertEquals(201, response.getStatus());
      System.out.println(response.getLinkHeader().toString());
      Link instance = response.getLocation();
      Assert.assertNotNull(instance);

      Link next = response.getLinkHeader().getLinkByTitle("continue");
      Assert.assertNotNull(next);

      Link variables = response.getLinkHeader().getLinkByTitle("variables");
      Link newVariables = response.getLinkHeader().getLinkByTitle("variable-template");

      response = variables.request().head();
      Assert.assertEquals(200, response.getStatus());
      System.out.println(response.getLinkHeader().toString());
      Link order = response.getLinkHeader().getLinkByTitle("order");
      String xml = order.request().getTarget(String.class);
      request = newVariables.request();
      response = request.pathParameter("var", "customer")
             .body(MediaType.APPLICATION_XML_TYPE, "bill")
              .put();
      Assert.assertEquals(201, response.getStatus());
      response = request.pathParameter("var", "customer")
             .body(MediaType.APPLICATION_XML_TYPE, "bill burke")
              .put();
      Assert.assertEquals(204, response.getStatus());

      response = next.request().post();
      Assert.assertEquals(204, response.getStatus());

The thing about this code, it is a little hard to read.  Because HTTP is being treated like a messaging API, the code is a conglomeration of simple API calls.  The RESTEasy client proxy framework provides a nice way to map Java method calls to HTTP requests.  It also allows you to map automatically, a response body to a Java object.  Unfortunately though, this doesn’t work that well for my usecases.  Because I’m relying a lot on Link headers to pass information around in REST-*, I need something that can represent an HTTP response as a whole in a nice way.

A POJO Response Mapping

So, I thought, why not define (or reuse JAX-RS annotations) to map an HTTP response to a Java POJO?  It would kind of be the opposite of the RESTEasy @Form feature (where form maps an incoming request to a POJO).  It could look something like this:

@ResponseMapping
@ExpectedCode(200)
public interface MyResponse {

   @Body
   public Customer getCustomer();

   @LinkHeader
   public Link getNext();

   @LinkHeader("last")
   public Link getLastCustomer();

   @Header("ETag")
   public String getHash();

}

In this example, the client code would be expecting a response code of 200 (OK), a message body converted to a Customer object, a Link header named “next”, and a HTTP response header “ETag”. Using the RESTEasy proxy framework, you could then return this as a method return value, i.e.

@Path("/customers")
public interface CustomerClient {

   @Path("{id}")
   @Produces("application/xml")
   public MyResponse getCustomer(@PathParam("id") int custId);
}

What about errors?

For responses where the response code does not match, you could define similar mappings on an exception class.

@ResponseMapping
@ExpectedCode(404)
public class NotFoundException extends RuntimeException {}

You’d integrate it with the RESTEasy proxy framework by putting it within the throws clause.

@Path("/customers")
public interface CustomerClient {

   @Path("{id}")
   @Produces("application/xml")
   public MyResponse getCustomer(@PathParam("id") int custId) throws NotFoundException;
}

What do you think?
Maybe I’m going a little overboard here. Maybe not? I don’t know. Let me know what you think.

Speaking at new Boston JBoss User Group 2/9

Leave a comment

Jesper Pederson has created a Boston JBoss User Group.  Our first meeting is next Tuesday, February 9th.  I’m the first speaker and will be giving an intro to REST, JAX-RS, and, if I have time, some of the stuff that we’re doing at REST-* (rest-star.org).  Please click here for more details.

Speaking in DC on REST, JAX-RS, and REST-*

Leave a comment

I’ll be speaking for NOVAJUG in WashingtonDC on Wednesday, January 20th 6:30pm-9:00pm. You can sign up for the event here.

The presentation will be about REST, JAX-RS, and REST-* specifically I will provide a short introduction to REST along with an explanation of the JAX-RS specification and how you can build RESTful web services with it. I will then get into how REST intersects with middleware services like messaging, transactions, and workflow.  Hope to see you there!

Possible POE support in Resteasy

Leave a comment

I was thinking about some POE support for Resteasy.  On the client side add a poe() set of methods on ClientRequest and a @POE annotation for the Proxy framework.  I.e.

ClienRequest request = ...;
request.body("<stuff/>", "appliation/xml");
ClientResponse response = request.poe();

@Path("/")
public interface MyService {
   @POE
   @Consumes("application/xml")
   public void poeIt(Data data);
}

The way they’d both work is a HEAD to the base URL would be sent to get the POE-Link, then a POST to the POE-Link would be done using the message body.  A Retry-like exception would be thrown if the POST fails.  For the serverside it could look something like this:

@Path("/foo/{sub}/{id}")
@POE
public void poeIt(@PathParam("sub") String subpath, @PathParam("id") @PoeGenerated int id) {...}

@PathParam combined with @PoeGenerated is an automatically uniquely generated id.  So, the user would invoke on /foo/{sub} and get back a POE link of /foo/{sub}/{id}.  i.e.

HEAD /foo/stuff

HTTP/1.1 200 OK
POE: 1
POE-Link: /foo/stuff/3333

Thoughts?

RESTEasy 1.2.1 Released

Leave a comment

Minor bug fix release.  Also, had to remove one of the referenced maven repositories because it was screwing up the build.

RESTEasy 1.2.GA Released

Leave a comment

After a few months RESTEasy 1.2.GA is finally ready.  This is mostly a cleanup, bug fix, and refactoring release, but here are some features of note:

I’d also like to thank Attila Kiraly for fixing some bugs that cropped up in Multipart and XOP support.  Pascal de Kloe, a new committer, also helped refactor content negotiation to support charset variants.  Solomon Duskis continues to be a seasoned veteran and helps with bugs and features here and there.

What’s next?  I’d like to focus next on getting complete OAuth support in.  I think it will help out our REST-* efforts as we look to secure the services we’re defining there.  RESTEasy is also going to expand beyond a simple JAX-RS implementation.  As JBoss projects like HornetQ, jBPM, Drools, Transactions, and Infinispan obtain RESTful interfaces, I’ll be creating a REST profile under the RESTEasy umbrella.

Useful links:

Older Entries Newer Entries