by Lars Vogel

Follow me on twitter

Lars Vogel on Google+

OSGi with Eclipse Equinox - Tutorial

Lars Vogel

Version 3.4

25.01.2012

Revision History
Revision 0.1 03.09.2007 Lars
Vogel
Created
Revision 0.2 - 3.4 25.10.2008 - 25.01.2012 Lars
Vogel
bugfixes and enhancements

OSGi with Eclipse Equinox

This tutorial gives an overview of OSGi. It explains the creation and consumption of OSGi services via ServiceTrackers and declarative services. Eclipse Equinox is used as an standalone OSGi server. For this tutorial Eclipse 4.2 (Juno) is used.


Table of Contents

1. OSGi Overview
1.1. What is OSGi
1.2. Implementations
2. OSGi Bundles and Dependencies
2.1. OSGi bundles
2.2. Bundle-SymbolicName and Version
2.3. MANIFEST.MF
2.4. Bundle dependencies and public API
2.5. OSGi dependency management
2.6. Bundle Lifecycle
3. Eclipse Equinox
4. OSGi console
4.1. OSGI console commands
4.2. Access to the Eclipse OSGi console
5. Installation
5.1. Java
5.2. Download the Eclipse plug-in package
5.3. Update an Eclipse Java IDE
6. Tutorial: Your first OSGi bundle
6.1. Create a new Bundle
6.2. Coding
6.3. Run
6.4. Export your bundle
7. Running a standalone OSGI server
8. OSGi Services
8.1. Overview
8.2. BundleContext
8.3. Registering services
8.4. Accessing a services
8.5. Best practices for defining services
8.6. OSGi Service Tracker
8.7. Problems with service tracker
9. Tutorial: Define a Service and service consumption
9.1. Define the service interface
9.2. Create service
9.3. Install service bundles
9.4. Use your service
9.5. Use your service with a service tracker
10. Declarative OSGiServices
10.1. Overview
10.2. Required bundles
10.3. Definition of a DS service
11. Tutorial: Define a declarative OSGi Service
12. Tutorial: Using services via declarative services
13. Bndtools
14. Thank you
15. Questions and Discussion
16. Links and Literature
16.1. Source Code
16.2. OSGi Resources
16.3. vogella Resources

1. OSGi Overview

1.1. What is OSGi

OSGi is a specification. The core of the OSGi specification defines a component and service model for Java. The components and services can be dynamically activated, de-activated, updated and de-installed.

A very practical advantage of OSGi is that every bundle must define its exported Java packages and its required dependencies. This way you can effectively control the provided API and the dependencies of your plug-ins.

1.2. Implementations

OSGi has several implementations, for example Knopflerfish OSGi or Apache Felix.

2. OSGi Bundles and Dependencies

2.1. OSGi bundles

The OSGi specification defines the OSGi bundle as the unit of modularization.

A bundle is a cohesive, self-contained unit, which explicitly defines its dependencies to other modules and services. It also explicitly defines its external API.

Technically OSGi bundles are .jar files with additional meta information. This meta information is stored in the "META-INF" folder in the "MANIFEST.MF" file.

The "MANIFEST.MF" file is part of a standard jar specification to which OSGi adds additional metadata. Any non-OSGi runtime will ignore the OSGi metadata. Therefore OSGi bundles can be used without restrictions in non-OSGi Java environments.

2.2. Bundle-SymbolicName and Version

Each bundle has a symbolic name which is defined via the Bundle-SymbolicName property. The name starts per convention with the reverse domain name of the author of the bundle, e.g. if you owned the domain example.com the name of your symbolic name would start with "com.example".

Each bundle has also a version number in the Bundle-Version property.

The Bundle-Version and the Bundle-SymbolicName uniquely identifies a bundle in OSGi.

Both properties are defined in the "MANIFEST.MF" file.

2.3. MANIFEST.MF

The following is an example of a "MANIFEST.MF" file.

				
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Popup Plug-in
Bundle-SymbolicName: de.vogella.rcp.intro.commands.popup; singleton:=true
Bundle-Version: 1.0.0
Bundle-Activator: de.vogella.rcp.intro.commands.popup.Activator
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6

			

