OSGi

  • submit to reddit

Eclipse Plug-in Development

By James Sugrue

14,182 Downloads · Refcard 70 of 151 (see them all)

Download
FREE PDF


The Essential Eclipse Plug-in Cheat Sheet

Eclipse consists of many plug-ins, which are bundles of code that provide some functionality to the entire system. Plug-ins contribute functionality to the system by implementing pre-defined extension points. You can provide extension points in your own plug-in to allow other plug-ins to extend your functionality. This DZone Refcard takes the user through the process of Eclipse-based plug-in development, from plug-in basics to the OSGi manifest, the plug-in manifest, hot tips, and more.
HTML Preview
Eclipse Plug-in Development

Eclipse Plug-in Development

By James Sugrue

About Eclipse Plug-ins

The Eclipse platform consists of many plug-ins, which are bundles of code that provide some functionality to the entire system. Plug-ins contribute functionality to the system by implementing pre-defined extension points. You can provide extension points in your own plug-in to allow other plug-ins to extend your functionality.

Hot Tip

Eclipse has a dedicated perspective for development of plug-ins, the PDE (Plug-in Development Environment). You can download Eclipse for RCP/ Plug-in Developers with all you need to get started from http://www.eclipse.org.

How plug-ins work

A plug-in describes itself to the system using an OSGi manifest (MANIFEST.MF) file and a plug-in manifest (plugin.xml) file. The Eclipse platform maintains a registry of installed plug-ins and the function they provide. As Equinox, the OSGi runtime, is at the core of Eclipse, you can think of a plug-in as an OSGi bundle. The main difference between plug-ins and bundles is that plug-ins use extension points for interaction between bundles.

Plug-ins take a lazy-loading approach, where they can be installed and available on the registry but will not be activated until the user requests some functionality residing in the plug-in.

the osgi manifest

MANIFEST.MF, usually located in the META-INF directory, deals with the runtime details for your plug-in. Editing of the manifest can be done through the editor provided, or directly in the MANIFEST.MF tab. The following is an example of one such manifest for a simple plug-in:


Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Myplugin
Bundle-SymbolicName: com.dzone.tests.myplugin
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.dzone.tests.myplugin.Activator
Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6

The Eclipse OSGi Framework implements the complete OSGi R4.1 Framework specification and all of the Core Framework services. Here we list the most common manifest headers and directives.

Manifest Entry Use Example
Manifest-Version Manifest versioning information for your own records 1.0
Bundle-ManifestVersion A bundle manifest mayexpress the version of the syntax in which it is written by specifying a bundle manifest version. If using syntax from OSGi Release 4 or later, you must specify a bundle manifest version. The bundle manifest version defined by OSGi Release 4 is '2'. 2
Bundle-Name Human readable name for the plug-in. MyPlugin
Bundle-SymbolicName A unique name for this plug-in, usually in package naming convention. com.dzone.tests.myplugin
Bundle-Version The version of this plugin. This should follow the typical three number versioning format of < major version>. <minor version>. < revision> This can also be appended by an alphanumeric qualifier. 1.0.1.alpha
Bundle-Activator The activator, or plug-in class, that controls this plug-in. com.dzone.tests.myplugin.Activator
Bundle-Vendor Human readable string for the plug-in provider. DZone
Bundle-Classpath A comma-separated list of directories and jar files used to extend this bundle's functionality. lib/junit.jar,lib/xerces.jar
Require-Bundle A comma-separated list of symbolic names of other bundles required by this plug-in. rg.eclipse.ui,org.eclipse. core.runtime
Bundle-ActivationPolicy Manifest header identifying the bundle's activation policy. This replaces the deprecated Eclipse-LazyStart directive. Lazy
Bundle-Required ExecutionEnvironment Manifest header identifying the required execution environment for the bundle. The platform may run this bundle if any of the execution environments named in this header match one of the execution environments it implements. JavaSE-1.6
Export-package A list of the packages that this bundle provides for export to other plug-ins. com.dzone.tests.api

Plug-in Runtime

The Require-bundle manifest header has some extra functionality to help you manage your runtime dependencies. Bundles can be marked as optional dependencies by annotating the bundle with ;resolution:=optional.

You can also manage which version of the bundle your dependent on needs to be present using the ;bundleversion=' <values>' annotation. Here, the <values> that we refer to are a range of versions where you can specify minimum and maximum version ranges. The syntax of this range value is illustrated through these examples:

Example Meaning
3.5 Dependent only on version 3.5 of this bundle
[3.5, 3.5.1] Must be either version 3.5 or 3.5.1
[3.0, 4.0] Must be a version of 3.0 or over, but not 4.0

Additional Eclipse Bundle Headers

Eclipse provides a number of addition bundle headers and directives. These extra headers are not part of the OSGi R4.1 specification, but allow developers to use additional Eclipse OSGi Framework functionality.

Manifest Entry Use Example
Export-Package
Additional directives
are available to manage
the access restriction of
exported packages.
x-internal
The default value for this
property is false. When
internal packages are
specified as true using this
option, the Eclipse PDE
discourages their use.
x-friends
This option is similar to
x-internal, but allows
certain bundles to use the
exported packages that
have this option. Other
bundles are discouraged.
The x-internal option
takes precedence over
x-friends.
Export-Package:
org.eclipse.
foo.internal;
x-internal:=true
Export-Package:
org.eclipse.foo.
formyfriends;
x-friends:='org.
eclipse.foo.
friend1'
Eclipse-PlatformFilter
This allows you to set
particular rules for your
bundle before it can start.
osgi.nl for language
osgi.os for operating
system
osgi.arch for
architecture
osgi.ws for windowing
system
Eclipse- PlatformFilter: (& (osgi.ws=win32) (osgi.os=win32) (osgi.arch=x86))

All entries in the manifest can be internationalized by moving them to a separate plugin.properties file.

the plug-in manifest

With the Manifest.MF file looking after the runtime dependencies, plugin.xml deals with the plug-in extensions and extension points.

