Experimenting with OSGi on Server Side

Ruchika Goyal

I was introduced to OSGi quite by coincidence. I had to give a presentation and a colleague suggested to look into OSGi. And once I started looking into it, I was quite surprised to find the ease with which it provided the solutions to some of the problems that we face in the web application development. There are so many good articles and blogs which provide a great amount of material regarding OSGi. They are mentioned in the reference.

One of the concepts of OSGi that really intrigued me was how it allows bundles to export services that can be consumed by other bundles without knowing anything about the exporting bundle. OSGi takes care of this by introducing Service Registry where the exporting bundle registers the interfaces that it want to expose and any other bundle which wants to use those interface can just look up in the registry to use the implementation. The other concept of OSGi which I also found interesting was how OSGi uses version management to allow different versions of the same java class to be used within the project. So I created this blog to explore these concepts in greater detail. At this point, it would be important to mention that the intended audience for this blog are people who are new to OSGi. Also the example used are very basic and intend to show just the flow of control from one package to another.

To show how OSGi uses the Service Registry, I have created 2 bundles (Service and Dao) which register their interfaces. There are 2 more bundles (ServiceServlet and DaoServlet) which reference the registry to look for these interfaces respectively. I have created servlets to call the methods of the interface to show how we can create a dynamic web enabled project using OSGi. Finally to show the version management. I have created 2 different bundles having the same package and the same java class but different methods. These bundles would have different versions and we will see how these 2 methods can coexist.

Environment Setup:
Prerequisites:

  1. You must already have Java 1.5 or above installed in your system path. For my installation, I am using Java 1.6.
  2. You must already be familiar with Eclipse.
  3. You must already be familiar with how to create a bundle and how to use OSGi commands. If you are not familiar with these , then it would be a good idea to understand first how to create a simple OSGi bundle.

For this setup, I am using Eclipse Europa which comes with the Equinox framework required for running OSGi. You can also download the latest version of the eclipse. The OSGi container Equinox comes inbuilt with Eclipse 3.2 or later. Incase you are using Eclipse 3.1 or earlier , you would need to download Eclipse Equinox plugin.

For this setup, we are using Jetty as the server. But Equinox can be configured to work with Tomcat.

Setup the Execution Environment

Make sure that you have installed the JVMs you wish to use and that you have mapped each OSGi Execution Environment to one of the JVMs. Go to Window --> Preferences --> Installed JREs --> Execution Environments.


