|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 5
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 the HelloServiceImpl 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 HelloServiceImpl class 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 the ServiceFactory interface and register its object, instead of the actual service object, as a service. Once you do that, your ServiceFactory class will take control whenever any bundle requests the service. ServiceFactory will create a new object of Service 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 the com.javaworld.sample.HelloService bundle developed in the last section to use a ServiceFactory:
HelloServiceFactory.java, as shown in Listing 9.
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);
}
}
ServiceFactory interface defines two methods:
BundleContext.getService(ServiceReference) method. In Listing 9, we use this method to create a different object of HelloServiceImpl 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.
usageCount of the service and print the number of clients for the service.
HelloServiceActivator.java and modify the start() method of your activator so that it will register objects of ServiceFactory instead of HelloService, as shown in Listing 10:
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 HelloWorld bundle is started and zero (0) when the HelloWorld bundle is stopped.
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.
MANIFEST.MF for your HelloWorld bundle to import the org.osgi.util.tracker package.
HelloServiceTracker.java as shown in Listing 11.
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);
}
}
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 the HelloService interface name. The HelloServiceTracker class extends the ServiceTracker class and implements two methods:
Activator.java so that it starts using the HelloServiceTracker class to manage services instead of looking them up directly, as shown in Listing 12.
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();
}
}
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 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.
OSGi open source containers
More
Archived Discussions (Read only)