An extension allows you to extend the functionality of another plug-in in your system. An extension can be added through the plug-in editor's Extensions tab, or to your plugin.xml.


<extension point='org.eclipse.ui.preferencePages'>
   <page
     class='com.dzone.tests.myplugin.preferences.
       SamplePreferencePage'
           id='com.dzone.tests.myplugin.preferences.
       SamplePreferencePage'
     name='Sample Preferences'>
   </page>
</extension>

Each extension point has a XML schema which specifies the elements and attributes that make up the extension. As you can see in the listing above, each extension point has a unique identifier. The <page> element above is specified in the XML schema for the org.eclipse.ui.preferencesPages extension.

Hot Tip

Plug-ins and extension points are expected to have the same unique identifiers following the Java package naming pattern.

You can also define your own extension points, and we will detail that process in a later section.

Plug-in mode l

The plug-in class is a representation of your plug-in running in the Eclipse platform. A plug-in class in Eclipse must extend org. eclipse.core.runtime.Plugin, which is an abstract class that provides generic facilities for managing plug-ins. When using the project wizard in the PDE, this class typically gets assigned Activator as its default name. Whatever name you assign to this plug-in class, it must be the same as that mentioned in the Bundle-Activator directive of your MANIFEST.MF.

The class has start and stop methods that refer to the BundleContext and are provided by the BundleActivator interface. These methods allow you to deal with the plug-ins lifecycle, so that you can do both initialization and cleanup activities at the appropriate times. When overriding these methods be sure to always call the superclass Implementations.

Hot Tip

Plug-ins that contribute to the UI will have activators that extend AbstractUIPlugin, while non-UI plug-ins will extend Plugin.

Bundle Context

A BundleContext is associated with your plug-in when it is started. As well as providing information about the plug-in, the BundleContext can provide information about other plug-ins in the system. By providing a listener to BundleEvent, you can monitor the lifecycle of any other plug-in.

Bundle

The terms Bundle and Plug-in may be used interchangeably when discussing Eclipse. The Bundle class provides us with the OSGi unit of modularity. There are six states associated with bundles:

State Meaning
UINSTALLED The bundle is uninstalled and not available.
INSTALLED A bundle is in the INSTALLED state when it has been installed in the Framework but is not or cannot be resolved
RESOLVED Before a plug-in can be started, it must first be in the RESOLVED state.
A bundle is in the RESOLVED state when the Framework has successfully resolved the bundle's code dependencies.
STARTING A bundle is in the STARTING state when its start method is active.
If the bundle has a lazy activation policy, the bundle may remain in this state until the activation is triggered.
STOPPING A bundle is in the STOPPING state when its stop method is active.
When the BundleActivator.stop method completes the bundle is stopped and must move to the RESOLVED state.
ACTIVE A bundle is in the ACTIVE state when it has been successfully started and activated.

Lazy Loading

Plug-ins are normally set to load lazily, so that the code isn't loaded into memory until it is required. This is normally a good thing as you don't want to affect the startup time of Eclipse. If you do require your plug-in to start up and load when Eclipse launches, you can use the org.eclipse.ui.startup extension point.


<extension point='org.eclipse.ui.startup'>
   <startup class='com.myplugin.StartupClass'>
</extension>

The startup class listed above must implement the org.eclipse.ui.IStartup interface which provides an earlyStartup() method. The method is called in a separate thread after the workbench initializes.

Extension Points

The Eclipse platform provides a number of extension points that you can hook into, to provide additional functionality. The concept behind an extension point is that a class provides some extendable behavior, and publishes this behavior as an extension point. In order to run this code, the plug-in requires a host '" in this case your own plug-in.

In your plugin.xml you take this extension point and provide extra information to help it run. You will usually need to provide some class that implements a particular interface in order to do this.

Here we will run through some useful extension points in the Eclipse platform. Note, that to make some of these available for your plug-in, you will usually need to add dependencies.

Example Meaning
org.eclipse.core.runtime .preferences Allows plug-ins to use the Eclipse preferences mechanism, including the setting of default preference values.
org.eclipse.core.runtime .applications A plug-in that wishes to use the platform but control all aspects of its execution is an application.
org.eclipse.core.resources .builders Useful for IDE builders who wish to provide an incremental project builder, processing a set of resource changes.
org.eclipse.core.resources .markers Markers are used to tag resources with use information '" this marker can then be utilized in the problems view.
org.eclipse.ui.activities The activity extension point allows the filtering of plug-in contributions from users until they wish to use them.
org.eclipse.ui.editors Allows the addition of new editors to the workbench, which can be tied to particular file extension types.
org.eclipse.ui.intro When Eclipse is first started up the welcome page, or intro is displayed. This extension point allows contributions to the welcome page.
org.eclipse.ui.menus Allows custom menus to be added to the workbench either in the main menu, toolbar or popup menus through the locationURI attribute.
org.eclipse.ui.perspective Allows the addition of a perspective factory to the workbench, defining a particular layout of windows.
org.eclipse.ui.propertyPages Adds a property page for objects of a given type.
org.eclipse.ui.themes Allows the customization of the user interface, overriding the default colors and fonts.
org.eclipse.ui.views Provides the ability to add views to the workbench.

Creating your own extension points

As well as being a user of extension points, a plug-in can provide its own extensions for other plug-ins. Extension points allow loose coupling of functionality '" your plug-in exposes a set of interfaces and an extension point definition for others to use.

Extension Point Definition

You can create your extension point through the plugin.xml file, or through the Add button in the Extension Points tab of the plug-in editor.

For identifying your extension point you need to provide a unique identifier and a human readable name. At this point you can also point to a schema file and edit it afterwards. An extension point schema must have .exsd as its suffix.

Extension Point Wizard

Figure 1: The New Extension Point Wizard

Defining an Extension Point Schema

