A New Approach to Software Development

A Gentle Introduction to OSGi

JeromeMoliere
A-Gentle-Introduction-to-OSGi

Jerome Moliere offers reasons to use OSGi, and introduces philosophy and key tools.

This is an attempt to give readers the necessary clues to start
developing on the OSGi platform. This article will offer reasons to
use such technology, and introduce philosophy and key tools.

For over a decade a group of companies interested in providing
software for embedded devices, then for more usual platforms
(desktop or server side ones,) started to work on writing
specifications for a logical platform aimed at hosting applications
while placing emphasis on different criteria:

• modularity

• efficiency

• small footprint

• dynamic aspect

Among them we can find:

• BMW Automotive

• Siemens, etc…

OSGi specifications are divided into two major books:

• OSGi Core, contains the base API for working with OSGi,
especially the stuff related to bundles.

• OSGi compendium, offering specifications for the whole set of
standard services, services available to any compliant OSGi
container.

This tale, which started with a focus on embedded devices,
turned out to embrace the whole spectrum of software. Success
stories, products based on OSGi, are the best way to show what you
can do with OSGi: Eclipse (based on an OSGi implementation called
Equinox since 3.1 release), Glassfish 3 or Jonas 5 (JEE application
servers).

For extended features, we may look to extended specifications
with:

• Enterprise OSGi, offering an enhanced set of APIs aimed at
easing enterprise centric development (JPA integration.)

• Distributed OSGi, offering mechanisms to distribute
applications running on top of a collection of Java Virtual
machines.

OSGi Keypoints

 

OSGi specifications use Java as a
base while avoiding classic Java headaches with a special
classloading policy. The OSGi classloader deviates from the
standard Java classloading policy while offering a way to support
these impossible features:

 

• running several versions of the
same component inside the same JVM

• true class reloading

 

With such power, efficient
application reloading becomes possible. So OSGi needs to extend
standard Java to deliver components, that’s why it just wraps the
standard Java deployment format (.jar) while adding metadata into
the misunderstood META-INF/MANIFEST.MF file.

 

The OSGi platform hosts components
offering services to other components (called bundles in OSGi
jargon) and may depend on services offered by other bundles. It’s a
real microcosm but with a dynamic facet, where services can appear
or disappear at any time. Figure 1 models such relationships
between bundles.

 

 

MANIFEST.MF file will contain all
meta information required to express such relationships for each
bundle. The following listing shows contents from one bundle
requiring at runtime one service for logging purpose (it’s the
standard OSGi logging service), this service may have different
implementations but that’s not the problem for our code. Please
refer to the sample code provided in this article.

 

Bundle
Lifecycle

 

In such a dynamic environment,
components (packaged as jar files called bundles) may be installed,
deployed, stopped or removed. Figure 2 from the OSGi Alliance
website shows transitions into the different states possible for a
bundle. The next section introduces OSGi shells, offering commands
to control bundles states.

 

 

OSGi Shells

 

OSGi defines containers made to host
applications delivered as bundles (the unit of deployment). The
runtime controlling your applications is called a shell like Unix
shells manage programs. Working with OSGi means delivering
(provisioning) your application as bundles and deploying them into
a shell. You may choose between different equivalent OSGi
implementations:

 

Apache
Felix

Eclipse
Equinox

Knopflerfish
from Makewave

 

You may use extensions from the OSGi
specifications and use:

 

Paremus shell (for Distributed OSGi)

• Apache CXF

• Eclipse ECF

 

or for Enterprise OSGi products
like:

 

Apache Aries

• Apache Karaf is a useful shell
too

What can a shell do for you? Just getting full access to the
bundles lifecycle while also providing an elegant way to integrate
your own commands. If the commands list may change from one product
to another, every shell will give you at least access to the
bundles lifecycle, so you will be able to :

 

• install/uninstall a bundle

• start/stop a bundle

• get the list of installed bundles
with their current state.

 

Choosing a Shell

 

It’s a matter of choice but the
writer uses felix for its very low footprint and tests its plugins
with knopflerfish for convenience (graphic shell is very close to
the specifications).

 

Services &
Tracking

 

From the OSGi point of view, a
service is just a plain Java interface, this interface may be
implemented in different manners. In such a dynamic environment,
getting references to one of the compatible implementations is an
absolute requirement. You may use one of the following ways to
achieve this goal:

 

• use standard OSGi API.

• use the ServiceTracker to get a
more convenient result.