The following table gives an explanation of the identifiers.

Table 1. OSGi Manifest Identifier

Identifier Description
Bundle-Name Short descriptive text of the bundle.
Bundle-SymbolicName Ihe unique identifier for this bundle.
Bundle-Version Defines the bundle version and must be incremented if a new version of the bundle is published.
Bundle-Activator Optional, defines an Activator. This class will be notified whenever the bundle is started or stopped.
Bundle-RequiredExecutionEnvironment Specify which Java version is required to run the bundle. If this requirement is not fulfilled then the OSGi runtime does not load the bundle.

2.4. Bundle dependencies and public API

Via the "MANIFEST.MF" file a bundle can define its dependency to other bundles or packages. OSGi will throw a ClassNotFoundException, if a class from a bundle tries to access a class without a defined dependency to it.

In the MANIFEST.MF file a bundle also defines the Java packages which should be exported and therefore available to other bundles (as API). Packages which are not exported are not visible to other bundles.

All these restrictions are enforced via a specific OSGi classloader. Each bundle has its own classloader. Access to restricted classes is not possible, also not via reflection.

A bundle can define that it depends on a certain version (or a range) of another bundle, e.g. bundle A can define that it depends on bundle C in version 2.0, while bundle B defines that it depends on version 1.0 of bundle C.

2.5. OSGi dependency management

OSGi is responsible for the dependency management between the bundles.

OSGi reads the MANIFEST.MF of a bundle during its installation. It ensures that all dependent bundles are also loaded, if the bundle is activated.

If the dependencies are not met, then the bundle is not loaded.

2.6. Bundle Lifecycle

With the installation of a bundle in the OSGi runtime this bundle is persisted in a local bundle cache. The OSGi runtime is then trying to resolve all dependencies of the bundle.

If all required dependencies are resolved the bundle is in the status "RESOLVED" otherwise it is in the status "INSTALLED".

If several bundles exist which would satisfy the dependency, then the bundle with the highest version is taking. If the versions are the same, then the bundle with the lowest ID will be taken. If the bundle is started, its status is "STARTING". Afterwards it gets the "ACTIVE" status.

3. Eclipse Equinox

Eclipse Equinox is the reference implementation of the base OSGi specification.

Eclipse Equinox is the runtime environment on which Eclipse application are based.

In Eclipse the smallest unit of modularization is a plug-in. The terms plug-in and bundle are (almost) interchangeable. An Eclipse plug-in is also an OSGi bundle and vice versa.

Eclipse Equinox extends the concept of bundles with the concept of extension points.

4. OSGi console

4.1. OSGI console commands

The OSGI console is like an MS-DOS prompt. In this console you can type a command to perform certain OSGI actions. The following is a reference of the most important OSGi commands.

Use for example the command ss to get an overview of all bundles and their status.

Table 2. OSGi commands

Command Desription
help Lists the available commands.
ss Gives you an overview of the installed bundles and their status.
ss vogella Gives you an overview of the bundles and their status if they have vogella within their name.
start id Starts the bundle with id
stop id Stops the bundle with id
install URL Installs a bundles from a URL
uninstall id Uninstalls the bundle with id
bundle "bundleid"" Show information about the bundle, including the registered and used services.
services filter Show all available services and their consumer. Filter is an optional LDAP filter, e.g. to see all services use "services (objectclass=*ManagedService)".


Bundles can be identified via their id which is displayed by the command ss.

4.2. Access to the Eclipse OSGi console

You can also access the OSGi console of your running Eclipse IDE. In the "Console" View of your running Eclipse you find a menu entry with the tooltip "Open Console". If you select here "Host OSGi Console" you will have access to your running OSGi instance.

5. Installation

5.1. Java

The following assumes that you have already Java installed. If not please Google for "How to installed Java for MyOS", while replacing "MyOS" with the operating system your are using.

5.2. Download the Eclipse plug-in package

Browse to Eclipse download site and download the package "Eclipse for RCP and RAP Developers". Extract the download to your harddisk. Avoid having special characters or spaces in the path to Eclipse.

5.3. Update an Eclipse Java IDE

In case you have downloaded the Eclipse Java IDE (or any other non RCP flavor) distribution you can use the Eclipse Update Manager to install the plug-ins required for RCP development.

Install General Purpose Tools Eclipse Plug-in Development Environment Eclipse RCP Plug-in Developer Resources from the Eclipse update site for your release. You may have to remove the "Group items by category" flag to see all available features.

Update dialog showing how the group by flag can be removed

Selecting the Ecipse RCP development package in the update manager.

6.  Tutorial: Your first OSGi bundle

The following will create a simple OSGi bundle and run it within Eclipse. At the end of this chapter you will also export your bundle to use it later in a standalone OSGi server.

6.1.  Create a new Bundle

Create a new plugin project "de.vogella.osgi.firstbundle" via FileNewOtherPlug-in DevelopmentPlug-in Project

6.2.  Coding

Create the following thread class.

				
package de.vogella.osgi.firstbundle.internal;

public class MyThread extends Thread {
	private volatile boolean active = true;

	public void run() {
		while (active) {
			System.out.println("Hello OSGI console");
			try {
				Thread.sleep(5000);
			} catch (Exception e) {
				System.out.println("Thread interrupted " + e.getMessage());
			}
		}
	}

	public void stopThread() {
		active = false;
	}
}

			

Change the class Activator.java to the following.

				
package de.vogella.osgi.firstbundle;

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

import de.vogella.osgi.firstbundle.internal.MyThread;

public class Activator implements BundleActivator {
	private MyThread myThread;

	public void start(BundleContext context) throws Exception {
		System.out.println("Starting de.vogella.osgi.firstbundle");
		myThread = new MyThread();
		myThread.start();
	}

	
	public void stop(BundleContext context) throws Exception {
		System.out.println("Stopping de.vogella.osgi.firstbundle");
		myThread.stopThread();
		myThread.join();
	}

}

			

6.3.  Run

Select your manifest.mf, right-click, select Run As-> Run Configuration. Create a OSGi Framework launch configuration. Deselect all bundles except your de.vogella.osgi.firstbundle. Press then "Add Required bundles".

Run this configuration. This should give you the following output. Every 5 second a new message should be written to the console.

Tip

In case you are wondering in which folder OSGi starts you find it in ${workspace_loc}/.metadata/plugins/org.eclipse.pde.core/ <runconfig> . This folder list the installed bundles via the file "dev.properties" and set the Eclipse workspace as reference in the config.ini file via the osgi.bundles=reference\:file\ statement. This way you can update your bundles in the running OSGi environment directly without any deployment.

6.4. Export your bundle

Export your bundle. This will allow you to install it into a OSGi runtime. Select your bundle and choose File -> Export -> Plug-in Development -> "Deployable plug-ins and fragment".

Unflag the option to export the source.

7.  Running a standalone OSGI server

This chapter will show how to run Equinox as a OSGI standalone runtime.

In your Eclipse installation directory identify the file org.eclipse.osgi*.jar. This file should be in the "plugin" folder. Copy this jar file to a new place, e.g. c:\temp\osgi-server. Rename the file to "org.eclipse.osgi.jar".

Start your OSGI server via the following command.

			
java -jar org.eclipse.osgi.jar -console

		

You can use "install URL" to install a bundle from a certain URL. For example to install your bundle from "c:\temp\bundles" use:

			
install file:c:\temp\bundles\plugins\de.vogella.osgi.firstbundle_1.0.0.jar

		

Tip

You properly need to correct the path and the bundle name on your system.

You can start then the bundle with start and the id.

Tip

You can remove all installed bundles with the -clean parameter.

8. OSGi Services

8.1. Overview

A bundle can register and use OSGi services. An OSGi service registered Java class which provides a certain functionality.

OSGi provides the central OSGi Service Registry for this purpose.

A service in OSGi is defined by a standard Java class or interface. Typically a Java interface is used to define the service interface.

As service in OSGi can be dynamically started and stopped, therefore the bundles must manage these dependencies themselves. The bundles can register listeners to get informed, if a service is started or stopped.

8.2. BundleContext

Access to the service registry is performed via the BundleContext class.

