March 31, 2010

OSGI Tutorial - Dynamic Usage of ServiceTracker

« OSGI Tutorial and Running Example | Main | SSH Port Forwading and Tunneling »

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.

Regards
Rafael Sobek

Technorati Tags:

Posted by rafael.sobek at 6:50 AM in OSGI

 

[Trackback URL for this entry]

Comment: Baptiste Wicht at Mi, 31 Mrz 9:43 AM

Really interesting.

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

Thanks

Pingback: Java Links of the week | @Blog("Baptiste Wicht") at So, 4 Apr 12:30 PM

OSGI Tutorial - Dynamic Usage of ServiceTracker
clean implementation of Chain of Responsibility, by James Sugrue Dynamic Usage of ServiceTracker : Rafael Sobek show a way to use

Pingback: Java Links of the week | @Blog("Baptiste Wicht") at So, 4 Apr 12:30 PM

OSGI Tutorial - Dynamic Usage of ServiceTracker
clean implementation of Chain of Responsibility, by James Sugrue Dynamic Usage of ServiceTracker : Rafael Sobek show a way to use

Comment: Na_D at Di, 25 Mai 12:28 PM

A very neat post indeed but is there any way so that we can have a two way service registry i.e. two bundles using the services of each other.

Comment: Na_D at Di, 25 Mai 12:31 PM

A neat post nice ... but I just wanted to know is there any way so that we can have a two way service registry..i.e two bundles using the services of each other registered dynamically

Comment: devrim baris acar at Mi, 15 Dez 1:58 PM

I guess there should be some other way of binding services instead of exploiting my domain service class with infrastructure glue code.

Comment: Ordos at Mi, 3 Aug 9:45 PM

Great article, indeed. I have a short question: Doesn't the ServiceTrackerCustomizer lead to the same result as when extending the ServiceTracker (as done here)?

Trackback: Arun at Mo, 21 Mai 6:32 AM

Arun
OSGI Tutorial - Dynamic Usage of ServiceTracker

Your comment:

(not displayed)
 
 
 

Live Comment Preview:

 
 
test