OSGi JAX-RS connector: Publishing REST services

OSGi JAX-RS connector: Publishing REST services

In a recent blog post Peter Kriens commented that the OSGi service model is as important as object-orientation. I feel the same – I don’t want to write software without this concept anymore. But for me, the service model only makes sense when it’s used together with the modularity OSGi provides. I think the modularisation layer is the greatest advantage of the OSGi platform and the services are really only there to simplify the communication between modules.

When it comes to developing a REST API with Java, this advantage is missing in most of today’s libraries (e.g. Restlet or Jersey), because the Java language still lacks modularity. But especially for the design of a REST API this concept can be a great benefit, because it overcomes the limitation of only being able to separate REST services by url and Java packages. With modularity the service implementations can be separated into modules which improves the maintainability and the beauty of the whole system a lot.

[ Find even more tools to hack your workflow: Eclipse Tools. | Running a mission-critical system? Keep it running smooth with our Production Support. ]

A few months ago I discovered JAX-RS for developing REST services. (Before that I used Restlet.) I have to say that the JAX-RS API makes it really easy to develop REST services. See this article for a how-to. A reference implementation of this API is Jersey. The cool thing about this implementation is that it plays really well together with the OSGi HttpService and it ships as bundles. In this way we have the option to actively deploy REST services into the HttpService. But is this how we want to publish REST services? To me, it’s not!

In my ideal world I would write my @Path annotated Pojos and publish them as OSGi services. That’s it. The runtime should take care of publishing and service wiring. Sadly, Jersey has no built-in feature for that. This is the reason I wrote a little OSGi-JAX-RS connector. The only thing the connector does is that it publishes OSGi services as REST services using JAX-RS. Of course, there are OSGi remote services, but using them does not allow the use of JAX-RS the way I’d prefer, namely as a lightweight additional bundle.

You can find the connector in GitHub. To make it work simply install it into your OSGi instance by using this jar. (You’ll also find a p2 repository there). That’s it. The only thing you have to take care of is writing the REST services like the one in this example.

@Path( "/osgi-jax-rs" )
public class ExampleService {

  @GET
  public String seyHello() {
    return "JAX-RS and OSGi are a lovely couple.";
  }
}

The activator can then look like this:

public class Activator implements BundleActivator {

  private ServiceRegistration registration;

  @Override
  public void start( BundleContext context ) throws Exception {
    ExampleService exampleService = new ExampleService();
    registration = context.registerService( ExampleService.class.getName(), exampleService, null );
  }

  @Override
  public void stop( BundleContext context ) throws Exception {
    registration.unregister();
  }
}

Further instructions can be found in the README of the git repository. It also contains two examples for using this connector with and without declarative services. In the second part of this blog series I will show you how to configure the services using the OSGi Configuration Admin Service and publish services on different ports within the same OSGi instance. I hope you enjoy this connector as much as I do.

17 Comments
  • Posted at 12:21 pm, January 23, 2012

    I’m curious how you manage the lifecycle of the JAX-RS resources. As you know, the JAX-RS specification requires us to supply Class objects to the Application rather than actual resource objects; this is because by default JAX-RS creates a new instance of the resource for each HTTP connection… so they are using the Class as a kind-of factory. This makes it very hard to inject other OSGi services using DS or whatever, because the servlet is in charge of the resource lifecycle rather than DS.

    So I’d be interested to hear if you found a way around this problem (I admit I haven’t followed the progress of JAX-RS 2.0 at all). Otherwise this looks fairly similar to the connector I wrote about a year ago: https://github.com/njbartlett/jaxrs-osgi-extender

    Cheers,
    Neil

  • Posted at 12:48 pm, January 23, 2012

    Hi Holger… thanks for the clarification. Yes I remember that now but I don’t remember why I didn’t use that approach myself! As I seem to recall that the JAX-RS encourages the use of per-request resource objects over singletons, but perhaps that is purely because you get thread-safety “for free” whereas a singleton will have to be consciously programmed to be thread safe.

  • Posted at 5:20 pm, January 23, 2012

    Hm – I’m unable to install this into my target it complains about missing javax.servlet [2.3.0,4.0.0] which is very strange because my target shows javax.servlet 2.5.0! Any idea what can cause this problem?

  • Posted at 6:52 pm, January 23, 2012

    a that worked. In the meantime I checked out your sources and is there a reason you are requireing org.osgi.framework 1.7.0 and org.osgi.service.com 1.4.0 in the console-bundle? Using 1.6.0 and 1.4.0 at least does not give me compiler errors (they are the ones coming with 3.7.1) whereas I guess 1.7.0 and 1.4.0 are from 3.8.

  • Lukasz Jastrzebski
    Posted at 3:00 am, January 27, 2012

    Hi,

    I did similar thing but using camel-cxf, which of course is an overhead, but I just want to play with whiteboard pattern and try different things like (consuming Guice beans with Declarative services) and so on.

    I manage to build that with tycho (eclipse plugins/features/tests and p2 repo), so if You are interested in adding maven build to your project I could help with that.

    Finally the repository: https://github.com/elyast/sppaclet

    Please free to comment.

  • Andrew
    Posted at 8:55 am, February 2, 2012

    I myself used a similar pattern in some software I helped develop, however rather than registering resources via OSGi I registered javax.ws.rs.Application instances.

    To get it all to work I had a Jersey servlet registered which then forwarded the ContainerRequest to other Jersey application instances based on the OSGi registered javax.ws.rs.Application instances. This did mean that each javax.ws.rs.Application needed to have its concept of “context path” so that the forwarder knew which one to direct the request to for handling, the “context path” was provided by service properties with the javax.ws.rs.Application registration.

  • Swapna
    Posted at 1:22 pm, April 9, 2012

    Hi Holger, I downloaded all the source from the git hub, i got them compiled too. I launched the JAX-RS Example DS. After this how to test the ExampleService.

    Can you please help me on this ?

    Thanks
    Swapna

  • Gireesh
    Posted at 6:00 pm, April 11, 2012

    Hi,

    I got the jars from Github and deployed in Virgo server. Deployment worked fine, but my REST service is not working. When debugging I found that “com.eclipsesource.jaxrs.connector.internal.HttpTracker.addingService(ServiceReference)” is never called, hence all the resources are going to “resourceCache”

    What could be the reason, Please help.

    Will this work on virgo ?

    Thanks
    Gireesh

  • Gireesh
    Posted at 1:05 pm, April 12, 2012

    Hi,

    Virgo server supposed to have a HttpService running, because I was able to run my Spring Controller based REST services, when deploying as “web” bundle, Also I am able to access Virgo Admin console. Is there any thing else I need to check ?

    Thanks
    Gireesh

  • Gireesh
    Posted at 2:56 pm, April 12, 2012

    Ok, got it , Virgo doesn’t have HTTPService. I deployed “PAX-WEB” Jetty bundle, now the Resource registration is happening and I am able to invoke the service from browser, But there are other issues like

    1. When registering the Resource, I get the below message in console.
    Starting web bundle ‘null’ version ‘null’ with context path ‘null’.

    2. when invoking the rest service, I get some binary data (not the string I am returning from the function, I also given @Produces(“text/plain”), still I dont see the string message

    http://team.ops4j.org/wiki/display/paxweb/Pax+Web

    What could be the issue ?

    -Gireesh

  • Gireesh
    Posted at 3:50 pm, April 12, 2012

    Hi

    I got it working, Used Apache Felix Http service and mapped to a different port and its working now.

    Thanks
    Gireesh