A bundle can define a Bundle-Activator (Activator) in its declaration. This class must extend the BundleActivator interface.

If defined OSGi injects the BundleContext into the start() and stop() methods of the implementing Activator class.

				

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


public class Activator implements BundleActivator {

	public void start(BundleContext context) throws Exception {
		System.out.println("Starting bundle");
		// Do something with the context, e.g. 
		// register services
	}

	public void stop(BundleContext context) throws Exception {
		System.out.println("Stopping bundle");
		serviceTracker.close();
		// Do something with the context, e.g. 
		// deregister service
	}

}
			

If you don't have an Activator, you can use the FrameworkUtil class from the OSGi framework which allows to retrieve the BundleContext for a class.

				
BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
			

8.3. Registering services

A bundle can also register itself to the events ( ServiceEvents ) of the BundleContext. These are for example triggered, if a new bundle is installed or de-installed or if a new service is registered.

To publish a service in your bundle use:

				
public class Activator implements BundleActivator {
	// ...
	public void start(BundleContext context) throws Exception {
		context.registerService(IMyService.class.getName(), new ServiceImpl(), null);

	}
	// ...
}
			

Once the service is no longer used you must unregister the service with OSGi. OSGi counts the usage of services to enable a dynamic replacement of services.

				
context.ungetService(serviceReference);
			

8.4. Accessing a services

With the Context class is available, a bundle can acquire a service via:

				
ServiceReference<?> serviceReference = context.getServiceReference(IMyService.class.getName());
IMyService service = (IMyService) context.getService(serviceReference);
			

If the BundleContext is not available, you can aquire it via the FrameworkUtil class.

				
BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
ServiceReference<?> serviceReference = context.getServiceReference(IMyService.class.getName());
IMyService service = (IMyService) context.getService(serviceReference);
			

8.5. Best practices for defining services

It is common practice to define the service via a bundle which only contains the interface definition. Another bundle would provide the implementation for this service. This allows to change the implementation of the service via a different bundle.

8.6. OSGi Service Tracker

OSGi allows that services are dynamically defined, stopped and updated. To use this dynamism you can use the class ServiceTracker. ServiceTracker has two methods addingService() and removedService() in which you can define your code to react to the change.

The class ServiceTracker can be either used directly or via the ServiceTrackerCustomizer interface.

				
MyQuoteServiceTrackerCustomizer customer = new MyQuoteServiceTrackerCustomizer(context);
serviceTracker = new ServiceTracker(context, IQuoteService.class.getName(), customer);
serviceTracker.open();
			

OSGi provides a service to track service events, e.g. new service registered, service stopped, service started. For this the org.osgi.util.tracker package from the org.eclipse.osgi bundle can be used.

8.7.  Problems with service tracker

The problem with service trackers is that they still obey Java rules. In case your service consumer keeps a reference of the service, this service cannot get removed via the OSGi framework. The other disadvantage is that the service tracker requires a lot of boilerplate code. To solve these issues declarative services were developed.

9. Tutorial: Define a Service and service consumption

In the following we will define and consume a service. Our service will return "famous quotes".

9.1.  Define the service interface

Create a plugin project "de.vogella.osgi.quote" and the package "de.vogella.osgi.quote". Do not use a template. You do not need an activator. Afterwards select the MANIFEST.MF and the "Runtime" tab. Add "de.vogella.osgi.quote" to the exported packages.

Create the following interface "IQuoteService".

				
package de.vogella.osgi.quote;

public interface IQuoteService {
	String getQuote();
}

			

9.2.  Create service

We will now define a bundle which will provide the service.

Create a plugin project "de.vogella.osgi.quoteservice". Do not use a template.

Select the MANIFEST.MF and dependecy tab. Add "de.vogella.osgi.quote" to the required plugins.

Create the following class "QuoteService".

				
package de.vogella.osgi.quoteservice.internal;

import java.util.Random;

import de.vogella.osgi.quote.IQuoteService;

public class QuoteService implements IQuoteService {

	@Override
	public String getQuote() {
		Random random = new Random();
		// Create a number between 0 and 2
		int nextInt = random.nextInt(3);
		switch (nextInt) {
		case 0:
			return "Tell them I said something";
		case 1:
			return "I feel better already";
		default:
			return "Hubba Bubba, Baby!";
		}

	}
}

			

