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.

followme OSGi JAX RS connector: Publishing REST services

17 Responses to “OSGi JAX-RS connector: Publishing REST services”

  1. 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

  2. Hi Neil,
    thanks for your response. I know your connector but I couldn’t use it because I wanted the integration with the Service Lifecycle as you have allready described. The feature to manage the resource instantiation by yourself is not new in JAX-RS 2.0. The Application class has two methods to register resources. the first one for adding class objects. This is what you have used I guess? The other is called getSingletons(). A singleton in JAX-RS is an allready instantiated resource. See http://jax-rs-spec.java.net/nonav/2.0/apidocs/javax/ws/rs/core/Application.html

    My connector simply hooks the JAX-RS Singleton resources with OSGi services (they are also some kind of singletons as you know for sure ;)). Of course there is a little bit more regarding multiple HttpServices and Configuration. But basically thats it.

    Cheers Holger

  3. 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.

  4. That’s probably true. Another problem came into my mind when I found this method. What about scalability? When thousands of request come in in parallel? I mean, normally Jersey will manage the request delegation to different resource instances, but here it has only one. But, this problem does not exist. We have this in production and we wrote stress tests for this scenario. The singleton resources perform really well.

  5. Tom Schindl says:

    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?

  6. Hi Tom, please uncheck “include required software” while installing into your target. I allready pointed this out in the README file within the git repository. The repository only contains the connector and 3 Jersey Bundles.

  7. Tom Schindl says:

    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.

  8. The only reason I used these versions are that I developed against 3.8M4. I have opened an github issue for this, see https://github.com/hstaudacher/osgi-jax-rs-connector/issues/1

  9. Lukasz Jastrzebski says:

    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.

  10. Andrew says:

    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.

  11. Swapna says:

    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

  12. You need to launch an osgi instance with a configured port. After this you cann access the service with http://server:port/osgi-jax-rs

    Hth

  13. Gireesh says:

    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

  14. @Girees, That means that there is not HttpService. Did you started one?

  15. Gireesh says:

    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

  16. Gireesh says:

    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

  17. Gireesh says:

    Hi

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

    Thanks
    Gireesh

17 responses so far

Written by . Published in Categories: Planet Eclipse, Planet OSGi