Skip to content

Instantly share code, notes, and snippets.

@matzew
Forked from danbev/gist:3871798
Created October 15, 2012 11:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matzew/3892035 to your computer and use it in GitHub Desktop.
Save matzew/3892035 to your computer and use it in GitHub Desktop.
RestEasy Integration

RestEasy Integration with AeroGear Controller

This document is intended to describe AeroGear Controllers integration with RestEasy.

Background

Currently, the routes that AeroGear Controller can handle are "one way" in the sense that they go through AeroGear Controller are forwarded to a view, which can be populated by a data model provided by the Controller for the route in question.
For example:

route()
      .from("/customers/{id}")
      .on(RequestMethod.GET)
      .to(TargetClass.class).targetMethod(pathParam("id");

A request for customer/10 would be routed through the targetMethod of TargetClass, and a view for the configured Route would be populated and the request forwarded to the view. For example, a JSP page displaying customer information for user with id 10 might be the view in the above case.

Now, the next step is to allow clients to be able to invoke REST endpoint. The difference here is that the request pattern, instead of forwarding to a view, the data itself would be returned. The are other use cases as well where data might not be returned but there will always be a response, perhaps a status and a location where data has been PUT/POST:ed.

From a users perspective they will configure a REST endpoint in the same, or similar, way as is currently done for "normal" routes. The integration with RestEasy will be done by programmatically configuring the endpoint behind the scene. This document's goal is to figure out how this integration and configuration can be done.

Programmatic endpoint definition using RestEasy

This section will try to sort out the best way to implement the programmatic endpoint configuration. To start things off we've done some very basic prototyping to get to familiar to with RestEasy.

Starting with a very basic Pojo like this:

public class Pojo
{
   public String doit()
   {
      System.out.println("[Pojo] doing it");
      return "Pojo done";
   }
}

This class will simulate our the target endpoint and as you can see it has no annotations. Next, step is to figure out how we describe such a class and get RestEasy to be able to handle it.

We have copied a test from RestEasy and modified it a little, the full source can be found here: TestProgrammaticConfig

   @Test
   public void programmaticConfig() throws Exception
   {
      final ResourceMethodRegistry registry = (ResourceMethodRegistry) dispatcher.getRegistry();
      
      final ResourceClassConfig config = ResourceClass.path("/")
                      .resourceClass(Pojo.class)
                      .resourceMethod("doit").httpMethod(GET).method(Pojo.class.getMethod("doit"))
                      .build();
      registry.addPerRequestResource(config);
      
      final MockHttpRequest request = MockHttpRequest.create("GET", "/doit");
      ResourceInvoker resourceInvoker = registry.getResourceInvoker(request);
      Assert.assertNotNull(resourceInvoker);
      
      BuiltResponse response = resourceInvoker.invoke(request, new MockHttpResponse());
      Assert.assertEquals(response.getEntity(), "Pojo done");
          
   }

What we have is very basic but might be simple enough to use to further investigate how this integration will work.

Integration point for RestEasy in AeroGear Controller

This section will discuss how RestEasy will be hooked into AeroGear Controller.

An application that uses AeroGear Controller is deployed as a web application archive (WAR), with the aerogear-controller.jar in the WEB-INF/lib directory. Upon deploying the WAR, the servlet container will scan the deployment for @WebFilter annotation (among other things). AeroGear Controller contains such a servlet filter named AeroGear. All request to the web application will go through the AeroGear filter. AeroGear gets injected with a Router instance which is able to dispatch to the routes that the end users has configured.

RestEasy can be deployed as a Servlet, or a Servlet Filter. Currently, we are looking into what the best way is to integrate by adding RestEasy 3.0-alpha-1-SNAPSHOT as a dependency of aerogear-controller. The following branch is being used to experiment resteasy-integration.

So, where should we hook into RestEasy?
Well, how about a separate Servlet Filter, for example named AeroGearRest, with gets injected with a RestRouter of which RestEasyRouter would be an instance. Please ignore the locations/package names as these will change.
This solution assumes that AeroGear, which handles the "normal" Model View Controller (MVC) call, will only contain routes that it can handle. Likewise, AeroGearRest will only contain routes that it can handle. The order of the filters does not matter and one will be run first, its hasRoutes() method will determine if it can service the http request, and if it can't the next filter will get a chance to handle the request. At the moment RestEasyRouter's hasRoute() method is hard code to see if the request path contains hello. This is done to be able to manually test this:

curl -i http://localhost:8080/aerogear-controller-demo/hello
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: */*
Content-Length: 14
Date: Mon, 15 Oct 2012 07:16:34 GMT

Hello RestEasy

The next step is to remove the hard coding and for that to be possible we have to look into how REST routes will be configured in AeroGear Controller.

Configuration of REST routes in AeroGear Controller

[Work in progress]
What differs between a "normal" route and a REST route?

Issues

Packaging RestEasy in demo

When deploying aergear-controller-demo to AS7, RestEasy is added as an implicit module, this means that if we need the version of RestEasy that we ship we will need to add an exclude.

This can be checked by inspecting the following classes and their classloader:

JaxRsConfig.class.getClassLoader()
     Module "deployment.aerogear-controller-demo.war:main" from Service Module Loader
ResourceMethodRegistry.class.getClassLoader()
     Module "org.jboss.resteasy.resteasy-jaxrs:main" from local module loader @b23d12 (roots: /path/to/jboss-as-7.1.1.Final/modules)

To add an exclude for AS7 there are two options, either provide a jboss-deployment-structure.xml file in WEB-INF, or add the exclude as a MANIFEST Header. Currently, the demo branch uses a jboss-deployment-structure.xml.

RestEasy release schedule

If we are to contribute the programmatic configuration of endpoints to RestEasy it will not be considered until RestEasy's 3.0 release according to the RestEasy team. According to the RestEasy roadmap there is a 3.0-alpha-1 scheduled for March 2013. This must be taken into consideration as it could possibly effect AeroGear Controllers release date.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment