Using ServiceTracker

Purpose of ServiceTracker is similar to ServiceListener. It is called when specific services are started or stopped.

This example is the same as previous, just instead of ServiceListener, we will implement ServiceTracker interface.

Calculator user thread

This thread periodically calls add() method from the calculator service.

package si.matjazcerkvenik.calculatoruser;

import si.matjazcerkvenik.calculator.CalculatorService;


public class CalculatorUserThread extends Thread {

private CalculatorService cs = null;

public CalculatorUserThread(CalculatorService s) {
cs = s;
}

private boolean running = true;

@Override
public void run() {

while (running) {

int a = (int) (5 * Math.random());
int b = (int) (5 * Math.random());

System.out.println("CalculatorService: " + a + " + " + b + " = "
+ cs.add(a, b));

try {
sleep(3000);
} catch (InterruptedException e) {
}

}

}

public void stopThread() {
running = false;
}

}

MyCustomTracker

Class MyCustomTracker must implement ServiceTrackerCustomizer interface and provide implementation of the methods: addingService(), modifiedService() and removedService() which are called when service is started, modified or stopped.

package si.matjazcerkvenik.calculatoruser;

import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import si.matjazcerkvenik.calculator.CalculatorService;

public class MyCustomTracker implements ServiceTrackerCustomizer {

private CalculatorService cs = null;
private CalculatorUserThread t = null;

public Object addingService(ServiceReference arg0) {
System.out.println("addingService");
cs = (CalculatorService) Activator3.bc.getService(arg0);
if (t == null) {
startUserThread();
return cs;
}
return cs;
}

public void modifiedService(ServiceReference arg0, Object arg1) {

System.out.println("modifiedService");
stopUserThread();
cs = (CalculatorService) Activator3.bc.getService(arg0);
startUserThread();

}

public void removedService(ServiceReference arg0, Object arg1) {
System.out.println("removedService");
stopUserThread();
}

public void startUserThread() {
t = new CalculatorUserThread(cs);
t.start();
}

public void stopUserThread() {
if (t == null) {
return;
}
t.stopThread();
try {
t.join();
} catch (InterruptedException e) {
}
cs = null;
t = null;
}

}

Activator

In activator class MyCustomTracker object must be passed to the ServiceTracker object.

package si.matjazcerkvenik.calculatoruser;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.util.tracker.ServiceTracker;

import si.matjazcerkvenik.calculator.CalculatorService;

public class Activator implements BundleActivator {

public static BundleContext bc = null;
private ServiceTracker tracker = null;

public void start(BundleContext ctx) throws Exception {
bc = ctx;
System.out.println(bc.getBundle().getHeaders()
.get(Constants.BUNDLE_NAME)
+ " starting...");

tracker = new ServiceTracker(bc, CalculatorService.class.getName(), new MyCustomTracker());
tracker.open();
}

public void stop(BundleContext arg0) throws Exception {
System.out.println(bc.getBundle().getHeaders()
.get(Constants.BUNDLE_NAME)
+ " stopping...");
tracker.close();
bc = null;

}

}

Manifest

In manifest file you need to add the package of the tracker to the Import-Package parameter.

Manifest-Version: 2.0
Bundle-Name: calculatoruser
Bundle-SymbolicName: calculatoruser
Bundle-Version: 1.0.0
Bundle-Description: OSGi example
Bundle-Vendor: Knopflerfish
Bundle-Activator: si.matjazcerkvenik.calculatoruser.Activator
Bundle-Category: example
Import-Package: org.osgi.framework,org.osgi.util.tracker,si.matjazcerkvenik.calculator

Build project

Build the project with the following Ant build file.

<?xml version="1.0" encoding="UTF-8" ?>
<project name="calculatoruser" default="all" >

<property name="lib.dir" location="lib" />

<target name="all" depends="clean,init,compile,jar" />

<target name="init" >
<mkdir dir="build/classes" />
</target>

<target name="compile" >
<javac destdir="build/classes" debug="on" srcdir="src" >
<classpath>
<fileset dir="${lib.dir}" includes="**/*.jar" />
</classpath>
</javac>
</target>

<target name="jar" >
<jar basedir="build/classes" jarfile="dist/${ant.project.name}.jar"
compress="true" includes="**/*" manifest="META-INF/manifest.mf" />
</target>

<target name="clean" >
<delete dir="build" />
</target>
</project>

Deploying

Deploy the bundle in the framework. Make sure that also CalculatorService bundle is deployed.
Start each bundle. Again it is not important which bundle is started first. CalculatorUser bundle will start working when CalculatorService will be available.