Hello World! Using OSGi Framework – Part V

Previous: Hello World! Using OSGi Framework – Part IV

Creating a service factory

In the last section you learned how to use the OSGi framework to create a Java object and register it as service to be consumed by any other bundle. If you look at the HelloServiceActivator.start()method you will notice that we created an object of theHelloServiceImpl class in the start method and registered it under the name of HelloService interface. Thereafter, whenever any bundle asks for the HelloService service, the OSGi container will return the same object.

This implementation will work for most common use cases. But let’s say you want to return a different object of the HelloServiceImplclass for every consumer bundle. Alternately, let’s say your service object needs to open a connection to a database and you don’t want to open the connection unless someone really needs the service.

In either case, the solution is to create a class implementing theServiceFactory interface and register its object, instead of the actual service object, as a service. Once you do that, yourServiceFactory class will take control whenever any bundle requests the service. ServiceFactory will create a new object ofService for every bundle, and will also delay creation of the actual service until someone really needs it.

Follow these steps to change the implementation of thecom.javaworld.sample.HelloService bundle developed in the last section to use a ServiceFactory:

  1. Create the factory classHelloServiceFactory.java, as shown in Listing 9.

    Listing 9. Create HelloServiceFactory.java

  2. public class HelloServiceFactory implements ServiceFactory{
        private int usageCounter = 0;
        public Object getService(Bundle bundle, ServiceRegistration registration) {
            System.out.println("Create object of HelloService for " + bundle.getSymbolicName());
            usageCounter++;
            System.out.println("Number of bundles using service " + usageCounter);
            HelloService helloService = new HelloServiceImpl();
            return helloService;
        }
        public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
            System.out.println("Release object of HelloService for " + bundle.getSymbolicName());
            usageCounter--;
            System.out.println("Number of bundles using service " + usageCounter);
        }
    }
  3. The ServiceFactory interface defines two methods:
    • getService(): The OSGi framework invokes this method the first time the specified bundle requests a service object using theBundleContext.getService(ServiceReference) method. In Listing 9, we use this method to create a different object ofHelloServiceImpl for every bundle, and we return that object. The OSGi framework caches the value returned (unless it is null), and will return the same service object on any future calls to BundleContext.getService() from the same bundle.
    • ungetService(): The OSGi container invokes this method when a service has been released by a bundle. The service object may then be destroyed. In Listing 9, we use this method to reduce the usageCount of the service and print the number of clients for the service.
  4. Change HelloServiceActivator.java and modify the start() method of your activator so that it will register objects ofServiceFactory instead of HelloService, as shown in Listing 10:

    Listing 10. Changes to HelloServiceActivator.java

public class HelloServiceActivator implements BundleActivator  {
    ServiceRegistration helloServiceRegistration;
    public void start(BundleContext context) throws Exception {
        HelloServiceFactory helloServiceFactory = new HelloServiceFactory();
        helloServiceRegistration =context.registerService(HelloService.class.getName(), helloServiceFactory, null);
    }
    public void stop(BundleContext context) throws Exception {
        helloServiceRegistration.unregister();
    }
}

Now try running this sample code. You should notice that it prints the service usage count as one (1) when HelloWorldbundle is started and zero (0) when the HelloWorld bundle is stopped.

Tracking services

In the “OSGi services” section you learned how to search for a service using its interface name. But what happens if more than one bundle registers a service under the same interface name? In that case the OSGi container will return the service with the highest ranking — that is, the service that is registered with the highest valued SERVICE_RANKING property. If more than one service has an equally valued SERVICE_RANKING property, then the OSGi container will return the service with the lowest PID.

But let’s say that you are creating a consumer that needs to know whenever an object is registered or unregistered under a particular interface. In this situation, you should use the ServiceTracker class. Let’s see what happens when we change the sample code to utilize a service tracker, as described below.

  1. Change the MANIFEST.MF for your HelloWorld bundle to import the org.osgi.util.tracker package.
  2. Create HelloServiceTracker.java as shown in Listing 11.

    Listing 11. HelloServiceTracker.java

  3. public class HelloServiceTracker extends ServiceTracker {
        public HelloServiceTracker(BundleContext context) {
            super(context, HelloService.class.getName(),null);
        }
        public Object addingService(ServiceReference reference) {
            System.out.println("Inside HelloServiceTracker.addingService " + reference.getBundle());
            return super.addingService(reference);
        }
        public void removedService(ServiceReference reference, Object service) {
            System.out.println("Inside HelloServiceTracker.removedService " + reference.getBundle());
            super.removedService(reference, service);
        }
    }
  4. As you can see in the constructor of the HelloServiceTracker class, we are passing the name of the HelloService interface to its super class, which is the equivalent of saying that HelloServiceTracker should track services registered under theHelloService interface name. The HelloServiceTracker class extends the ServiceTracker class and implements two methods:
    • addingService() is called when a bundle registers a service under the given interface name.
    • removedService() is called when a bundle unregisters a service under the given interface name.
  5. Change Activator.java so that it starts using the HelloServiceTracker class to manage services instead of looking them up directly, as shown in Listing 12.

    Listing 12. Activator.java uses HelloServiceTracker

  6. public class Activator implements BundleActivator {
        HelloServiceTracker helloServiceTracker;
        public void start(BundleContext context) throws Exception {
            System.out.println("Hello World!!");
            helloServiceTracker= new HelloServiceTracker(context);
            helloServiceTracker.open();
            HelloService helloService = (HelloService)helloServiceTracker.getService();
            System.out.println(helloService.sayHello());
    
        }
        public void stop(BundleContext context) throws Exception {
            System.out.println("Goodbye World!!");
            helloServiceTracker.close();
        }
    }
  7. In the initial start() method we first create a HelloServiceTracker object, then we ask HelloServiceTracker to start tracking the underlying service. A call to getService() will now get the HelloService object.

If you try executing this sample you will notice that whenever you start or stop the HelloService bundle it will result in a call to either the addingService() or removedService() method of the HelloServiceTracker object.

In conclusion

In this first article in the three-part Hello, OSGi series, I’ve introduced you to the basic concepts of modular application development with OSGi. You’ve learned about the three currently available open source OSGi containers and walked through the steps to develop a simple component bundle using Equinox, the fully OSGi-compliant Eclipse container. You’ve also learned how bundles can interact by importing and exporting each other’s packages and services.

In this article you may have noticed one of the challenges of developing OSGi bundles: that each of your bundles needs to be aware of OSGi AP. In some development scenarios this could mean writing a lot of infrastructure code. In the next article in the Hello, OSGi series I’ll introduce you to the Spring Dynamic Modules for OSGi Service Platforms project, which simplifies development of Spring-based OSGi bundles. See the Resources section in the meantime, to learn more about OSGi.

Source: http://www.javaworld.com/javaworld/jw-03-2008/jw-03-osgi1.html

About javarchive

I'm swimming into the depth of Java world
This entry was posted in Archives. Bookmark the permalink.

1 Response to Hello World! Using OSGi Framework – Part V

  1. Pingback: Hello World! Using OSGi Framework – Part IV | Java Archives

Leave a comment