Register the service in the class Activator.

				
package de.vogella.osgi.quoteservice;

import java.util.Hashtable;

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

import de.vogella.osgi.quote.IQuoteService;
import de.vogella.osgi.quoteservice.internal.QuoteService;

public class Activator implements BundleActivator {

	public void start(BundleContext context) throws Exception {
		IQuoteService service = new QuoteService();
		// Third parameter is a hashmap which allows to configure the service
		// Not required in this example
		context.registerService(IQuoteService.class.getName(), service,
				null);
		System.out.println("IQuoteService is registered");
	}

	public void stop(BundleContext context) throws Exception {
	}
}

			

9.3.  Install service bundles

Export your bundles and install them on your server. Start the service bundle.

Tip

Nothing fancy happens, as we are not yet consuming our service.

9.4.  Use your service

Create a new plugin "de.vogella.osgi.quoteconsumer". Add also a dependency to the package "de.vogella.osgi.quote".

Tip

Please note that we have added the dependency against the package NOT against the plugin. This way we later replace the service with a different implementation.

Lets register directly to the service and use it.

				
package de.vogella.osgi.quoteconsumer;

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

import de.vogella.osgi.quote.IQuoteService;

public class Activator implements BundleActivator {

	private BundleContext context;
	private IQuoteService service;

	public void start(BundleContext context) throws Exception {
		this.context = context;
		// Register directly with the service
		ServiceReference reference = context
				.getServiceReference(IQuoteService.class.getName());
		service = (IQuoteService) context.getService(reference);
		System.out.println(service.getQuote());
	}

	public void stop(BundleContext context) throws Exception {
		System.out.println(service.getQuote());
	}

}

			

Export this bundle, install it and start and stop it. Everything work. But if you stop the service bundle then your receive an error.

The reason for this is that OSGi is a very dynamic environment and service may be registered and de-registered any time. The next chapter will use a service tracker to improve this.

9.5.  Use your service with a service tracker

Declare a package dependency to the package "org.osgi.util.tracker" in your bundle.

To use this define the following class "MyQuoteServiceTrackerCustomizer"

				
package de.vogella.osgi.quoteconsumer;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import de.vogella.osgi.quote.IQuoteService;

public class MyQuoteServiceTrackerCustomizer implements
		ServiceTrackerCustomizer {

	private final BundleContext context;

	public MyQuoteServiceTrackerCustomizer(BundleContext context) {
		this.context = context;
	}

	private MyThread thread;

	@Override
	public Object addingService(ServiceReference reference) {
		IQuoteService service = (IQuoteService) context.getService(reference);
		thread = new MyThread(service);
		thread.start();
		return service;
	}

	@Override
	public void modifiedService(ServiceReference reference, Object service) {
		// removedService(reference, service);
		// addingService(reference);
	}

	@Override
	public void removedService(ServiceReference reference, Object service) {
		context.ungetService(reference);
		System.out.println("How sad. Service for quote is gone");
		thread.stopThread();
	}

	public static class MyThread extends Thread {

		private volatile boolean active = true;
		private final IQuoteService service;

		public MyThread(IQuoteService service) {
			this.service = service;
		}

		public void run() {
			while (active) {
				System.out.println(service.getQuote());
				try {
					Thread.sleep(5000);
				} catch (Exception e) {
					System.out.println("Thread interrupted " + e.getMessage());
				}
			}
		}

		public void stopThread() {
			active = false;
		}
	}

}

			

You also need to register a service tracker in your activator of your serviceconsumer.

				
package de.vogella.osgi.quoteconsumer;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;

import de.vogella.osgi.quote.IQuoteService;

public class Activator implements BundleActivator {

	private ServiceTracker serviceTracker;

	public void start(BundleContext context) throws Exception {
		System.out.println("Starting quoteconsumer bundles");
		// Register directly with the service
		MyQuoteServiceTrackerCustomizer customer = new MyQuoteServiceTrackerCustomizer(
				context);
		serviceTracker = new ServiceTracker(context, IQuoteService.class
				.getName(), customer);
		serviceTracker.open();
	}