• use the SCR or Declarative
Services, to have an easy and powerful way to inject dependencies
at runtime, like Spring Core does (Spring simply does dependency
injection)

 

OSGi Standard Services
List


OSGi defines the following list of
services:

 

• http service, to expose with a Web
interface resources contained in one bundle.

• logging service, to trace events
encountered during runtime.

• event services, is a mono JVM
(OSGi container related only) messages broker.

• configadmin, offers a complete API
dedicated to storing configuration data for your bundles.

• preferences, describes how to
store user preferences.

• metatype, enables modelling of
meta data related to your structures and to handle them gently into
GUIs.

• SCR or Declarative Services, is
the way to inject dependencies into any service at runtime.

 

       
    

We’ll have a closer look
at…

 

… two of these services:
LoggingService and EventAdmin with complete code samples. In the
first sample, we will send traces and retrieve them with the
LogService API. Sending traces is trivial, just injecting a
reference to the LogService, then using it to store LogEntries.
Reading these traces is not difficult while using the
LogReaderService (Listing 1).

 

 

Figure 3 shows the results of two
such bundles installed in a Felix container.

 

 

Listing 2 illustrates how OSGi
provides a smart way to master coupling between bundles using a
‘messages broker’like : EventAdmin. Sending events with EventAdmin.
Figure 4 shows events in action.

 

 

The two bundles use a naming
convention while sharing a common topic, the object storing
messages (events in the EventAdmin wording). It’s important to
ensure to use the same name in both bundles to get a working
communication.

 

         
 
      

Modularity &
OSGi

 

Where does modularity come from in
the OSGi world? Modularity in the OSGi jargon is not just bullshit,
it comes from the strict cutting of responsibilities between
components deployed into the OSGi container (bundles). The contract
between a bundle and the container is the key point, it is
materialized using the META-INF/MANIFEST.MF file. This contract
lists explicitly what the component offers to the platform and what
it requires from it. Defining services as Java interfaces into API
bundles (delivering concrete implementations of this service in
separate bundles) and specifying dependencies to the only API
bundle, enables us to change the implementation bundles without any
impact on the client components. It’s just a ‘component aware’
manner to translate the TAO of object modelling, where you should
use the most generic interface of a class rather than the most
specific one. Conforming to this rule is necessary to do modular
development.

 

A component requiring a service does
not need to know the implementation delivering this service, it is
the ‘black box’ principle. You don’t need to be a mechanical
specialist to start your car.

 

With such a low level of coupling
between components, good design principles become trivial, like the
one of mocking components while testing your applications following
Test Driven methodologies. Such design is the key to get working
architectures in very short timeframes, the whole application
feature list is being completed with the next releases if you
follow an agile scheduling (XP, Scrum or whatever methodology you
want). Many solutions may exist while trying to use a service. If
using the basic OSGi API raises many problems and induces a lot of
codelines, using the ServiceTracker while injecting service
references directly into your component may be the better
solution.

 

 

SCR is a very dynamic and powerful
solution, using it can be as simple as using the XML form or
annotation as provided by bnd
(refer to the tooling section). It’s the best architectural
response to the problems raised while trying to handle dependencies
to services appearing/disappearing during the
runtime phase.
It’s not the only one because since early releases of
specifications, OSGi provided different ways to do this job
(ServiceTracker or through the Service API ).

 

Working with
OSGi

 

What is the arsenal of weapons to
deploy to work with OSGi?

The answer will include different
facets of work, that is to say:

• Development

• Debugging

• Deployment

• Integration into an integration
process (Continuous Integration)

 

1. Basic Brick

 

As with any Java based environment,
you just need to code into Java, but providing metadata requires
you to master the tricky MANIFEST.MF file format. This text based
format has many traps and it sounds like a good idea not to handle
them directly, but instead to delegate the generation of this file
to a dedicated tool. Here comes bnd to the rescue. Bnd by Peter
Kriens, OSGi Alliance fellow, is a versatile tool, the Swiss army
knife OSGi tool. Bnd has three main roles, and it can perform three
kind of jobs for you:

 

• inspecting a bundle

• wrapping a library into a
compliant bundle

• creating a bundle from your
code

 

Bnd comes with its own syntax and set of directives, it’s very
rich and only dedicated to one thing: having more compliant
bundles, more quickly. Bnd scans your code to fetch imports so it
computes for you the long list of imported packages. Bnd inspects
contents from your code and generates the import-package clause
from MANIFEST.MF for you. It can’t guess what services you want to
expose so you must take care of this. You need to provide the
privatepackage clause too.

   