The PDE provides an editor for defining your .exsd file, consisting of three tabs. First, the Overview tab allows you to provide documentation and examples for your extension point. This is an essential step if you want your extension point to be adopted. Next, the Definition tab presents a graphical way to define your schema, while the Source tab allows editing of the .exsd XML definition.

Test_Extension

Figure 2: The Extension Point editor

When creating your extension point, you will first want to create one or more elements with attributes that will be used. Each extension point attribute has a number of associated properties:

Attribute Use
Name The name of the extension point attribute.
Deprecated Whether the attribute is deprecated or not.
Use Whether the attribute is optional, required or default. Default allows you to specify a value for the attribute if it hasn't been used.
Type The available types are Boolean, String, Java, Resource and Identifier. While Boolean and String are self '"explanatory, Resource should be used if the attribute is a file. Identifier provides a reference id for the extension point.
Extends If the type is Java this must be the name of the class that the attribute must extend.
Implements If the type is Java this must be the name of the class that the attribute must implement.
Translatable If the type is String this Boolean value indicates whether the attribute should be translated.
Restrictions If the type is String this can be used to limit the choice of value to a list of strings.
Description Attribute documentation.
References If the type is Identifier, this provides the id of the extension point that you want to reference. This will allow implementers of the extension point to easily find the id, without having to look through the plug-in registry.

Once you have created your elements and attributes for the extension point, the element can be added to a sequence for this extension. You can control the multiplicity of your extension here.

The mapping of XML to extension point declaration is simple; for users of your point, an xml element in the extension point will always appear on the left hand side tree, as part of the extension point declaration, while the xml attributes will appear as extension point attributes.

The Code Behind an Extension Point

With the extension point defined, the producer of this needs to provide some implementation that makes use of any extension point contributions.

To get a list of all the implementers of your extension point you can query the extension registry as follows, providing your extension point identifier as the parameter.


IConfigurationElement[] config = Platform.getExtensionRegistry()
   .getConfigurationElementsFor('myextid');


To use the implementing extension point, you can get the object from the IConfigurationElement.


final Object o = config[i].createExecutableExtension('class');

Useful Tools

The PDE plug-in editor provides a number of useful utilities for working with your plug-ins. The Dependencies tab in particular is essential for organizing your runtime.

The Dependencies Tab

From here you can investigate the plug-in dependency hierarchy, starting with your plug-in as the root. You can also see which plug-ins are dependent on your own plug-in, as well as find any unused dependencies. This can be useful if you previously added a dependency to use an extension point, but have found that it is since no longer required. Finally, and most importantly, the tab provides a utility for investigating for cyclic dependencies.

Another useful tool for plug-in development is the Plug-in Registry view. This can be accessed from the Window>Show View>Other..>Plug-in Development category. This view will display all the plug-ins that are currently available in your Eclipse installation.

The Dependencies Tab

Figure 4: Plug-in Registry

Hot Tip

When launching an application containing you plugin, use the -consoleLog program argument from the Run Configurations dialog to see output to the system console.

Logging

It is recommended to log to a file, rather than using System. out. The Activator or plug-in class provides a facility to access the plug-in logging mechanism through the getLog() method, returning the org.eclipse.core.runtime.ILog interface.

Each log entry using this framework is of type IStatus. Any CoreExceptions thrown in Eclipse have an associated IStatus object. An implementation of this interface, Status, is available for use. There is also a MultiStatus class which allows multiple statuses to be logged at once.

Distributing your PL ug-in

Since Eclipse 3.4, p2 has been used as the method to provision your application with new or updated plug-ins. For build managers who have used the Update Site mechanism before, there doesn't need to be any change.

To create an update site you can use the wizard provided to create a new site.xml file. Using the Software Updates menu, users can point to your update site on the web and download the plug-in.

By adding some extra functionality over this simple implementation, you can leverage p2 to add extra meta data to your update site, which will make the installation experience faster for end users.

p2 Update Site Publisher

The UpdateSite Publisher application is provided by p2 to generate an artifact.xml and content.xml files for your standard update site. You can run this application in headless mode using org.eclipse.equinox.p2.publisher.UpdateSitePublisher. The following shows an example of how to run this application, taken from the p2 wiki.


java -jar <targetProductFolder>/plugins/org.eclipse.equinox.
launcher_*.jar
 -application org.eclipse.equinox.p2.publisher.UpdateSitePublisher
 -metadataRepository file:/<some location>/repository
 -artifactRepository file:/<some location>/repository
 -source /< location with a site.xml>
 -configs gtk.linux.x86
 -compress
 -publishArtifacts

Read more about p2 at http://wiki.eclipse.org/Equinox/p2

Enha ncing your plug-in

When developing your plug-in, you should be aware of the wide variety of projects available in the Eclipse eco-system that help make your development easier and faster. This section gives an overview of just a few of the useful projects that exist, and explains how they can be used in your project.

Eclipse Modeling Project
http://eclipse.org/modeling/

The Eclipse Modelling Project provides a large set of tools for model driven development. The most popular part of this project is the Eclipse Modelling Framework (EMF). Using this technology, you can define a model in the ecore format, generate Java code to represent, serialise and de-serialise the model. Other tools within the modelling project utilise EMF to provide more specialised frameworks for developers.

The Connected Data Objects (CDO) project provides a threetier architecture for distributed and shared models.

The Graphical Modelling Framework (GMF) allows you to generate graphical editors for your model based on EMF and the Graphical Editing Framework (GEF). For developers who want to provide textual editor for their own language or DSL, XText provides a EBNF grammar language and generates a parser, meta-model and Eclipse text editor from this input.

Eclipse Communication Framework
http://eclipse.org/ecf

If your plugin requires any communication functionality, the ECF project is the first place to look. ECF consists of a number of bundles that expose various communication APIs. These APIs range from instant messaging, dynamic service discovery, file transfer to remote and distributed OSGi. Real-time shared editing functionality is also available in the framework, allowing you to collaborate remotely on anything that you are editing within your plug-in's environment.

Business Intelligence and Reporting Tools
http://eclipse.org/birt