	public void stop(BundleContext context) throws Exception {
		System.out.println("Stopping quoteconsumer bundles");
		serviceTracker.close();
	}

}

			

Export your bundle again. Start the OSGI console. Use the update command or the install command to get the new version of your bundle and start it. Once you start your service the tracker will be called and the consumer bundle will start writing messages to the console. Stop the service and verify that the consumer does not use the service anymore.

10. Declarative OSGiServices

10.1.  Overview

Declarative services (DS) allow to define and consume services via metadata (XML). Via DS you can define OSGi services without extending or implementing OSGi classes. This allows that these services can be tested independently of the OSGi runtime.

The "OSGi service component" is responsible for starting the service (service component). For the service consumer it is not visible if the service has been created via declarative service or via other means.

Service Components consists of an XML description (Component Description) and an object (Component Instance). The component description contains all information about the service component, e.g. the class name of the component instance and the service interface.

A reference to the component description is maintained in the "MANIFEST.MF" file. This file is read by the OSGi runtime and if a component description is found the corresponding service is created. The component description in the "MANIFEST.MF" file looks for example like the following:

				
Service-Component: component.xml, OSGI-INF/component.xml
			

10.2.  Required bundles

To run declarative services you require the following bundles.

  • org.eclipse.equinox.util

  • org.eclipse.equinox.ds - Declarative service

10.3.  Definition of a DS service

Typically component definitions are created in the project folder "OSGI-INF" via NewOtherPlug-in Development Component Definition . The wizard will also add the Service-Component entry to the "MANIFEST.MF" file.

On the next page of the wizard, you can maintain the name of the component definition file, a name and the class which implements the services (or consumes the services).

If you press finish, the service editor opens.

On the service tab you can maintain provided services or referred services. For example to provide a service you would press "Add" under "Provided Services" and select the service interface you want to implement.

As a final step you would implement the class which would provide the service.

A correctly maintained component.xml would look like the following in XML.

				
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="de.vogella.osgi.ds.quoteservice">
   <implementation class="de.vogella.osgi.ds.quoteservice.QuoteService"/>
   <service>
      <provide interface="de.vogella.osgi.quote.IQuoteService"/>
   </service>
</scr:component>

			

This means that there is a component called "de.vogella.osgi.ds.quoteservice" which provides a service to the OSGI Service Registry under the interface "de.vogella.osgi.quote.IQuoteService". This component is implemented by the class "de.vogella.osgi.ds.quoteservice.QuoteService.

After the definition of the component your MANIFEST.MF would contain an entry to the service component.

				
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Quoteservice
Bundle-SymbolicName: de.vogella.osgi.ds.quoteservice
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: de.vogella.osgi.quote
Service-Component: OSGI-INF/component.xml

			

11. Tutorial: Define a declarative OSGi Service

The following will define a DS service based on the quote example. It is therefore required that you have created the "de.vogella.osgi.quote" project which contains the interface definition.

Create a new plugin project "de.vogella.osgi.ds.quoteservice". Do not use a template, do not create an activator. Import package "de.vogella.osgi.quote" in MANIFST.MF on the tab "dependencies".

Create the Folder "OSGI-INF" in your project. Create a new component definition as described earlier. The implementing class is de.vogella.osgi.ds.quoteservice.QuoteService which provides the service for IQuoteService.

Create the class "QuoteService" which implements the interface IQuoteService.

			
package de.vogella.osgi.ds.quoteservice;

import java.util.Random;

import de.vogella.osgi.quote.IQuoteService;

public class QuoteService implements IQuoteService {

	@Override
	public String getQuote() {
		Random random = new Random();
		// Create a number between 0 and 2
		int nextInt = random.nextInt(3);
		switch (nextInt) {
		case 0:
			return "Ds: Tell them I said something";
		case 1:
			return "Ds: I feel better already";
		default:
			return "Ds: Hubba Bubba, Baby!";
		}
	}

}

		

Open component.xml and select the tab "Source". The final result should look like the following.

			
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="de.vogella.osgi.ds.quoteservice">
   <implementation class="de.vogella.osgi.ds.quoteservice.QuoteService"/>
   <service>
      <provide interface="de.vogella.osgi.quote.IQuoteService"/>
   </service>
