With the release of the OSGi Enterprise Specification a whole new set of developers will be trying to figure just what the hell you can do with this OSGi technology anyway?
Those who have started to explore it will have found that surprisingly OSGi doesn’t tend (initially) to make development easier, it also doesn’t tend (initially) to reduce the amount of code you need to write. So what then is it good for?
The key feature of OSGi is that it allows for proper modularization of Java software. There’s a lot of good information out there on the interweb about why modularization is important – but the key message is that modularization allows you to decide what are the building blocks of your application. Not at the nuts and bolts level that is Object Orientation and not at the red car or blue car level that is SOA, but at the intermediate level of engines, tires and gearboxes – where most engineers really like to play…
OSGi makes the task of building sets of applications easier. It is not about building one application but about building applications from applications, software reuse, yada yada, or as I like to think of it – turtles all the way down.
All this sounds great, but in order to build good modular software it is important to decide what are the public parts of your architecture, what are the bits you’d rather keep private and which parts you want to inherit from others. This process is achieved in OSGi via importing and exporting packages between bundles. It is also highly advantageous to use the OSGi services model which allows you to neatly hide implementation specific code behind interfaces and plug in and out different providers at runtime.
The problem now becomes that as you depend on more and more bundles the task of managing that list of bundles becomes more and more onerous. Most peoples first experiences with OSGi (mine included) is a frustrating iteration of trying to start a given bundle but getting a loud exception message saying that a given bundle cannot be resolved because some of its dependencies are missing. You then add bundles that satisfy these dependencies but find that these dependencies are transitive, so satisfying the top level dependencies just leads to another deeper search for the bundles that satisfy those dependencies. You finally get all the required bundles installed and activate your top level bundle and click on the web browser or ui and nothing happens. Silly you, you have forgotten to activate the bundles that provided supporting services for your application.
The benefits of OSGi are obsured by the complex task of managing both the api level and service level dependencies. Which bundles do I need installed? Which bundles do I need to activate? If I remove this bundle what are the consequences? If I stop my application what else can be tidied up? All these questions are exactly those we started asking ourselves when we started writing OSGi applications and Nimble is the logical conclusion of this work.
The interesting thing is that Nimble is in fact built upon the very modularity information that is so complex for developers to navigate, all of this information is actually perfect for a computer to make reasoned judgements about. Given a set of bundles Nimble can very rapidly traverse the set of bundles that need to be installed and activated to make your application work, and when you’re done it will tidy it all away again.
Sample JEE application
To see how this works in practice let’s see how to build a traditional three tier application comprised of a web tier, a business tier and a data access tier. For this example we’re going to reuse the AriesTrader sample provided as part of the Aries project. This sample uses six different parts of the OSGi Enterprise specification.
- Blueprint (Spring Beans)
- JDBC
- JNDI
- JPA
- JTA
- Web Applications
When fully installed this application is comprised of more than fifty individual bundles which could be a real headache to download, install and activate manually. However using Nimble this process is easily managed using it’s advanced resolver capabilities and scripting support.
So running the sample…
Before proceeding you should check that your version of Nimble is up to date. You can do this using the “version” command from the cli. This example requires that you have at least version 1.0.14 installed. For information on upgrading Nimble refer to our online documentation.
As Aries is still in the incubation phase at Apache there are not yet any released artifacts we can build against, so if you want to run these samples you will need to check out the source code from svn and build it yourself – there are instructions on how to do this here. To run the Aries trader sample we also need to download and install derby, again instructions can be found here.
Having completed these preliminaries I will create the AriesTrader database which the sample application uses to store its data.
$ mkdir /tmp/aries $ cd /tmp/aries $ export CLASSPATH=$DERBY_INSTALL/lib/derby.jar:/opt/lib/derby/lib/derbytools.jar $ java org.apache.derby.tools.ij $ARIES_SOURCE/samples/ariestrader-sample/assemblies/equinox-test-harness/target/tradeDB.sql
Here I’ve created a sample directory on my machine and created the empty database in that directory.
In fact the aries trader sample is pretty simple and assumes the database is located on the same machine and the sample needs to be run from that directory as it assumes the database is located relative to the Java process. I guess it’s important to say that this is a limitation of the sample and not JDBC/JPA in OSGi in general!! But for this example be sure to run Nimble from the same directory that you created the database in – in my case /tmp/aries/.
Let’s now run the aries trader example using a OSGi shell script. To do this launch Nimble via the Posh shell executable located in the bin directory of the Nimble installation and then run the aries-trader script in the console.
[dave@feynman aries]$ $NIMBLE_HOME/bin/posh [feynman.local.0]% pwd file:/private/tmp/aries/ [feynman.local.0]% sh http://chronological-thought.googlecode.com/svn/trunk/nimble-examples/aries-trader.osh Internal Paremus Nimble Developer License, expires Fri Dec 31 23:59:59 GMT 2010. ________________________________________ Welcome to Paremus Nimble! Type 'help' for help. ---------------------------------- - AriesTrader sample application - ---------------------------------- # Enter aries source location: /Users/dave/development/apache/aries Indexing aries:0 -> file:/Users/dave/development/apache/aries/ -> file:/private/tmp/aries/aries.xml include=.*target.*jar exclude=null base=file:/Users/dave/development/apache/aries/ load=false Indexed 32 resources Indexed 64 resources Indexed 96 resources Indexed 128 resources Indexed 160 resources Indexed 192 resources Indexed 224 resources indexed aries:0 Connect to AriesTrader at http://localhost:8080/ariestrader

