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