OSGi quick start
I’ve been playing a bit with OSGi last time. The OSGi platform can be a good starting point for developing SOBA’s. OSGi has some nice features like dependency handling, multi version support, and remote management to applications. The explicit export and import of packages between bundles is very useful for keeping a good separation of concerns. However, I also encountered a couple of details which can save you a lot of time if you know them on beforehand. I’d like to share some recommendations which are hopefully helpful for you.
Getting started
No better place to start than these very useful tutorials.
Eclipse PDE
I highly recommend to use the Eclipse Plug-in Development Environment when developing OSGi bundles. It helps a lot in defining the manifest file, managing the dependencies between bundles (also at design time), etc. New bundles can easily be created using ‘File > New > Plug-in Project’. However, in the next window you shouldn’t forget to choose ‘standard’ as target platform. This will ensure compliance with the OSGi standard instead of adding Equinox specific behavior.
Classpath
At some point you definitely want to add some libraries to your bundle. Not every external jar should be loaded as a bundle in the OSGi framework. You can include jar files by adding the following line to the manifest file of the bundle: ‘Bundle-ClassPath: ., lib/commons-lang-2.4.jar’. Pay some attention to the ‘.’. This will include the root dir of the bundle in the classpath. If you skip the ‘.’, your own source code isn’t on the classpath (that won’t work).
Declarative Services
It is possible to define the services bundles expose and use from each other with XML. This can be done using OSGi Declarative Services (a part of the OSGi standard) or by using Spring Dynamic Modules for OSGi Service Platforms. For now OSGi Declarative Services has done the job for me, so I’m sticking to the official standard. However, if you already have developed everything using Spring it will be easier to use Spring-DM.
Declarative Services gives the option to define reference to other services. It is also possible to specify the cardinality of the reference. The cardinality is specified using two numbers, the first one, 0 or 1, indicates the optionality, the second one, 1 or n, indicates the multiplicity.
One special case can occur using these cardinalities. Imagine two services referencing to each other using the cardinality "1..1". In that specific case the OSGi framework will throw an org.eclipse.equinox.internal.ds.CircularityException. That’s because the first ‘1′ means that the service can’t be started without having the referenced service available. Changing one of the cardinalities to "0..1" will break the circle and everything will start fine including the services having both a reference to each other.
Log bundle
It is always handy to include a log bundle in your target platform, especially while using declarative services. By example, if you use equinox include the bundle org.eclipse.equinox.log. If the log service is registered you can look up the log by typing ‘log’ into the OSGi console. In this log the exceptions encountered during the parsing of the Declerative Services xml will be printed.
Classloader
Each existing piece of java code can be used as an OSGi bundle. If Declarative Service is used even no OSGi specific code is needed. However, at least one exception exist when porting existing code to OSGi. In a lot of code (just scan some open source projects) the method Thread.currentThread().getContextClassLoader() is used. This method returns ‘null’ if called within an OSGi bundle (and this mostly results in a NullPointer exception because most developers don’t expect this).
In Java code very often the system classloader or the thread’s classloader is used, while in OSGi only the bundle’s classloader can be used. This can easily be fixed by using getClass().getClassLoader(). If you use third-party libraries which can’t be changed, you can set the thread’s classloader before calling the library methods using Thread.currentThread().setContextClassLoader(cl). This isn’t the most elegant solutions, but it works on all OSGi frameworks.
The Knopflerfish OSGi framework contains code which can automatically patch existing Java code (including classloader problems, static main’s, imports and exports). See this presentation for more information.
Resources
What I really like when working with OSGi is the availability of a full specification. Mostly when working with third-party frameworks you have to fall back to diving into source code (if possible) or to google (see if someone else has the same obscure problem you encounter). In case of OSGi most things can be found in the specification. Don’t forget to download the "OSGi Service Platform Service Compendium", it has a lot useful information in addition to the core spec. By example chapter 112 about Declarative services.
Another useful resource is the JavaDoc of the OSGi framework. However, if you make use of Declarative Services you won’t need any OSGi specific code.
4 Comments Added
Join DiscussionThe following error when I click the link http://neilbartlett.name/blog/osgi-articles/
Error establishing a database connection
As far as I can see everything just works fine…
Thanks for this article! It just gets to the point and has helped me more than the (felt) hundreds of longer articles I’ve read by now. Especially the part about ClassLoader gave me the hint of how
to solve my problem.
Classloader part was really helpful . Thank you 🙂