My first service

This example describes how to implement a service and provide its functionality to other bundles.

We will need to create two new projects: CalculatorService will provide methods for performing calculations (service); and CalculatorUser which will represent the client that uses the calculator service.

Calculator Service

We will create CalculatorService with single method add(a, b), which represents our service functionality. First we need to make service interface.

package si.matjazcerkvenik.calculator;

public interface CalculatorService {

public int add(int a, int b);

}

Now we need to provide implementation of calculator interface.

package si.matjazcerkvenik.calculator;

public class CalculatorServiceImpl implements CalculatorService {

public int add(int a, int b) {
return a + b;
}

}

Activator

In start() method of Activator class we need to register calculator service. Service is registered with registerService() method. Method accepts three parameters: name of service interface, instance of service implementation and list of parameters as key/value pairs that provide additional information about the service.

When stop() method is called, service is automatically unregistered from the framework.

package si.matjazcerkvenik.calculator;

import java.util.Hashtable;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

public class Activator implements BundleActivator {

private BundleContext bc = null;

public void start(BundleContext ctx) throws Exception {
bc = ctx;

CalculatorService service = new CalculatorServiceImpl();
ServiceRegistration registration = bc.registerService(
CalculatorService.class.getName(), service, new Hashtable<String, Object>());
System.out.println("Service registered: CalculatorService");
}

public void stop(BundleContext ctx) throws Exception {
bc = null;
}
}

Manifest file

The following manifest file will be included within bundle. It contains Export-Package parameter which makes package of Calculator service available to other bundles.

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

Building a bundle

The following ant file is used to build the project.

<?xml version="1.0" encoding="UTF-8" ?>
<project name="calculatorservice" 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>

Calculator User

So far we created calculator service. Service itself does nothing, just waits for the user to use the service. Now we need to create the user.

Create new project and add framework.jar and calculatorservice.jar to the build path.

Activator

In start() method of Activator class retrieve a service reference. If service reference is successfully retrieved (not null), the service can be used. The result is printed in console. When the service is no longer needed, you should call ungetService() method.

package si.matjazcerkvenik.calculatoruser;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import si.matjazcerkvenik.calculator.CalculatorService;

public class Activator implements BundleActivator {

public static BundleContext bc = null;

public void start(BundleContext bc) throws Exception {
Activator.bc = bc;
ServiceReference<?> reference = bc
.getServiceReference(CalculatorService.class.getName());
if (reference != null) {
CalculatorService service = (CalculatorService) bc.getService(reference);

int a = (int) (5 * Math.random());
int b = (int) (5 * Math.random());
System.out.println("CalculatorService: " + a + " + " + b + " = "
+ service.add(a, b));

bc.ungetService(reference);
} else {
System.out.println("No service available!");
}
}

public void stop(BundleContext bc) throws Exception {
Activator.bc = null;
}
}

Manifest

Notice that manifest file imports the package of calculator service.

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,si.matjazcerkvenik.calculator

Build file

Build the CalculatorUser project.

<?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 service and user bundles

Install both bundles in Knopflerfish OSGI framework. First start calculator service then calculator user. In console you should see the result.

Although the service works, it can only serve as an example how services are made, registered and used. This approach has many drawbacks.
The calculator user has to be restarted every time, when you wish to perform calculation. Also the calculator user has to be restarted if service is not available at the moment.
Framework solves this problems for us. Framework can notify the bundles when new service is registered. In next example we will see how ServiceListener works.