1. IDE
integration

 

BndTools by Neil Barlett is the most
powerful environment for OSGi development. It is an Eclipse plugin
wrapping bnd features with a clear and intuitive interface. It just
works!!! BndTools provides a new kind of project with a Bnd OSGi
project. After creating such a project you’ll be able to access the
following features:

 

• directly test your code in Eclipse
with your preferred shell

• watch/edit the contents from your
MANIFEST.MF file

• inspect the contents from one
bundle

• declare dependencies injection
graphically with a dedicated wizard

• manage your runtime environment
(adding bundles to be included in your shell at runtime)

• handle import/export clauses of
your bundles graphically without any other intervention besides
drag and drop.

 

This tool is an incredible one,
powerful and easy, providing bundles close to the specifications
and close to the state of the art in OSGi development. Figure 6 and
7 show BndTools in different situations.

 

 

Using this tool involves using a
workflow like the following:

 

• create a new Bnd OSGi project

• create a Java package

• create some code (interface +
implementation for a service or a single concrete Java class for a
client)

• create a new bnd bundle
descriptor

• adjust the bnd.bnd descriptor to
suit your needs

• run the bnd.bnd with a Run As OSGi
application (right click)

 

Here you are, you have created your
first bundle with Bnd-Tools.

 

 

 

Please ensure to modify the
Components tab view from each bundle using Declarative Services and
adding one or more (maybe a joker) list of components. BndTools
used in conjunction with Peter Kriens’s annotations provide a very
convenient way to inject components without even writing a single
line of XML as used by SCR. We’ll take our simple use case once
again and rewrite it using BndTools and Bnd annotations. The
following listings contain the complete source code for Java code
and bnd files required in our context.

 

2. Debugging with Felix Web
bundles


What can go wrong during runtime?
You may have unsatisfied dependencies, not so easy to find while
the application is running (tricky indeed). The best solution is to
install Felix WebConsole and to connect to this console through
your browser to diagnose the origins of your problem. This is a
very nice tool, easy to use and install. It has a few dependencies
as shown in the next picture.

 

 

 

 

Figures 10-12 show some facets from
this very useful tool. You may use the different tabs offered to
ensure that:

 

• all bundles have the expected
state

• all dependencies are met messages
(events in the EventAdmin wording). It’s important to ensure to use
the same name in both bundles to get a working communication.

• bundles implement the expected
services

 

Moreover the WebConsole can be used
to view trace entries as issued by LogService and last but not
least it is an extensible component. To conclude with this tool we
should mention these requirements:

 

• code makes usage from NIO so
ensure your JVM offers this API

• webconsole is just a war deployed
into the HttpService, so it requires you to install the Jetty Web
bundle

• optional dependency to
LogService

• Provisioning with Felix
FileInstall

 

FileInstall provides an easy way to
install bundles into your OSGi container, using a single
configuration file you will be able to configure one or several
repositories (directories) targeted to host bundles and
configuration properties file (for the ConfigAdmin Service). This
bundle used in conjunction with the SCR is the perfect way to
automate application starting, while having no hassles with the
runlevels. It is a very convenient way to configure your
application simply by setting a few properties as shown in the next
sample. This sample shows properties used by Felix FileInstall to
configure one deployment directory (felix.fileinstall.dir) and the
polling interval (one second here), because Felix Install acts as a
watchdog. These properties may be integrated into the Felix config
file

 

(living into
${felix.dir}/conf/config.properties).

 

felix.fileinstall.dir = deploy

felix.fileinstall.poll = 1000

 

Felix FileInstall can be used as a
replacement or in conjunction with the OBR (Bundles repository).
OBR is an http repository like the ibiblio one for Maven storing
many Java projects ready to use in OSGi environments.

 

Conclusion

 

I wish you a good trip into this new
approach to software development, I am convinced that it should
bring you success and fun, success because of its efficiency and
great design, fun because of the pleasure felt in designing
applications that just work! I have still many things to write
about this technology but it is time for me to conclude. Happy
coding.

Author
JeromeMoliere
Jerome Moliere discovered Java early 1996, he is a SCJP2 and JBoss certified architect. He is doing consulting and training for his own company Mentor/J. He is about to deliver the first French book dedicated to OSGi. He can be reached at jerome@javaxpert.com. He blogs at http://romjethoughts.blogspot.com/
Comments
comments powered by Disqus