</scr:component>

		

Copy the "org.eclipse.equinox.ds*.jar", "org.eclipse.osgi.services.jar" and "org.eclipse.equinox.util*.jar" from your Eclipse/plugin installation directory into a folder, e.g. "C:\temp\bundles\plugins" and install the bundle into your OSGi runtime via.

			
install file:c:\temp\bundles\plugins\org.eclipse.equinox.ds.jar
install file:c:\temp\bundles\plugins\org.eclipse.equinox.util.jar
install file:c:\temp\bundles\plugins\org.eclipse.osgi.services.jar

		

Start the bundles manually so that declarative services are available.

Export your own bundle to "de.vogella.osgi.ds.quoteservice.jar". and install it via:

			
install file:c:\temp\bundles\plugins\de.vogella.osgi.ds.quoteservice.jar

		

To check if your service was registered use the command "services". This will list all installed and available services.

If you stop / uninstall the old service provider and start the new one your service should be picked up by the consumer.

12. Tutorial: Using services via declarative services

Of course you can also define the consumption of services via DS.

Create a new plugin "de.vogella.osgi.ds.quoteconsumer". Do not use a template, do not create an activator. Import the package "de.vogella.osgi.quote" in MANIFEST.MF on the tab "Dependencies".

Create the following class.

			
package de.vogella.osgi.ds.quoteconsumer;

import de.vogella.osgi.quote.IQuoteService;

public class QuoteConsumer {
	private IQuoteService service;

	public void quote() {
		System.out.println(service.getQuote());
	}
	
	// Method will be used by DS to set the quote service
	public synchronized void setQuote(IQuoteService service) {
		System.out.println("Service was set. Thank you DS!");
		this.service = service;
		// I know I should not use the service here but just for demonstration
		System.out.println(service.getQuote());
	}

	// Method will be used by DS to unset the quote service
	public synchronized void unsetQuote(IQuoteService service) {
		System.out.println("Service was unset. Why did you do this to me?");
		if (this.service == service) {
			this.service = null;
		}
	}
}

		

Tip

Note that this class has no dependency to OSGi.

Create the Folder "OSGI-INF" and create a new "Component Definition" in this folder.

This time we will use a service. Maintain the "Referenced Services".

Make the relationship to the bind / unbind method via by selecting your entry can pressing "Edit".

The result component.xml should look like:

			
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="de.vogella.osgi.ds.quoteconsumer">
   <implementation class="de.vogella.osgi.ds.quoteconsumer.QuoteConsumer"/>
   <reference bind="setQuote" cardinality="1..1" interface="de.vogella.osgi.quote.IQuoteService" name="IQuoteService" policy="static" unbind="unsetQuote"/>
</scr:component>

		

The result MANIFEST.MF should look like:

			
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Quoteconsumer
Bundle-SymbolicName: de.vogella.osgi.ds.quoteconsumer
Bundle-Version: 1.0.4
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: de.vogella.osgi.quote
Service-Component: OSGI-INF/component.xml

		

Export your plugin and install it via: install file:c:\temp\bundles\plugins \de.vogella.osgi.ds.quoteconsumer.jar

"If you start the bundle now with "start id_of_your_bundle" you should get the feedback that the service was set and one quote should be returned

13. Bndtools

Eclipse use the PDE tooling to manage bundles. Alternatively you can use Bndtools hosted at http://bndtools.org/ .

Please see Bndtools tutorial for an introduction.

14. Thank you

Please help me to support this article:

Flattr this

15. Questions and Discussion

Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.de Google Group. I have created a short list how to create good questions which might also help you.

16. Links and Literature

16.1. Source Code

Source Code of Examples

16.3. vogella Resources

Eclipse RCP Training (German) Eclipse RCP Training with Lars Vogel

Android Tutorial Introduction to Android Programming

GWT Tutorial Program in Java and compile to JavaScript and HTML

Eclipse RCP Tutorial Create native applications in Java

JUnit Tutorial Test your application

Git Tutorial Put everything you have under distributed version control system