Wednesday, 13 January 2010

Agile OSGi with Eclipse and Nimble

There's a view that doing things 'the OSGi way' adds overhead. In fact, I have even been told in the past "don't worry about the modularity thing just now, just get the demo out of the door".

However, for me, working with OSGi is a no brainer, and adds virtually no overhead even for the smallest projects. Additionally, I find that not only is it sensible to start with OSGi, but doing so speeds up my ability to deliver quality modular software.

There are a couple of tools that help make life easy for me (as it should be for a developer) so that I am not wasting time with my environment. These tools are Eclipse and Nimble.

Firstly, my IDE, Eclipse. I give it a hard time sometimes but it does let me get on in what I feel is a very productive manner. Eclipse 3.5 is generally great and has even more support for OSGi and my personal favourite is the support for declarative services - the editor making it very easy to spit out the required XML making it really quick to build a component based bundle in hardly any time. For those 'small' projects that people consider an overhead, I still recommend this approach, as it is noddy to add a main method (either to that component or another class which uses that component) and you still end up with a jar file you can execute from the command line, especially if you add the Main-Class attribute to the manifest. At the end of the day we're still talking about simple Java objects, but with a little bit of extra metadata.

Finally, the key to clarity when developing OSGi apps in Eclipse is 'targets'. So for each workspace I would create a meta-project that contains an Eclipse target and any top level external dependency bundles. The target references these bundles and when I apply the target to my workspace I now only have visibility of the exports from the bundles in the manifest editor, and those plugins in Eclipse's plugin perspective. All the noise from the hundreds of bundles that Eclipse uses to run is gone.

(For me, the only thing that lets Eclipse down is that I feel it could be more defensive about how it handles plugins which don't always play nicely)

Until recently I made the framework I was deploying to a big part of the development architecture. In fact I would write an ant script to build my bundles, the framework, it's dependencies and then deploy my bundles in to that framework and then run it to do my integration testing.

While doing a development cycle of code/compile/deploy I would tend to have Felix running with fileinstall configured to look at a folder called plugins and then use Eclipse's export tool to drop new versions of my bundles in to that folder. Fileinstall detects the new bundles and adds/updates as appropriate. But what about dependencies? They would have to already be installed in the framework. For for each external dependency I am using I would have to resolve that bundle's dependencies manually... if those bundles have dependencies and so on, this soon becomes long winded and tedious!

These days I am much more agile about this and use 'Nimble', which is OSGi resolver technology from Paremus. To use Nimble, you simply install it and you get 'posh' - the Paremus OSGi Shell, another clever piece of technology that can save a lot of time.

So if I wanted to test my application on Felix I would start posh as follows:

posh -C -F

The -C parameter clears the cache and downloads dependencies from scratch. -F specifies that I want to use Felix as my framework. In a few seconds I have a running Felix OSGi framework and a sophisticated OSGI shell but not much else. (At this point the docs on posh are really useful to see what you can do.)

Once I've indexed my bundles I create a nimble rule which defines a dependency on the activated state of my bundles and osgi services and save this in an xml file of it's own to the plugins folder as well:

Using the command 'nim add app/myapp' my bundles are installed, resolved (including dependancies) and started.

The last thing I have to do is tell the HttpService what port to start port:
setpid org.apache.felix.http org.osgi.service.http.port==8080

but I only have to do that once per Posh session.

The key thing here is that all my dependencies are resolved for me. I don't have to do anything except worry about my production bundles.

Then when I want to distribute my application to colleagues or the customer or deploy to another environment, I just distribute the bundles and my repo xml files, and they fire it up with minimal effort. Glorious!

Please note, that the above does not necessarily constitute best practice. I have been chatting with the Paremus guys about best practices and will follow up with information about that at a later date.

No comments: