Click here to Skip to main content
15,889,877 members
Articles / All Topics

OSGI for Beginners Using Maven with Equinox (HowTo)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
2 Jun 2011Apache4 min read 21.4K   2   2
OSGI for beginners Using Maven with Equinox (HowTo)

I have struggled to understand what OSGI really means for a long time. It has been around since a very long time but not many people are aware of it. It has been hyped as a very complex technology to understand. Here is my attempt to make it simple for any Java Developer. In my view, if you understand the concept of Interface, JNDI or EJB (or registering some service in some form), you will understand OSGI. In short, OSGI is a Container where you can register your services through interfaces and those can be accessed any time. Another benefit of OSGI is that all these services can be Installed/Uninstalled/Started/Stopped at runtime (i.e., code can be hot deployed at runtime) rather than normal requirement we have where we have restart J2EE server. Similar to J2ee containers (Tomcat, WebSphere, Jboss , Weblogic), OSGI also has a container like Equinox (which is base for Eclipse), Apache Felix, etc.

In this article, I’m going to explain OSGI with Eclipse Equinox container. Anyone who has Eclipse IDE installed on their machine has OSGI container also installed in Eclipse plugin’s folder.

Name of OSGI container jar file looks like org.eclipse.osgi_<version>.jar.

You can start OSGI like this:

java -jar org.eclipse.osgi_3.5.2.R35x_v20100126.jar -console

Attached is sample screenshot of how I started my OSGI container (It's analogous to starting tomcat).

Image 1

Now that we started OSGI , let me start creation a HelloWorld OSGI Application using Maven. Let me show you my project structure first and then display my pom.xml.

Image 2
Now I’ll display my pom.xml. My pom.xml has 2 more profiles added to create 2 more new modules (MathService and MathServiceClient) which will be later explained in this article.

XML
<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>com.linkwithweb.osgi</groupId>
	<artifactId>HelloWorld</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>HelloWorld</name>
	<dependencies>
		<dependency>
			<groupId>org.osgi</groupId>
			<artifactId>org.osgi.core</artifactId>
			<version>4.2.0</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>HelloWorld-${version}</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.1</version>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<configuration>
					<archive>
						<manifestFile>src/main/
						resources/META-INF/MANIFEST.MF</manifestFile>
					</archive>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<profiles>
		<profile>
			<id>MathService</id>
			<build>
				<finalName>MathService-${version}</finalName>
				<plugins>
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-compiler-plugin</artifactId>
						<version>2.3.1</version>
						<configuration>
							<source>1.5</source>
							<target>1.5</target>
						</configuration>
					</plugin>

					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-jar-plugin</artifactId>
						<configuration>

							<excludes>
								<exclude>**/*.xml</exclude>
								<exclude>**/*.bsh</exclude>
								<exclude>**/*.properties</exclude>
							</excludes>
							<archive>
								<manifestFile>src/main/resources/
								MathService/META-INF/MANIFEST.MF</manifestFile>
							</archive>
						</configuration>
					</plugin>

				</plugins>
			</build>
		</profile>
		<profile>
			<id>MathServiceClient</id>
			<build>
				<finalName>MathServiceClient-${version}</finalName>
				<plugins>
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-compiler-plugin</artifactId>
						<version>2.3.1</version>
						<configuration>
							<source>1.5</source>
							<target>1.5</target>
						</configuration>
					</plugin>

					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-jar-plugin</artifactId>
						<configuration>

							<excludes>
								<exclude>**/*.xml</exclude>
								<exclude>**/*.bsh</exclude>
								<exclude>**/*.properties</exclude>
							</excludes>
							<archive>
								<manifestFile>src/main/resources/
								MathServiceClient/META-INF/MANIFEST.MF</manifestFile>
							</archive>
						</configuration>
					</plugin>

				</plugins>
			</build>
		</profile>
	</profiles>

</project>

Now if you observe pom.xml, there are 3 different MANIFEST.MF defined for 3 different OSGI bundles we create. Saying so, let me explain to you that OSGI bundles are the same as Java jar file with its configuration defined in Manifest file of standard jar. OSGI defined few entries in manifest file which are related to OSGI which are read by container to activate the bundle, thus avoiding learning of any new metadata format we generally have for other frameworks.

Here is a sample Manifest.MF I have defined for MathServiceClient.

Manifest-Version: 1.0
Bundle-Name: MathServiceClient
Bundle-Activator: com.linkwithweb.osgi.service.client.MathServiceClientActivator
Bundle-SymbolicName: MathServiceClient
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework,com.linkwithweb.osgi.service

If you observe the above manifest file, you can observe that all the entries except Manifest-Version are OSGI specific entries. These are the entries which define how to deploy a bundle, what all it is dependent on and what are extension points it exposes for other services to consume, etc.

Having explained this. let me first explain a HelloWorld bundle with its MANIFEST.MF and Activator class and its installation into Equinox OSGI Container.

Java
/**
 *
 */
package com.linkwithweb.osgi;

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

/**
 * @author Ashwin Kumar
 *
 */
public class HelloActivator implements BundleActivator {
	public void start(BundleContext context) {
		System.out.println("Hello World");
	}

	public void stop(BundleContext context) {
		System.out.println("Goodbye All");
	}
}
Manifest-Version: 1.0
Bundle-Name: HelloWorld
Bundle-Activator: com.linkwithweb.osgi.HelloActivator
Bundle-SymbolicName: HelloWorld
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework

Now run “mvn clean package” to build our bundle.

It will create HelloWorld-0.0.1-SNAPSHOT.jar in target folder and we can install that into Equinox to test. Here is the image which shows how to install and start our HelloWorld into Equinox.

Image 3

install file:K:\Ashwin\OSGI\MavenProject\target\HelloWorld-0.0.1-SNAPSHOT.jar

If you observe the above screenshot, you can use install command to install the bundle and use the start command on bundle id to start the bundle.

On start of Bundle start method of Activator class is called and while stopping bundle stop method of Activator is called and so you are seeing HelloWorld.

Congratulations! You have learned the basics of OSGI and you have just deployed your first bundle.

Now let me explain my second part of the article which explains how to Expose and Consume services of modules.

Exposing and Consuming Services

To explain this, I’ll take a very simple example where I’ll publish a service which can add 2 numbers.

Here is the code which does that.

First, we need to define an Interface which we are thinking of exposing to external bundles:

Java
/**
 *
 */
package com.linkwithweb.osgi.service;

/**
 * @author Ashwin Kumar
 *
 */
public interface MathService {

	/**
	 * @param a
	 * @param b
	 * @return
	 */
	public int add(int a, int b);
}

Now the implementation Class:

Java
/**
 *
 */
package com.linkwithweb.osgi.service;

/**
 * @author Ashwin Kumar
 *
 */
public class MathServiceImpl implements MathService {

	/* (non-Javadoc)
	 * @see com.linkwithweb.osgi.service.MathService#add(int, int)
	 */
	public int add(int a, int b) {
		// TODO Auto-generated method stub
		return a+b;
	}
}

Now Activator class which registers this service with OSGI container:

Java
/**
 *
 */
package com.linkwithweb.osgi.service;

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

/**
 * @author Ashwin Kumar
 *
 */
public class MathServiceActivator implements BundleActivator {
	/*
	 * (non-Javadoc)
	 *
	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) {
		MathService service = new MathServiceImpl();
		// Third parameter is a hashmap which allows to configure the service
		// Not required in this example
		context.registerService(MathService.class.getName(), service, null);
		System.out.println("Math Service Registered");
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) {
		System.out.println("Goodbye From math service");
	}
}

Here is the manifest file which exposes service:

Manifest-Version: 1.0
Bundle-Name: MathService
Bundle-Activator: com.linkwithweb.osgi.service.MathServiceActivator
Bundle-SymbolicName: MathService
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework
Export-Package: com.linkwithweb.osgi.service

If you observe this, we are Exporting some packages so that they can be consumed later. Also, all the packages that we are thinking of importing have to be defined here.

Use the following command to build the jar file:

mvn -PMathService package

and here is the image which displays how to Install and Run the service.

Image 4

Now let me explain how to implement consumer:

Java
/**
 *
 */
package com.linkwithweb.osgi.service.client;

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

import com.linkwithweb.osgi.service.MathService;

/**
 * @author Ashwin Kumar
 *
 */
public class MathServiceClientActivator implements BundleActivator {
	MathService service;
	private BundleContext context;

	/*
	 * (non-Javadoc)
	 *
	 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) {
		this.context = context;
		// Register directly with the service
		ServiceReference reference = context
				.getServiceReference(MathService.class.getName());
		service = (MathService) context.getService(reference);
		System.out.println(service.add(1, 2));
	}	/*
	 * (non-Javadoc)
	 *
	 * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) {
		System.out.println(service.add(5, 6));
	}
}

And now manifest file:

Manifest-Version: 1.0
Bundle-Name: MathServiceClient
Bundle-Activator: com.linkwithweb.osgi.service.client.MathServiceClientActivator
Bundle-SymbolicName: MathServiceClient
Bundle-Version: 1.0.0
Import-Package: org.osgi.framework,com.linkwithweb.osgi.service

Now here is how we create package and install:

mvn -PMathServiceClient package

Image 5

Source code has been checked in to the following location:

Enjoy creating OSGI bundles. The main benefit is that you can redeploy your bundles/services at runtime.

Mail me in case you have any doubts.

Image 6 Image 7 Image 8 Image 9 Image 10 Image 11 Image 12 Image 13

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Chief Technology Officer Northalley
United States United States
A Technology evangelist with no technical language barriers. A strong believer that Simple Sofware Is Perfect Software. A staunch proponent of software / documentation automation in all domain's. And finally a true diciple of Google Search.

Comments and Discussions

 
GeneralFeedback Pin
Member 1024344430-Aug-13 13:28
Member 1024344430-Aug-13 13:28 
GeneralMy vote of 5 Pin
Ata Amini13-Mar-12 11:02
Ata Amini13-Mar-12 11:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.