Hello, OSGi, Part 1: Bundles for beginners

Creating, executing, and managing bundles in an OSGi container

1 2 3 4 5 Page 4
Page 4 of 5

Class-level scope

If you try running the sample service package now it will print "Hello World" on your Eclipse console. If you try running Activator.java to access HelloServiceImpl.java and compile it with the normal javac complier, it will compile. If you try to execute this bundle in an OSGi container, however, it will throw an exception.

How is the OSGi container able to hide a few classes from the .jar file while others are visible? The answer is that the OSGi container uses the Java class loader to manage class visibility. The OSGi container creates a different class loader for every bundle. The bundle can therefore access classes from

  • Boot classpath: Contains the java.* packages.
  • Framework classpath: Usually has a separate class loader for the framework implementation classes as well as key service interface classes.
  • Bundle space: Consists of the JAR file that is associated with the bundle plus any additional JARs that are closely tied to the bundle, like fragments.
  • Imported packages: For instance, the HelloWorld bundle imports the com.javaworld.sample.service package so it can access classes from that package.

The bundle-level scope is a powerful feature allowing you (for instance) to safely change the HelloServiceImpl.java class without worrying that dependent code might break.

OSGi services

As previously mentioned, the OSGi architecture is a very good candidate for implementing service-oriented applications. It allows bundles to export services that can be consumed by other bundles without knowing anything about the exporting bundle. Taken with the ability to hide the actual service implementation class, OSGi provides a perfect combination for service-oriented applications.

In OSGi, a source bundle registers a POJO (you don't have to implement any interfaces or extend from any superclass) with the OSGi container as a service under one or more interfaces. The target bundle can then ask the OSGi container for services registered under a particular interface. Once the service is found, the target bundle binds with it and can start calling its methods. As with other OSGi concepts, a sample application will make all of this more clear.

Exporting services

In this section we will change the HelloService bundle so that it exports objects of the HelloServiceImpl.java class as a service. Here are the steps to set up the sample application:

  1. Change the MANIFEST.MF for com.javaworld.sample.HelloService to import the org.osgi.framework package.
  2. Create the

    com.javaworld.sample.service.impl.HelloServiceActivator.java

    as shown in Listing 7.

    Listing 7. Create HelloServiceActivator.java

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

    Note that the source bundle should use the

    BundleContext.registerService()

    method to export the service. It takes three parameters:

    • The name of the interface under which you want to register the service. If you want to register the service under multiple interfaces then you should create a String array of interface names and pass it as your first argument. In the sample code we want to export the service under the name of HelloService interface.
    • The actual Java object that you want to register as a service. In our sample code we are exporting objects of the HelloServiceImpl class as the service.
    • Properties of the service, in this case a Dictionary object. If more than one bundle exports a service under the same interface name then the target object can use these properties to filter out the service that it is interested in.
  3. The last step is to change the MANIFEST.MF file of the HelloService bundle to declare HelloServiceActivator as the bundle's activator class. To do that, simply add com.javaworld.sample.service.impl.HelloServiceActivator as the value of the Bundle-Activator header in your MANIFEST.MF file.

Now the HelloService bundle is ready to export objects of the HelloServiceImpl class. When the OSGi container starts the HelloService bundle it will pass control to HelloServiceActivator.java, which will register an object of HelloServiceImpl as a service. The next step is to create the service consumer.

Importing the service

In this section we will change the HelloWorld bundle developed in the last section so that it acts as a consumer of the HelloService service. The main thing you need to do is change the Activator.java for the HelloWorld bundle as shown in Listing 8.

Listing 8. HelloWorldActivator.java

public class Activator implements BundleActivator {
    ServiceReference helloServiceReference;
    public void start(BundleContext context) throws Exception {
        System.out.println("Hello World!!");
        helloServiceReference= context.getServiceReference(HelloService.class.getName());
        HelloService helloService =(HelloService)context.getService(helloServiceReference);
        System.out.println(helloService.sayHello());

    }
    public void stop(BundleContext context) throws Exception {
        System.out.println("Goodbye World!!");
        context.ungetService(helloServiceReference);
    }
}

The BundleContext.getServiceReference() method returns a ServiceReference object for a service registered under the HelloService interface. If multiple such services exist, the service with the highest ranking (as specified in its Constants.SERVICE_RANKING property) is returned. Once you have the object of ServiceReference you can call its BundleContext.getService() method to get the actual service object.

You can run this sample the same way you would execute any bundle, by clicking Run --> Run Simply make sure that both the HelloWorld and HelloService bundles are checked in as plugins. When you start the HelloService bundle, you will see the message "Inside HelloServiceImple.sayHello()" printed from the HelloServiceImpl.sayHello() method.

1 2 3 4 5 Page 4
Page 4 of 5