The first time you run this script it will prompt you for the location of the Aries source folder and will index the osgi bundles you built earlier.
You should be able to verify that the AriesTrader sample is running by browsing to the AriesTrader web application, the address of which is echoed at the end of the aries-trader.osh script. If you want to play around with the AriesTrader application you can populate the database by navigating to the “Configuration” tab on the aries trader web portal and clicking “(Re)-populate AriesTrader Database”. You should see the database data being populated and you can then log in via the “Trading & Portfolios” tab.
A look under the hood
So what’s going on in this example from a Nimble and OSGi perspective? Let’s look at the contents of the “aries-trader.osh” file. To do this we can use the built in “more” command in Nimble:
[feynman.local.0]% more http://chronological-thought.googlecode.com/svn/trunk/nimble-examples/aries-trader.osh
This pages through the contents of the file allowing us to see the contents just like a standard unix more command, one thing to note is that Nimble uses java.net.URI objects in most places where unix would use a file reference so we can more the file directly from the web. So the contents of the file (in bite size chunks)…
tofile = {
path = $it schemeSpecificPart;
new File $path;
};
activate = {
nim add osgi.active.bundle/$it;
};
The first thing I’ve done is declare a couple of closures “tofile” and “activate” that allow me to tidy up boiler plate code that would otherwise be repeated in the rest of the script.
The “tofile” closure converts a java.net.URI object to a java.io.File here you can see that Nimble is able to make reflective calls on Java objects – get methods are camel cased and the return value of the closure is the last object returned.
The “activate” closure just passes the parameter parsed to the “nim add” command which we saw in previous posts to add the specified osgi bundle to this OSGi framework in the active state. I’ve then created some banner code that makes the script a little more user friendly:
echo ----------------------------------; echo - AriesTrader sample application -; echo ----------------------------------;
Now we start the work of the script proper. Nimble figures out the bundles that need installing or activating based on indexes, so in order to load the aries bundles we need to generate an index file that describes their requirements and capabilities. The following section of the aries-trader.osh script shows how I created this index:
aries = tofile ($PWD resolve aries.xml);
if { not { $aries exists } } {
echo # Enter aries source location:;
read sourceDir;
source = new URI $sourceDir/;
pom = tofile ($source resolve pom.xml);
if { not { $pom exists } } {
echo Expected aries source directory;
exit;
};
nim index -viI .*target.*jar aries $source $aries;
};
Firstly I check if a file aries.xml exists in the directory where I’ve run this script, if it does then no action needs to be taken, if not then I need to generate an index. To generate the index I prompt the user to tell me the location of their Aries source folder and make a trivial check that it is in fact the Aries source folder by checking if there is a pom.xml file present in that directory. If all is well I then call the nim index command with a number of options that tell Nimble to generate an index called “aries” in this directory based on files that match the regular expression .*target.*jar from the specified source folder. The result being we get an index file aries.xml of all artifacts built by the maven build. We now need to load the indexes.
nim repos -l $aries; nim repos -l ($0 resolve aries-rules.xml); nim repos -l springdm;
These three commands add the indexes that Nimble will use to build our application. The first entry loads the aries.xml index we generated above, the second adds a second aries index file that I have pregenerated (more on this in a second) and the third adds an index that points at the Spring Enterprise Bundle repository based on a well known alias name “springdm”. Ok so hang on a minute where does this aries-rules.xml file come from? Let’s take a look at it via Nimble:
[feynman.local.0]% more http://chronological-thought.googlecode.com/svn/trunk/nimble-examples/aries-rules.xml <repository name="aries-rules:0" xmlns="http://schema.paremus.com/nri/1"> <rule name="aries.osgi.service/blueprint:0.1.0.incubating.SNAPSHOT"> <req name="builder/primordial.builder" /> <req name="osgi.active.bundle/org.apache.aries.blueprint:0.1.0.incubating.SNAPSHOT"/> <req name="osgi.active.bundle/org.apache.aries.transaction.blueprint:0.1.0.incubating.SNAPSHOT"/> <req name="osgi.active.bundle/org.apache.aries.jpa.blueprint.aries:0.1.0.incubating.SNAPSHOT"/> <cap name="aries.osgi.service/blueprint:0.1.0.incubating.SNAPSHOT" /> <cap name="osgi.service/blueprint.extender:0.0.0" /> </rule> <rule name="aries.osgi.service/jta:0.1.0.incubating.SNAPSHOT"> <req name="builder/primordial.builder" /> <req name="osgi.active.bundle/org.apache.aries.transaction.manager:0.1.0.incubating.SNAPSHOT"/> <cap name="aries.osgi.service/jta:0.1.0.incubating.SNAPSHOT" /> <cap name="osgi.service/jta.provider:0.0.0" /> </rule> <rule name="aries.osgi.service/jndi:0.1.0.incubating.SNAPSHOT"> <req name="builder/primordial.builder" /> <req name="osgi.active.bundle/org.apache.aries.jndi:0.1.0.incubating.SNAPSHOT"/> <cap name="aries.osgi.service/jndi:0.1.0.incubating.SNAPSHOT" /> <cap name="osgi.service/jndi.provider:0.0.0" /> </rule> <rule name="aries.osgi.service/jpa:0.1.0.incubating.SNAPSHOT"> <req name="builder/primordial.builder" /> <req name="osgi.active.bundle/org.apache.aries.jpa.container:0.1.0.incubating.SNAPSHOT"/> <req name="osgi.active.bundle/org.apache.aries.jpa.container.context:0.1.0.incubating.SNAPSHOT"/> <req name="osgi.active.bundle/org.apache.openjpa:2.0.0.beta2"/> <cap name="aries.osgi.service/jpa.provider:0.1.0.incubating.SNAPSHOT" /> <cap name="osgi.service/jpa.provider:1.0.0" /> </rule> </repository>
At the time of writing this file is hand generated, it specifies a number of capabilities that match requirements that are automatically detected from client bundles during the index step above. The capabilities are: osgi.service/jpa.provider, osgi.service/jndi.provider, osgi.service/jta.provider and osgi.service/blueprint.extender. When a bundle is activated that requires one of these capabilities then Nimble traverses its indexes looking for rules that provide these capabilities and resolves the rule plus its requirements. In this case we can see that when a bundle requires the osgi.service/blueprint.extender capability Nimble will install and activate three supporting bundles org.apache.aries.blueprint, org.apache.aries.transaction.blueprint and org.apache.aries.jpa.blueprint.aries.
Here an interesting point is that these osgi.service/xxx.yyy are indirect links to the supporting bundles. In fact if I want to switch to a different provider – say Eclipse Gemini then it is just a case of indexing these bundles instead and Nimble will resolve the bundle dependencies using a different set of providers. I’ll try to do this in a later post when the artifacts are available – stay tuned
The final section of the script loads the aries trader sample bundles:
// trader bundles activate org.apache.aries.samples.ariestrader.util; activate org.apache.aries.samples.ariestrader.core; activate org.apache.aries.samples.ariestrader.beans; activate org.apache.aries.samples.ariestrader.derby.ds; activate org.apache.aries.samples.ariestrader.entities; activate org.apache.aries.samples.ariestrader.persist.jdbc; activate org.apache.aries.samples.ariestrader.persist.jpa.am; activate org.apache.aries.samples.ariestrader.persist.jpa.cm; activate org.apache.aries.samples.ariestrader.web;
Here I’m really focusing on the nine bundles I really need for my application, all of the other bundle dependencies (all forty six of them – which you can see for yourself if you type the lsb command at the Nimble console) are automatically provisioned and configured by Nimble. In fact it is a trivial task to change this script to load the Aries blog sample – an exercise I’ll leave till another post.
So in summary Nimble has allowed us to quickly build up an application with real world components like web services, transactions and databases. We focused simply on top level bundles we require and Nimble resolves and deploys all supporting bundles based on index information that is very easy to generate and reuse between applications.
What’s more for the metathesiophobes (comments on a post card if you know of an actual fear related to dynamic resolution) the resolution path for the dynamically deployed bundles is minutely controllable via the indexes that you add to Nimble – so if you want to prevent certain artifacts from being resolved against because of known bugs etc – simply exclude them from your indexes.
Update: Seems I’m not the only one to have made the turtles reference – Kirk Knoernschild makes the same analogy, probably inadvertently borrowed the same metaphor as I do read his excellent blogs.




