ServiceTracker Introduction
Sometimes an OSGI bundle wants to access a dependent OSGI Service, which wasn't registered yet. Further it should be possible to start a bundle during dependent bundles and services aren't deployed yet. The org.osgi.util.tracker.ServiceTracker class is an utility class for grabbing services. It will be started by calling the open() method and stops by calling the close() method. The ServiceTracker constructor expects the BundleContext and tracked service class name. With the getService method you get required services.
public class Activator implements BundleActivator {
private ServiceTracker tracker;
public void start(BundleContext context) {
tracker = new ServiceTracker(context, MyClass.class.getName(), null);
tracker.open();
//tracker.getService
}
public void stop(BundleContext context) {
tracker.close();
}
}
Dynamic Usage of ServiceTracker
More interesting way is to use the callback methods of the ServiceTracker class. For that you have to extend from the ServiceTracker class and override the callback methods. So you can react event oriented on service registrations of another bundles.That's a way to implement the Whiteboard pattern.
public class MyTracker extends ServiceTracker {
public MyTracker(BundleContext context) {
//tracks classes of a certain type
super(context, MyClass.class.getName(), null);
}
// callback method if MyClass service object is registered
public Object addingService(ServiceReference reference) {
...
// return service object
}
// callback if necessary class is deregistred
public void removedService(ServiceReference reference, Object service) {
...
}
}
ServiceTracker Example
MathService API Bundle
This bundle contains the IMathService interface. It's necessary to starts the MathService Consumer Bundle in OSGI runtime.
package org.developers.blog.mathservice.api;
public interface IMathService {
int sum(int a, int b);
}
MathService Consumer Bundle
MathServiceConsumer class
This class use the MathService object. Every 10 seconds the implemented Timer checks if a MathService is set or not.
package org.developers.blog.mathservice.consumer;
import java.util.Timer;
import java.util.TimerTask;
import org.developers.blog.mathservice.api.IMathService;
public class MathServiceConsumer {
private IMathService mathService = null;
public IMathService getMathService() {
return mathService;
}
public void setMathService(IMathService mathService) {
this.mathService = mathService;
}
public MathServiceConsumer() {
//timer, that checks if MathService is registered on OSGI runtime
int delay = 1000;
int period = 10000;
Timer timer = new Timer();
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
if (mathService == null) {
System.out.println("MathService wasn't registered.");
} else {
System.out.println("MathService is registered.");
System.out.println("Result of 1+1 is " + mathService.sum(1, 1));
}
}
}, delay, period);
}
}
ServiceTracker Implementation - MathServiceTracker
This ServiceTracker implementation reacts on addition, updating or removing of the IMathService-ServiceReferences of the MathService Producer Bundle in OSGI container. It adds or removes registered MathService objects to the MathServiceConsumer class.
package org.developers.blog.mathservice.consumer;
import org.developers.blog.mathservice.api.IMathService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
public class MathServiceTracker extends ServiceTracker {
private MathServiceConsumer mathServiceConsumer;
public MathServiceTracker(
BundleContext bundleContext,
MathServiceConsumer mathServiceConsumer) {
super(bundleContext, IMathService.class.getName(), null);
this.mathServiceConsumer = mathServiceConsumer;
}
@Override
public Object addingService(ServiceReference reference) {
System.out.println("hello");
IMathService mathService = (IMathService)context.getService(reference);
mathServiceConsumer.setMathService(mathService);
return mathService;
}
@Override
public void modifiedService(ServiceReference sr, Object o) {
this.mathServiceConsumer.setMathService(null);
IMathService mathService = (IMathService)context.getService(sr);
this.mathServiceConsumer.setMathService(mathService);
}
@Override
public void removedService(ServiceReference reference, Object service) {
IMathService mathService = (IMathService)service;
//for clean up
this.mathServiceConsumer.setMathService(null);
context.ungetService(reference);
}
}
Activator
The Activator starts and close the MathServiceTracker.
package org.developers.blog.mathservice.consumer;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator {
private MathServiceTracker mathServiceTracker;
public void start(BundleContext bundleContext) throws Exception {
MathServiceConsumer consumer = new MathServiceConsumer();
mathServiceTracker =
new MathServiceTracker(bundleContext, consumer);
mathServiceTracker.open();
}
public void stop(BundleContext bundleContext) throws Exception {
mathServiceTracker.close();
}
}
MathService Producer Bundle
This bundle contains a class which implements the IMathService interface and registers the service in usual way.
package org.developers.blog.mathservice.producer;
import org.developers.blog.mathservice.api.IMathService;
public class MathService implements IMathService {
public int sum(int a, int b) {
return a + b;
}
}
package org.developers.blog.mathservice.producer;
import org.developers.blog.mathservice.api.IMathService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
public class Activator implements BundleActivator {
private ServiceRegistration serviceRegistration;
public void start(BundleContext bundleContext) throws Exception {
MathService mathService = new MathService();
serviceRegistration = bundleContext.registerService(
IMathService.class.getName(), mathService, null
);
}
public void stop(BundleContext bundleContext) throws Exception {
serviceRegistration.unregister();
}
}
Installation and Starting Example
rafsob@rafsob-desktop:~/projects/math-service-consumer-bundle$ mvn pax:provision ... MathService wasn't registered. MathService wasn't registered. MathService wasn't registered. MathService wasn't registered. start file:///home/rafsob/.m2/repository/org/developers/blog/math-service-producer-bundle/1.0-SNAPSHOT/math-service-producer-bundle-1.0-SNAPSHOT.jar MathService is registered. Result of 1+1 is 2
Full example can be download here. Have a look to another basic OSGI tutorial with a running example.
RegardsRafael Sobek
Technorati Tags: OSGI ServiceTracker Whiteboard

Really interesting.
I've neved thinked to use the ServiceTracker like that, but effectively, that's a powerful way to use it.
Thanks