You can download the source. Import the packages into eclipse and skip right to the First Scenario.

  1. Create a bundle SampleDao with 2 packages.
    1. Package com.sample.sampledao contains an interface MyDao which has a method List retrieveAllObjects()
    2. public interface MyDao {
      public List retrieveAllObjects();
      }
    3. Package com.sample.sampledao.impl contains the activator for the bundle as well as the implementation for the MyDao interface. In the activator , we are registering the interface in the service registry so that any package from outside the bundle can access it.
    4. public class Activator implements BundleActivator {
      private ServiceRegistration daoregistration;
      public void start(BundleContext context) throws Exception
      {
      System.out.println("inside sampleDao bundle");
      MyDao mydao = new MyDaoImpl();
      daoregistration = context.registerService(MyDao.class.getName(),
      mydao, null);
      }
      
      public void stop(BundleContext context) throws Exception
      {
      System.out.println("Outside sampleDao bundle");
      daoregistration.unregister();
      }
      }
    5. Make sure to add the Activator in the Overview tab of the Manifest.MF.
    6. The implementation code would be. For now leave the commented out code as it is.
    7. public class MyDaoImpl implements MyDao {
      public List retrieveAllObjects()
      {
      //Test test= new Test();
      System.out.println("Inside retrieveAllObjects of MyDao");
      //test.testMethod2();
      return null;
      }
      }
    8. In the Runtime Tab of the Manifest.MF, click on Add button in the Exported Packages and select com.sample.sampledao to export it. Now click on properties and select the version 1.0.0.
  2. Create a bundle SampleService with 2 packages.
    1. Package com.sample.sampleservice has an interface MyService.java with the method List findAllObjects().
    2. public interface MyService
      {
      public List findAllObjects();
      }
    3. Package com.sample.sampleservice.impl contains the activator for the bundle as well as the implementation for the MyService interface. In the activator, we are registering the interface in the service registry so that any package from outside the bundle can access it. We are also referencing the service registry to look for the service provided by the Dao Interface.
    4. public class Activator implements BundleActivator {
      private ServiceRegistration registration;
      public static MyDao myDao;
      ServiceReference daoServiceReference;
      public void start(BundleContext context) throws Exception
      {
      System.out.println("Inside sampleservice bundle");
      MyService service = new MyServiceImpl();
      registration = context.registerService (MyService.class.getName(),
      service, null);
      daoServiceReference= context.getServiceReference(MyDao.class.getName());
      myDao =(MyDao)context.getService(daoServiceReference);
      }
      public void stop(BundleContext context) throws Exception
      {
      System.out.println("Outside sampleservice bundle");
      registration.unregister();
      context.ungetService(daoServiceReference);
      }
      }

      Again make sure to add the activator in the Overview Tab of the Manifest.MF. Also go to the Dependenies Tab of the Manifest.MF and import com.sample.sampledao package.

    5. The implementation of the service interface has the following code. As earlier, leave the commented out code as such.
    6. public class MyServiceImpl implements MyService {
      MyDao myDao;
      public List findAllObjects()
      {
      // Test test = new Test();
      myDao = Activator.myDao;
      System.out.println("Inside findAllObjects of MyService");
      // test.testMethod1();
      return (myDao == null) ? null : myDao.retrieveAllObjects();
      }
      }
    7. Export the package com.sample.sampleservice in the Runtime Tab of the Manifest.MF as was done in step 1d.
  3. Create a bundle ServiceServlet with a package com.sample.service.
    1. To create a servlet in a bundle, there are a few steps that need to be followed.
      1. Go to the Manifest.MF and select the dependencies tab.
      2. Click Add button under Automated Management of Dependencies and choose javax.servlet from the list of bundles.
      3. Click the Add button next to Imported Packages and add the javax.servlet and javax.servlet.http JARs.
    2. The activator for the bundle uses the service registry to look for the implementation of the MyService interface.The code for the activator is as:
    3. public class ServletActivator implements BundleActivator {
      public static MyService myService;
      ServiceReference serviceReference;
      public void start(BundleContext context) throws Exception
      {
      System.out.println("Inside ServiceServlet");
      serviceReference= context.getServiceReference (MyService.class.getName());
      myService =(MyService)context.getService(serviceReference);
      }
      
      public void stop(BundleContext context) throws Exception
      {
      System.out.println("Outside Service Servlet");
      context.ungetService(serviceReference);
      }
      }
    4. Create a servlet MyServlet in the package com.sample.service. The servlet code looks like :
    5.  public class MyServlet extends HttpServlet
      {
      MyService myService;
      protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException
      {
      resp.setContentType("text/html");
      PrintWriter pw = new PrintWriter (resp.getOutputStream());
      pw.println("This servlet is running in an Service Servlet using OSGi.");
      pw.println("Welcome to my Service Servlet");
      pw.println("");
      myService.findAllObjects();
      pw.close();
      }
      //@Override
      public void init() throws ServletException
      {
      System.out.println("inside init method");
      myService = ServletActivator.myService;
      }
      }

      This servlet is calling the method findAllObjects of the MyService Interface.

    6. In order to web enable the application, we need to use extension points to register the servlet.
      1. Goto Overview Tab in the Manifest Wizard and click on Extensions.
      2. Click OK to display the Extensions page. This will add an Extensions tab the Manifests wizard that will open automatically henceforth.
      3. Click the Add button and set the filter to "org.eclipse.equinox.http.registry.servlets." Remember to uncheck the check box.
      4. Enter the name of your Servlet class and give it an alias and save your changes.

      5. This will create a plugin.xml in your Manifest.MF.

  4. Create Bundle Dao Servlet with package com.sample.daoservlet.
    1. Repeat step 3a to add javax.servlet and javax.http.servlet jar as the dependencies for the DaoServlet.
      The activator for the bundle uses the service registry to look for the implementation of the MyDao Interface
    2. public class DaoActivator implements BundleActivator
      {
      public static MyDao myDao;
      ServiceReference daoServiceReference;
      
      public void start(BundleContext context) throws Exception
      {
      System.out.println("Inside DaoServlet");
      daoServiceReference= context.getServiceReference(MyDao.class.getName());
      myDao =(MyDao)context.getService(daoServiceReference);
      }
      
      public void stop(BundleContext context) throws Exception
      {
      System.out.println("Outside Dao Servlet");
      context.ungetService(daoServiceReference);
      }
      
      }
    3. Create a servlet DaoServlet in the package com.sample.DaoServlet. The servlet code looks like :
    4. public class MyServlet extends HttpServlet
      {
      MyService myService;
      protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException
      {
      resp.setContentType("text/html");
      PrintWriter pw = new PrintWriter (resp.getOutputStream());
      pw.println("This servlet is running in an Dao Servlet using OSGi.");
      pw.println("Welcome to my Dao Servlet");
      pw.println("");
      myService.retreiveAllObjects();
      pw.close();
      }

      Dao Servlet is calling the method retrieveAllObjects of MyDao.

    5. Repeat step 3d to register the servlet using extension points.

    First Scenario: We have a method findAllObjects() in MyService interface. This method calls retrieveAllObjects() of MyDao Interface. Both of the interfaces are registered in the service registry.

    Its time to test the work we have done so far. But before we do that, there are some more steps that need to be done .

    • Select a project and click Run As --> Open Run Dialog...
    • Select the arguments tab and add -Dorg.osgi.service.http.port to assign the port number. I chose port 8081 for OSGi. Return to the Bundles tab so that we can select the package dependencies.
    • Click on DeselctAll to deselect all the bundles. Now select all the Workspace bundles.
    • In addition to selecting your projects, select the following bundles:
      • javax.servlet
      • org.apache.commons.logging
      • org.apache.xerces
      • org.apache.xml.resolver
      • org.eclipse.core.jobs
      • org.eclipse.core.runtime.compatibility.registry
      • org.eclipse.equinox.common
      • org.eclipse.equinox.http.jetty
      • org.eclipse.equinox.http.registry
      • org.eclipse.equinox.http.servlet
      • org.eclipse.equinox.registry
      • org.eclipse.osgi
      • org.eclipse.osgi.services
      • org.mortbay.jetty
    • You can now click the run button to launch your OSGi bundle with an embedded Jetty server.
    • Now click on Run As---> OSGi Framework and you should see
      osgi> Jun 23, 2008 10:32:41 AM org.mortbay.http.HttpServer doStart
      INFO: Version Jetty/5.1.x
      Jun 23, 2008 10:32:41 AM org.mortbay.util.Container start
      INFO: Started org.mortbay.jetty.servlet.ServletHandler@1081d2e
      Jun 23, 2008 10:32:41 AM org.mortbay.util.Container start
      INFO: Started HttpContext[/,/]
      Jun 23, 2008 10:32:41 AM org.mortbay.http.SocketListener start
      INFO: Started SocketListener on 0.0.0.0:8081
      osgi>
    • To see the status of the bundles, type ss at the osgi> prompt.This will show the bundle id as well as the status of the bundle. You can start a bundle by typing start .
    • Now if you go to http://localhost:8081/myservlet, you should see something like

      This servlet is running in an Service Servlet using OSGi.
      Welcome to my Service Servlet
      in the OSGi console, you should see the output:

      osgi> Inside findAllObjects of MyService
      Inside retrieveAllObjects of MyDao
    • If you go to http://localhost:8081/daoservlet, you should see something like this

      This servlet is running in an Dao Servlet using OSGi.
      Welcome to my Dao Servlet

      and in the OSGi console, you should see something like this:

      osgi> Inside retrieveAllObjects of MyDao

    Version Management To see how OSGi manages the 2 different versions of the same class, we will create 2 bundles, with the same package and having the same class.

  5. Create a bundle CheckVersion with default Activator. Create a package com.sample.test inside the bundle.
    1. This package has a class Test.java with the method testMethod1().
    2. public class Test {
      public void testMethod1()   {
      System.out.println("Inside Method 1 of Test");
      }
      }
    3. Click on the Runtime tab of the Manifest.MF. Export the package com.sample.test. Click on properties and select the version 1.0.0 of the package.
    4. Uncomment the the call to the Test.test.Method1() in the MyServiceImpl.java of the package com.sample.sampleservice.impl.
    5. In the Manifest.MF of the bundle SampleService, click on the Dependencies tab, and import the package com.sample.test. Select the newly imported package and click on the Properties. This will display a Dialog Box to select the version of the package. Enter 1.0.0 as the version of the selected package.
  6. Create a bundle CheckVersion2 aith default Activator . create a package com.sample.test in the bundle.
    1. Create a class Test.java in this package. This class will have the method testMethod2().
    2. public class Test
      {
      public void testMethod2() {
      System.out.println("Inside Method 2 of Test");
      }
      }
    3. Click on the Runtime tab of the Manifest.MF. Export the package com.sample.test. Click on properties and select the version 2.0.0 of the package.
    4. Uncomment the the call to the Test.test.Method2() in the MyDaoImpl.java.
    5. In the Manifest.MF of the bundle SampleDao, click on the Dependencies tab, and import the package com.sample.test. Select the newly imported package and click on the Properties. This will display a Dialog Box to select the version of the package. Enter 2.0.0 as the version of the selected package.

    Final Scenario We can check to see how the same class with 2 different methods and different versions can be called from inside a package.

    • Select a project and select Run As --> Open Run Dialog. Make sure to select all the packages in the workspace.
    • Click apply and Run.
    • This would open an osgi command prompt. Type ss at the osgi> and it will show a list of the packages.
    • Now if you go to http://localhost:8081/myservlet, you should see something like

      This servlet is running in an Service Servlet using OSGi.
      Welcome to my Service Servlet
      in the OSGi console, you should see the output:
      osgi> inside init method
      Inside findAllObjects of MyService
      test Objectcom.sample.test.Test@194d372
      Inside Method 1 of Test
      Inside retrieveAllObjects of MyDao
      Inside Method 2 of Test
    • If you go to http://localhost:8081/daoservlet, you should see something like this

      This servlet is running in an Dao Servlet using OSGi.
      Welcome to my Dao Servlet

      and in the OSGi console, you should see something like this:
      inside init method
      Inside retrieveAllObjects of MyDao
      Inside Method 2 of Test

    In this post, you learned how to setup the OSGi execution environment and how OSGi uses the service registry to handle dependencies and also about version management. In my next post, I will try to continue from here and write about some other cool features of OSGi.

    REFERENCES:

      http://java.dzone.com/news/there-place-osgitm-enterprise-
      http://java.dzone.com/news/there-place-osgi-enterprise-ap-0
      http://dev2dev.bea.com/pub/a/2007/12/osgi-introduction.html
      http://byteworksinc.blogspot.com/2008/02/summary-this-post-covers-setting-up-an.html

Comments (10)

  1. [...] Ruchika Goyal (Xebia Hollande) qui relate lui aussi son expérience OSGi dans Experimenting with OSGi on Server Side [...]

  2. [...] Experimenting with OSGi on Server Side | Xebia Blog [...]

  3. Gene De Lisa - Reply

    October 17, 2008 at 6:43 pm

    >the intended audience for this blog are people who are new to OSGi.

    But then this Einstein writes:

    >You must already be familiar with how to create a bundle and how to use OSGi commands.

    Incredible.

  4. Eugene - Reply

    October 20, 2008 at 11:05 pm

    I am looking for some idea and stumble upon your posting :) decide to wish you Thanks. Eugene

  5. Shrikant Vashishtha - Reply

    October 21, 2008 at 2:00 pm

    Gene,

    I think you may want to leave the fine tuning part on the blog. The content is really good for beginner level OSGI user otherwise. This is definitely not advanced OSGI stuff and that's what she meant.

  6. Jeryl Cook - Reply

    October 21, 2008 at 6:22 pm

    Great post!

  7. Tommy McGuire - Reply

    October 21, 2008 at 8:26 pm

    Be careful when using context.getServiceReference and context.getService-IIRC, your bundles do not track services that appear and disappear.

    Check out the ServiceTracker for another option.

  8. Sonny - Reply

    October 22, 2008 at 3:54 am

    You might be interested in OSGi articles by Neil Bartlett - http://neilbartlett.name/blog/osgi-articles/
    Great for people just getting started.

    Also have a look at OPS4J Pax tools - http://wiki.ops4j.org/confluence/display/ops4j/Pax, especially Pax Construct and Pax Runner. They make your life a little easier when developing with OSGi.

    I am just curious - is Xebia using OSGi in its projects?

  9. Shrikant Vashishtha - Reply

    October 26, 2008 at 7:12 pm

    Sonny,

    In Xebia we have all kinds of OSGi developers. Some are already using it in their projects and rest of the people always start learning at some point of time. This blog works for people who have just started learning OSGi. Thanks for sharing other references.

  10. Pavel Kaplin - Reply

    October 28, 2008 at 11:12 pm

    Take a look on working thing http://sevenhats.org/

Add a Comment