OSGi - Simple Hello World with services

In this post, we'll develop a simple Hello World application with OSGi. We will use Felix as OSGi container. In the next post, we'll continue with this application and use Spring Dynamic Modules to improve it.

To make the development interesting, we will create two bundles :

  • A bundle providing a service of HelloWorld
  • A bundle consuming the service to print hello at regular interval time.

So let's start with the first bundle. What we need first is a very simple service providing a simple print in the console :

package com.bw.osgi.provider.able;

public interface HelloWorldService {
    void hello();
}
package com.bw.osgi.provider.impl;

import com.bw.osgi.provider.able.HelloWorldService;

public class HelloWorldServiceImpl implements HelloWorldService {
    @Override
    public void hello(){
        System.out.println("Hello World !");
    }
}

We cannot make easier. Then, we need to export the Service using an activator :

package com.bw.osgi.provider;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import com.bw.osgi.provider.able.HelloWorldService;
import com.bw.osgi.provider.impl.HelloWorldServiceImpl;

public class ProviderActivator implements BundleActivator {
    private ServiceRegistration registration;

    @Override
    public void start(BundleContext bundleContext) throws Exception {
        registration = bundleContext.registerService(
                HelloWorldService.class.getName(),
                new HelloWorldServiceImpl(),
                null);
    }

    @Override
    public void stop(BundleContext bundleContext) throws Exception {
        registration.unregister();
    }
}

A lot more code here. For those who aren't confident with OSGi, some explanations. The start method will be called when the module is started and the stop when it's stopped. In the start method, we register our service in the bundle context using the name of the interface as the name of the exported service. The third parameter, null, indicate that we doesn't give any configuration for this service. In the stop method, we just unregister the service.

Now, our first bundle is ready. We can build it. For that we'll use Maven and the maven-bundle-plugin to build the OSGi Bundle directly. Here is the pom.xml file for the project.

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>OSGiDmHelloWorldProvider</groupId>
    <artifactId>OSGiDmHelloWorldProvider</artifactId>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>1.4.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>OSGiDmHelloWorldProvider</Bundle-SymbolicName>
                        <Export-Package>com.bw.osgi.provider.able</Export-Package>
                        <Bundle-Activator>com.bw.osgi.provider.ProviderActivator</Bundle-Activator>
                        <Bundle-Vendor>Baptiste Wicht</Bundle-Vendor>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build> 
</project>

And then, use mvn install to build it.

We'll work in a folder called osgi, so we'll copy this new bundle in the osgi folder.

We can already test it in the OSGi container. If you dont' have already Felix, let's download it here. You have to choose the "Felix Distribution".

Then extract it to the osgi folder we created before. You must now have this folder structure :

osgi
  - felix 
  - OSGiDmHelloWorldProvider-1.0.jar

So we can go in the felix folder and launch Felix :

wichtounet@Linux-Desktop:~/Desktop/osgi/felix$ java -jar bin/felix.jar 
_______________
Welcome to Apache Felix Gogo
g! 

And install our bundle :

g! install file:../OSGiDmHelloWorldProvider-1.0.jar         
Bundle ID: 5

The install is good installed, we can try to start it and see its status :

g! start 5
g! bundle 5
Location             file:../OSGiDmHelloWorldProvider-1.0.jar
State                32
Version              1.0.0
LastModified         1279124741320
Headers              [Tool=Bnd-0.0.357, Bundle-Activator=com.bw.osgi.provider.ProviderActivator, Export-Package=com.bw.osgi.provider.able, Build-Jdk=1.6.0_20, Bundle-Version=1.0.0, Created-By=Apache Maven Bundle Plugin, Bundle-ManifestVersion=2, Manifest-Version=1.0, Bundle-Vendor=Baptiste Wicht, Bnd-LastModified=1279124686551, Bundle-Name=Unnamed - OSGiDmHelloWorldProvider:OSGiDmHelloWorldProvider:bundle:1.0, Built-By=wichtounet, Bundle-SymbolicName=OSGiDmHelloWorldProvider, Import-Package=com.bw.osgi.provider.able,org.osgi.framework;version="1.5"]
BundleContext        org.apache.felix.framework.BundleContextImpl@2353f67e
BundleId             5
SymbolicName         OSGiDmHelloWorldProvider
RegisteredServices   [HelloWorldService]
ServicesInUse        null

All is fine. Our service is good registered :)

Now we'll try to consume this service in our second bundle. Our consumer class will be very simple :

package com.bw.osgi.consumer;

import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import com.bw.osgi.provider.able.HelloWorldService;

public class HelloWorldConsumer implements ActionListener {
    private final HelloWorldService service;
    private final Timer timer;

    public HelloWorldConsumer(HelloWorldService service) {
        super();

        this.service = service;

        timer = new Timer(1000, this);
    }

    public void startTimer(){
        timer.start();
    }

    public void stopTimer() {
        timer.stop();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        service.hello();
    }
}

And now, we must create the activator to get the service and then give it to the consumer. That will give use something like this :

package com.bw.osgi.consumer;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import com.bw.osgi.provider.able.HelloWorldService;

public class HelloWorldActivator implements BundleActivator {
    private HelloWorldConsumer consumer;

    @Override
    public void start(BundleContext bundleContext) throws Exception {
        ServiceReference reference = bundleContext.getServiceReference(HelloWorldService.class.getName());

        consumer = new HelloWorldConsumer((HelloWorldService) bundleContext.getService(reference));
        consumer.startTimer();
    }

    @Override
    public void stop(BundleContext bundleContext) throws Exception {
        consumer.stopTimer();
    }
}

We get a service reference from the bundle context using the name of the class. After that, we get the service instance from the bundle context.

We create also a little pom.xml file to build the bundle :

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>OSGiDmHelloWorldConsumer</groupId>
    <artifactId>OSGiDmHelloWorldConsumer</artifactId>
    <version>1.0</version>
    <packaging>bundle</packaging>

    <dependencies>
        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>1.0.0</version>
        </dependency>

        <dependency>
            <groupId>OSGiDmHelloWorldProvider</groupId>
            <artifactId>OSGiDmHelloWorldProvider</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>OSGiDmHelloWorldConsumer</Bundle-SymbolicName>
                        <Bundle-Activator>com.bw.osgi.consumer.HelloWorldActivator</Bundle-Activator>
                        <Bundle-Vendor>Baptiste Wicht</Bundle-Vendor>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Then, we use mvn install to create the bundle and we install it in the container :

g! start 6
g! Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
Hello World !
g! stop 6

And here we are :) We've created our first application using OSGi. With that technology you can build modules really independant.

In the next post about OSGi, we'll see how to use Spring to make the OSGi development easier and to concentrate our effort on the application not OSGi.

The sources of the two bundles are available here :

Related articles

  • OSGI and Spring Dynamic Modules - Simple Hello World
  • Modular Java – Book Review
  • Bundle non-OSGi dependencies with Maven
  • OSGi 4.2 Entreprise Release is available !
  • JTheque is going to OSGi
  • OSGi and cyclic dependencies
  • Comments

    Comments powered by Disqus