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 :
Comments
Comments powered by Disqus