BIRT is an open source reporting system based on Eclipse. BIRT provides both programmatic access to report creation, as well as functionality to create your own report template within the Eclipse IDE. While BIRT allows you to generate reports in file formats such as PDF, it is also possible to use BIRT on an application server to serve reports through a web browser.

Equinox
http://eclipse.org/equinox

As we have described in this card, Equinox is the Eclipse implementation of the OSGi R4 core framework specification, and provides the real runtime for all your plug-ins. However, as well as running your plug-ins on the desktop on an instance of Eclipse, you can take Equinox and run it on a server, allowing your plug-in to run on browsers as well as the desktop.

Rich Ajax Platform
http://eclipse.org/rap

With the emergence of the web as a real platform for rich applications, the Rich Ajax Platform allows you to take a standard RCP project, and with some minor modifications, make it deployable to the web. This idea of single-sourcing is key to the RAP project, and reduces the burden for developers to make an application ready for either the desktop or the web.

The same programming model is used, while qooxdoo is used for the client side presentation of your SWT and JFace widgets.

About The Author

Photo of author James Sugrue

James Sugrue

James Sugrue is a software architect at Pilz Ireland, a company using many Eclipse technologies. James is also editor at both EclipseZone and Javalobby. Currently he is working on TweetHub, a Twitter client based on RCP and ECF. James has also written previous Refcardz covering EMF and Eclipse RCP.

Zone Leader: EclipseZone, Javalobby

Twitter: @dzonejames

Recommended Books

eclipse

This book presents detailed, practical coverage of every aspect of plug-in development--with specific solutions for the challenges you’re most likely to encounter.


Eclipse Platform

In Eclipse Rich Client Platform, two leaders of the Eclipse RCP project show exactly how to leverage Eclipse for rapid, efficient,cross-platform desktop development.


Share this Refcard with
your friends & followers...

DZone greatly appreciates your support.


Your download should begin immediately.
If it doesn't, click here.

Getting Started with Spring-DM

By Craig Walls

16,698 Downloads · Refcard 57 of 151 (see them all)

Download
FREE PDF


The Essential Spring-DM Cheat Sheet

Spring is a framework that promotes development of loosely coupled/highly cohesive objects through dependency injection and interface-oriented design. Spring Dynamic Modules (Spring-DM) brings Spring and OSGi together to enable a declarative service model for OSGi that leverages Spring’s power of dependency injection. This DZone Refcard shows you how to use Spring-DM to wire together OSGi services to build highly modular and dynamic applications. You may also enjoy the other Spring DZone Refcardz in our Collection: Spring Configuration and Spring Annotations.
HTML Preview
Getting Started with Spring-DM

Getting Started with Spring-DM

By Craig Walls

about spring-dm

Spring is a framework that promotes development of looselycoupled/ highly-cohesive objects through dependency injection and interface-oriented design. OSGi is a framework specification that promotes development of loosely-coupled/ highly-cohesive application modules through services and interface-oriented design. Seems like a match made in heaven! Spring Dynamic Modules (Spring-DM) brings Spring and OSGi together to enable a declarative service model for OSGi that leverages Spring’s power of dependency injection. This reference card will be your resource for working with Spring- DM to wire together OSGi services and ultimately building modular applications.

You may be interested to know that Spring-DM is the basis for the SpringSource dm Server, a next-generation application server that embraces modularity through OSGi. What’s more, the upcoming OSGi R4.2 specification includes a component model known as the OSGi Blueprint Services that is heavily influenced by Spring-DM.

Introducing Spring-DM

The star player of Spring-DM is a bundle known as the Spring- DM extender. The Spring-DM extender watches for bundles to be installed and inspects them to see if they are Springenabled (that is, if they contain a Spring application context definition file). When it finds a Spring-enabled bundle, the extender will create a Spring application context for the bundle.

Spring Application Contexts

Spring-DM also provides a Spring configuration namespace that enables you to declare and publish Spring beans as OSGi services and to consume OSGi services as if they were just beans in a Spring application context. This declarative model effectively eliminates the need to work with the OSGi API directly.

Installing Spring-DM

One of the nice things about Spring-DM is that you do not need to include it in the classpath of your OSGi bundles or even reference it from those bundles. Installing Spring-DM involves two parts:

  1. Installing the Spring-DM and supporting bundles in your OSGi framework
  2. Adding the Spring-DM configuration namespace to your bundle’s Spring configuration XML files

You can download Spring-DM from
http://www.springframework.org/osgi. The distribution comes complete with everything you need to work with Spring- DM, including the Spring-DM extender bundle and all of its dependency bundles.

Installing the Spring-DM extender bundles

There are several means by which you can install bundles into an OSGi framework, depending on the OSGi framework and any add-ons or tools you may be using. But the most basic way is to use the “install” command that is available in most OSGi framework shells. For example, to install the Spring- DM extender bundle and the supporting Spring-DM bundles (assuming that you’ve unzipped the Spring-DM distribution in / spring-dm-1.2.0):


osgi> install file:///spring-dm-1.2.0/dist/spring-osgi-core-
   1.2.0.jar
osgi> install file:///spring-dm-1.2.0/dist/spring-osgi-extender-
   1.2.0.jar
osgi> install file:///spring-dm-1.2.0/dist/spring-osgi-io-
   1.2.0.jar

Spring-DM depends on the Spring framework, so you’ll also need to install several other Spring bundles:

refcardzad


osgi> install file:///spring-dm-1.2.0/lib/spring-aop-2.5.6.A.jar
osgi> install file:///spring-dm-1.2.0/lib/spring-context-
    2.5.6.A.jar
osgi> install file:///spring-dm-1.2.0/lib/spring-core-2.5.6.A.jar
osgi> install file:///spring-dm-1.2.0/lib/spring-beans-2.5.6.A.jar

Finally, you’ll also need to install several other supporting bundles that Spring and Spring-DM depend on:


osgi> install file:///spring-dm-1.2.0/lib/com.springsource.net.
   sf.cglib-2.1.3.jar
osgi> install file:///spring-dm-1.2.0/lib/com.springsource.org.
   aopalliance-1.0.0.jar
osgi> install file:///spring-dm-1.2.0/lib/com.springsource.slf4j.
   api-1.5.0.jar
osgi> install file:///spring-dm-1.2.0/lib/com.springsource.slf4j.
   log4j-1.5.0.jar
osgi> install file:///spring-dm-1.2.0/lib/com.springsource.slf4j.
   org.apache.commons.logging-1.5.0.jar
osgi> install file:///spring-dm-1.2.0/lib/log4j.osgi-1.2.15-
   SNAPSHOT.jar

Hot Tip

Use tools to help install bundles Installing bundles using the “install” command should work with almost any OSGi framework, but it is also quite a manual process. Pax Runner (http:// paxrunner.ops4j.org) is an OSGi framework launcher that takes a lot of the tedium out of installing bundles. Just use Pax Runner’s “spring dm” profile: % pax-run.sh --profiles=spring.dm

The Spring-DM configuration namespace

Schema URI:

http://www.springframework.org/schema/osgi

Schema XSD:

http://www.springframework.org/schema/osgi/spring-osgi.xsd

When it comes to declaring services and service consumers in Spring-DM, you’ll use Spring-DM’s core namespace. To do that, you’ll need to include the namespace in the XML file.


<?xml version=”1.0” encoding=”UTF-8”?>
<beans xmlns=”http://www.springframework.org/schema/beans”
	xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
	xmlns:osgi=”http://www.springframework.org/schema/osgi”
	xsi:schemaLocation=”http://www.springframework.org/
schema/beans
	    http://www.springframework.org/schema/beans/
spring-beans.xsd
		   http://www.springframework.org/schema/osgi
		     http://www.springframework.org/schema/
osgi/spring-osgi.xsd”>
...
</beans>

Spring’s “beans” namespace is the default namespace, but if you know that most or all of the elements in the Spring configuration file will be from the Spring-DM namespace, you can make it the default namespace:

spring beans

Publishing Services

To demonstrate Spring-DM’s capabilities, we’re going to create a few OSGi services that translate English text into some other language. All of these services will implement the following Translator interface:


package com.habuma.translator;
public interface Translator
   {
String translate(String text);
}

The first service we’ll work with is one that translates English into Pig Latin. It’s implementation looks something like this:


package com.habuma.translator.piglatin;
import com.habuma.translator.Translator;
public class PigLatinTranslator implements Translator {
	private final String VOWELS = “AEIOUaeiou”;
	public String translate(String text) {
	  // actual implementation left out for brevity
	}
}

If we were working with basic OSGi (that is, without Spring- DM), we’d publish this service to the OSGi service registry using the OSGi API, perhaps in a bundle activator’s start() method:


public void start(BundleContext context) throws Exception {
	context.registerService(Translator.class.getName(),
				new PigLatinTranslator(), null);
}

Although the native OSGi approach will work fine, it requires us to work programmatically with the OSGi API. Instead, we’ll publish services declaratively using Spring-DM. The first step: Create a Spring context definition file that declares the PigLatinTranslator as a Spring bean:


<?xml version=”1.0” encoding=”UTF-8”?>
<beans xmlns=”http://www.springframework.org/schema/beans”
		xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
		xsi:schemaLocation=”http://www.springframework.org/
schema/beans
		  http://www.springframework.org/schema/beans/springbeans.
xsd”>
  <bean id=”pigLatinTranslator”
    class=”com.habuma.translator.piglatin.PigLatinTranslator” />
</beans>

Hot Tip

Overriding the context configuration location By default, the Spring-DM extender looks for all XML files located in a bundle’s META-INF/spring folder and assumes that they’re all Spring context definition files that are to be used to create a Spring application context for the bundle; however, if you’d like to put your context definition files elsewhere in the bundle, use the Spring-Context: header in the META-INF/ MANIFEST.MF file.
For example, if you’d rather place your Spring configuration files in a directory called “spring-config” at the root of the bundle, add the following entry to your bundle’s manifest: Spring-Context: spring-config/*.xml

This Spring context file can be named anything, but it should be placed in the Pig Latin translator bundle’s META-INF/ spring directory. When the bundle is started in an OSGi framework, the Spring-DM extender will look for Spring context configuration files in that directory and use them to create a Spring application context for the bundle.

Publishing a simple OSGi service

By itself the Spring context we’ve created only creates a bean in the Spring application context. It’s not yet an OSGi service. To publish it as an OSGi service, we’ll create another Spring context definition file that uses the Spring-DM namespace:


<<?xml version=”1.0” encoding=”UTF-8”?>
<<beans:beans xmlns:beans=”http://www.springframework.org/schema/
beans”
		xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
		xmlns=”http://www.springframework.org/schema/osgi”
		xsi:schemaLocation=”http://www.springframework.org/
schema/beans
			http://www.springframework.org/schema/beans/
spring-beans.xsd
			  http://www.springframework.org/schema/osgi
				http://www.springframework.org/schema/
osgi/spring-osgi.xsd”>
   <<service ref=”pigLatinTranslator”
	  interface=”com.habuma.translator.Translator” />
<</beans:beans>

Hot Tip

Don’t mix your Spring and OSGi contexts Although you can certainly define all of your bundle’s Spring beans and OSGi services in a single Spring context definition file, it’s best to keep them in separate files (all in META-INF/spring). By keeping the OSGi-specific declarations out of the normal Spring context definition, you’ll be able to use the OSGi-free context to do non-OSGi integration tests of your beans.

This new Spring context file uses Spring-DM’s element to publish the bean whose ID is “pigLatinTranslator” in the OSGi service registry. The ref attribute refers to the Spring bean in the other context definition file. The interface attribute identifies the interface under which the service will be available in the OSGi service registry.

Publishing a service under multiple interfaces

Let’s suppose that the PigLatinTranslator class were to implement another interface, perhaps one called TextProcessor. And let’s say that we want to publish the service under both the Translator interface and the TextProcessor interface. In that case, you can use the element to identify the interfaces for the service:


<service ref=”pigLatinTranslator”>
  <interfaces>
    <beans:value>com.habuma.translator.Translator</beans:value>
    <beans:value>com.habuma.text.TextProcessor</beans:value>
  </interfaces>
</service>

Auto-selecting service interfaces

Instead of explicitly specifying the interfaces for a service, you can also let Spring-DM figure out which interfaces to use by specifying the auto-export attribute:


<service ref=”pigLatinTranslator”
       auto-export=”interfaces” />

By setting auto-export to “interfaces”, it tells Spring-DM to publish the service under all interfaces that the implementation class implements. You can also set auto-export to “all-classes” to publish the service under all interfaces and classes for the service or “class-hierarchy.”

Publishing a service with properties

It’s also possible to publish a service with properties to qualify that service. These properties can later be used to help refine the selection of services available to a consumer. For example, let’s say that we want to qualify Translator services by the language that they translate to:


<rvice ref=”pigLatinTranslator”
      interface=”com.habuma.translator.Translator”>
<service-properties>
   <beans:entry key=”translator.language” value=”Pig Latin” />
 </service-properties>
</service>

The <service-properties> element can contain one or more <entry> elements from the “beans” namespace. In this case, we’ve added a property named “translator.language” with a value of “Pig Latin”. Later, we’ll use this property to help select this particular service from among a selection of services that all implement Translator.

Consuming Services

Now that we’ve seen how to publish a service in the OSGi service registry, let’s look at how we can use Spring-DM to consume that service. To get started, we’ll create a simple client class:


package com.habuma.translator.client;
import java.util.List;
import com.habuma.translator.Translator;
public class TranslatorClient {
  private static String TEXT = “Be very very quiet. I’m hunting
rabbits!”;
  public void go() {
     System.out.println(“ TRANSLATED: “ +
        translator.translate(TEXT));
  }
  private Translator translator;
  public void setTranslator(Translator translator) {
    this.translator = translator;
  }
}

TranslatorClient is a simple POJO that is injected with a Translator and uses that Translator in its go() method to translate some text. We’ll declare it as a Spring bean like this:


<?xml version=”1.0” encoding=”UTF-8”?>
		<beans xmlns=”http://www.springframework.org/schema/beans”
		xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://www.springframework.org/
schema/beans
			http://www.springframework.org/schema/beans/springbeans.
xsd”>
  <bean class=”com.habuma.translator.client.TranslatorClient”
     init-method=”go”>
   <property name=”translator” ref=”translator” />
  </bean>
</beans>

As with the service’s Spring context declaration, the name of this Spring context definition can be named anything, but it should be placed in the client bundle’s META-INF/spring folder so that the Spring-DM extender will find it.

The bean is declared with the init-method attribute set to call the go() method when the bean is created. And we use the <property> element to inject the bean’s translator property with a reference to a bean whose ID is “translator”.

The big question here is: Where does the “translator” bean come from?

Simple service consumption

Spring-DM’s <reference> element mirrors the <service> element. Rather than publishing a service, however, <reference> retrieves a service from the OSGi service registry. The simplest way to consume a Translator service is as follows:


<reference id=”translator”
interface=”com.habuma.translator.Translator” />

When the Spring-DM extender creates a Spring context for the client bundle, it will create a bean with an ID of “translator” that is a proxy to the service it finds in the service registry. With that id attribute and interface, it is quite suitable for wiring into the client bean’s translator property.

Setting a service timeout

In a dynamic environment like OSGi, services can come and go. When the client bundle starts up, there may not be a Translator service available for consumption. If it’s not available, then Spring-DM will wait up to 5 minutes for the service to become available before giving up and throwing an exception.

But it’s possible to override the default timeout using the <reference> element’s timeout attribute. For example, to set the timeout to 1 minute instead of 5 minutes:


<reference id=”translator”
	interface=”com.habuma.translator.Translator”
	timeout=”60000” />

Notice that the timeout attribute is specified in milliseconds, so 60000 indicates 60 seconds or 1 minute.

Optional service references

Another way to deal with the dynamic nature of OSGi services is to specify that a service reference is optional. By default, the cardinality of a reference to a service is “1..1”, meaning that the service must be found within the timeout period or else an exception will be thrown. But you can specify an optional reference by setting the cardinality to “0..1”:


<reference id=”translator”
	interface=”com.habuma.translator.Translator”
	cardinality=”0..1” />

Filtering services

Imagine that we have two or more Translator services published in the OSGi service registry. Let’s say that in addition to the Pig Latin translator there’s also another Translator service that translates text into Elmer Fudd speak. How can we ensure that our client gets the Pig Latin service when another implementations may be available?

Earlier, we saw how to set a property on a service when it’s published. Now we’ll use that property to filter the selection of services found on the consumer side:


<reference id=”translator”
	interface=”com.habuma.translator.Translator”
	filter=”(translator.language=Pig Latin)” />

The filter attribute lets us specify properties that will help refine the selection of matching services. In this case, we’re only interested in a service that has its “translator.language” property set to “Pig Latin”.

Consuming multiple services

But why choose? What if we wanted to consume all matching services? Instead of pin-pointing a specific service, we can use Spring-DM’s <list> element to consume a collection of matching services:


<list id=”translators”
	interface=”com.habuma.translator.Translator” />

The Spring-DM extender will create a list of matching services that can be injected into a client bean collection property such as this one:


private List<Translator> translators;
public void setTranslators(List<Translator> translators) {
  this.translators = translators;
}

Optionally, you can use Spring-DM’s <set> element to create a set of matching services:


<set id=”translators”
   interface=”com.habuma.translator.Translator” />

The <list> and <set> elements share many of the same attributes with <reference>. For example, to consume a set of all Translator services filtered by a specific property:


<set id=”translators”
interface=”com.habuma.translator.Translator”
filter=”(translator.language=Elmer Fudd)” />

Testing Bundles

Hopefully, you’re in the habit of writing unit tests for your code. If so, that practice should extend to the code that is contained within your OSGi bundles. Because Spring-DM encourages POJO-based OSGi development, you can continue to write unit-tests for the classes that define and consume OSGi services just like you would for any other non-OSGi code.

But it’s also important to write tests that exercise your OSGi services as they’ll be used when deployed in an OSGi container. To accommodate in-OSGi integration testing of bundles, Spring-DM provides AbstractConfigurableBundleCreatorTests, a JUnit 3 base test class from which you can write your bundle tests.

What’s fascinating is how tests based on AbstractConfigurableBundleCreatorTests work. When the test is run, it starts up an OSGi framework implementation (Equinox by default) and installs one or more bundles into the framework. Finally, it wraps itself in an on-the-fly bundle and installs itself into the OSGi framework so that it can test bundles as an insider.

Writing a basic OSGi test

To illustrate, let’s write a simple test that loads our Translator interface bundle and the Pig Latin implementation bundle:


package com.habuma.translator.test;
import org.osgi.framework.ServiceReference;
import org.springframework.osgi.test.
AbstractConfigurableBundleCreatorTests;


import com.habuma.translator.Translator;
public class PigLatinTranslatorBundleTest
      extends AbstractConfigurableBundleCreatorTests {
  @Override
  protected String[] getTestBundlesNames() {
     return new String[] {
		“com.habuma.translator, interface, 1.0.0”,
		“com.habuma.translator, pig-latin, 1.0.0”
      };
  }
  public void testOsgiPlatformStarts() {
    assertNotNull(bundleContext);
  }
}

The getTestBundleNames() method returns an array of Strings where each entry represents a bundle that should be installed into the OSGi framework for the test. The format of each entry is a comma-separated set of values that identify the bundle by its Maven group ID, artifact ID, and version number.

So far, our test has a single test method, testOsgiPlatformStarts(). All this method does is test that the OSGi framework has started by asserting that bundleContext (inherited from AbstractConfigurableBundleCreatorTests) is not null.

Testing OSGi service references

A more interesting test we could write is one that uses the bundle context to lookup a reference to the Translator service and assert that it meets our expectations:


public void testServiceReferenceExists() {
  ServiceReference serviceReference =
    bundleContext.getServiceReference(Translator.class.
getName());
	assertNotNull(serviceReference);
	assertEquals(“Pig Latin”,
       serviceReference.getProperty(“translator.language”));
}

Here we retrieve a ServiceReference from the bundle context and assert that it isn’t null. This means that some implementation of the Translator service has been published in the OSGi service registry. Then, it examines the properties of the service reference and asserts that the “translator.language” property has been set to “Pig Latin”, as we’d expect from how we published the service earlier.

Testing OSGi services

One more thing we could test is that the Translator service does what we’d expect it to do. Certainly, this kind of test usually belongs in a unit test. But it’s still good to throw a smoke test its way to make sure that we’re getting the service we’re expecting.

We could use the ServiceReference to lookup the service. But, we can avoid any additional work with the OSGi API by having the Translator service wired directly into our test class. First, let’s add a Translator property and setter method to our test class


private Translator translator;
public void setTranslator(Translator translator) {
  this.translator = translator;
}

When the test is run, Spring will attempt to autowire the property with a bean from its own Spring application context. But we haven’t defined a Spring application context for the test yet. Let’s do that now:


<?xml version=”1.0” encoding=”UTF-8”?>
<beans:beans xmlns:beans=”http://www.springframework.org/schema/
beans”
		xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
		xmlns=”http://www.springframework.org/schema/osgi”
   xsi:schemaLocation=”http://www.springframework.org/schema/
beans
      http://www.springframework.org/schema/beans/spring-beans.
xsd
    http://www.springframework.org/schema/osgi
    http://www.springframework.org/schema/osgi/spring-osgi.xsd”>
  <reference id=”translator”
    interface=”com.habuma.translator.Translator” />
</beans:beans>

You’ll recognize that this Spring context definition looks a lot like the one we created for the service consumer. In fact, our test class will ultimately be a consumer of the Translator service. We just have one more thing to do before we can test the service—we’ll need to override the getConfigLocations() method to tell the test where it can find the context definition file:


@Override
protected String[] getConfigLocations() {
   return new String[] { “bundle-test-context.xml” };
}

Now we can write our test method:


public void testTranslatorService() {
	assertNotNull(translator);
	assertEquals(“id-DAY is-thAY ork-wAY”,
       translator.translate(“Did this work”));
}

This method assumes that by the time it is invoked, the translator property has been set. It first asserts that it is not null and then throws a simple test String at it to test that the service does what we expect.

Changing the tested OSGi framework

By default, Spring-DM tests are run within Equinox. But you can change them to run within another OSGi framework implementation such as Apache Felix or Knopflerfish by overriding the getConfigLocations() method. For example, to run the test within Apache Felix:


@Override
  protected String getPlatformName() {
    return Platforms.FELIX;
}

Or for Knoplerfish:


@Override
protected String getPlatformName() {
  return Platforms.KNOPFLERFISH;
}

Providing a Custom Manifest

When a Spring-DM test gets wrapped up in an on-the-fly bundle, a manifest will be automatically generated for it. But if you’d like to provide a custom manifest. To provide a custom manifest for the on-the-fly bundle, all you need to do is override the getManifestLocation(). For example:


protected String getManifestLocation() {
  return “classpath:com.habuma.translator.Translator.MF”;
}

Be aware, however, that if you provide a custom manifest, you must include a few things in that manifest to make Spring-DM testing work. First, you’ll need to specify a bundle activator:


Bundle-Activator: org.springframework.osgi.test.JUnitTestActivator

And you’ll need to import JUnit and Spring-DM packages:


Import-Package: junit.framework,
  org.osgi.framework,
  org.apache.commons.logging,
  org.springframework.util,
  org.springframework.osgi.service,
  org.springframework.osgi.util,
  org.springframework.osgi.test,
  org.springframework.context

References

Example Source Code:

http://www.habuma.com/refcard/spring-dm/translator.zip

Spring-DM Homepage:

http://www.springframework.org/osgi

OSGi Alliance:

http://www.osgi.org

Modular Java on Twitter:

http://twitter.com/modularjava

Craig’s Modular Java Blog:

http://www.modularjava.com

Craig’s Spring Blog:

http://www.springinaction.com

56 76

About The Author

Photo of Craig Walls

Craig Walls

is a Texas-based software developer with more than 15 years experience working the telecommunication, financial, retail, education, and software industries. He’s a zealous promoter of the Spring Framework, speaking frequently at local user groups and conferences and writing about Spring and OSGi on his blog. When he’s not slinging code, Craig spends as much time as he can with his wife, two daughters, six birds, and two dogs.

Craig’s Publications:

  • Modular Java: Creating Flexible Applications with OSGi and Spring, 2009
  • Spring in Action, 2nd Edition, 2007
  • XDoclet in Action, 2003

Craig’s Blog: http://www.springinaction.com

Recommended Book

Spring in action

Newcomers will find a thorough introduction to the framework, while experienced Drupal developers will learn best practices for building powerful websites. With Using Drupal, you’ll find concrete and creative solutions for developing the exact community website you have in mind.


Recommended Book

ModularJava

Modular Java is filled with tips and tricks that will make you a more proficient OSGi and Spring-DM developer. Equipped with the know-how gained from this book, you’ll be able to develop applications that are more robust and agile.

Share this Refcard with
your friends & followers...

DZone greatly appreciates your support.


Your download should begin immediately.
If it doesn't, click here.

Daily Dose: Microsoft Adding More Support for C++

In a research paper published by Google last week, C++ was found to be the best-performing programming language in the market, trumping Java, Scala, and its own Go language after a number of tests. Today, Microsoft revealed its plans to make C++ more suited...

0 replies - 10152 views - 06/15/11 by Ross Jernigan in Daily Dose

Daily Dose - NoSQLs Join Forces

NoSQL backers Membase and CouchOne just announced that they are merging to create Couchbase, Inc.  Combining the caching and clustering technology of Membase, and the document database capabilities of CouchDB, the newly-minted Couchbase company will be...

0 replies - 18210 views - 02/09/11 by Katie Mckinsey in Daily Dose

Daily Dose - CloudBees Adds Another Java All-Star

A few weeks ago, CloudBees, a cloud infrastructure that lets developers write code, test it, and put it into production on a PaaS, acquired InfraDNA—the infant startup of Hudson creator Kohsuke Kawaguchi, who left Oracle this year.  I spoke with CloudBees...

0 replies - 20994 views - 12/15/10 by Mitchell Pronsc... in Daily Dose

Daily Dose - Eclipse Believes There is Hope for Java 8

Last month, Eclipse Executive Director Mike Milinkovich stated his reservations about the Jigsaw brand of modularity in Java 8.  It is now a surprise that Eclipse is supporting the new JSR for Java 8.  It was originally thought that the Jigsaw modularity...

2 replies - 23242 views - 11/24/10 by Mitchell Pronsc... in Daily Dose

Daily Dose - Android Adds More Countries to the Marketplace, Plus Skype

A lot of Android news has happened in this past week.  Google CEO Eric Schmidt claims that the increase in advertising due to Android has already covered the cost of the platform's development, but Bill Ray of the Register seems skeptical.  Google also...

0 replies - 12596 views - 10/06/10 by Mitchell Pronsc... in Daily Dose

Daily Dose - Helios First Service Release

This week's Eclipse 3.6.1 release does not contain any new functionality but provides a healthy amount of bugfixes for the first service release of the "Helios" edition.  Helios consists of about 40 Eclipse projects, including IDEs for Java, PHP,...

1 replies - 15397 views - 09/28/10 by Mitchell Pronsc... in Daily Dose

Daily Dose - Virgo M4 Prepares for Equinox Upgrade

The first beta of the Virgo Web Server (formerly the Spring dm Server) is getting very close now that the Eclipse Foundation released the fourth milestone recently.  M4 features various build and test improvements along with several bugfixes.  OSGi...

0 replies - 16000 views - 09/07/10 by Mitchell Pronsc... in Daily Dose

Daily Dose - Juicy Details About Scala 2.9

It seems that the Scala community is perfectly willing to convert their projects to the new 2.8 binaries (Scala 2.8, released last month, was not binary compatible with 2.7).  Over 50% of more than 500 projects have already been converted.  After a bugfix...

11 replies - 20755 views - 08/11/10 by Mitchell Pronsc... in Daily Dose

Daily Dose - Eclipse Gemini Blueprint Reaches Milestone One

The Oracle-SpringSource venture, Gemini, is finally bearing fruit this month with the release of the OSGi 4.2 Blueprint Reference Implementation.  The Blueprint spec builds on top of the Spring Dynamic Modules v2 code base.  Gemini Blueprint is available...

0 replies - 11356 views - 07/07/10 by Mitchell Pronsc... in Daily Dose

Daily Dose - Spring Roo 1.1 Supports GWT, GAE, and Solr

With the first milestone release of Spring Roo 1.1.0, Project Lead Ben Alex says you can build a working web app with a Google Web Toolkit (GWT) front-end in as little as 200 keystrokes.  That's right, deep GWT support is finally here for Spring...

0 replies - 20084 views - 05/20/10 by Mitchell Pronsc... in Daily Dose

Have you started using Spring Dynamic Modules yet?

Get started now! Download the latest DZone Refcard: Getting Started with Spring-DM. 

0 replies - 5272 views - 06/08/09 by Lyndsey Clevesy in Announcements