Thus far the biggest headache I’ve found with OSGi is handling third-party libraries which aren’t marked up for OSGi. I’d say roughly 30% of the libraries I’ve used lately were OSGi-ready. It’s a pain because you have to update the jar’s manifest with a list of packages it exports to the container and a list of packages it imports from other bundles. This gets even more irritating when you have to take versioning into account.
So I decided I would leverage my sbt build scripts in some way to update the jars for me. Sure enough, I was able to get a list of all my dependencies (transitive dependencies included!), call BND’s API against the jars, and viola! I’m sure these generated manifests were more verbose than needed, but at least I wasn’t hand-writing them.
Now I had already deployed a handful of jars that I hand-crafted the manifests with success. By the time I got ready to try deploying a web application bundle (wab), I found out I had a LOT of jars to doctor up. Hence the need for my tool.
The first web (micro) framework I wanted to try was Scalatra. I was very intrigued by Yuvi Masory‘s interview with Ivan Carrero, a core developer of Scalatra. I grabbed the obligatory “hello world” project and began running my osgi-ify tool against all of the dependencies. Through many annoying iterations, I finally got all of them deployed and running. I packaged up my hello world app into a war file, and doctored up its manifest (I have yet to take the time to automate OSGi manifest creation for a wab).
I deployed Scalatra, and it exploded with one of those scary as hell Java errors that you fear when mucking around in alternative JVM languages:
java.lang.NoClassDefFoundError: org/scalatra/servlet/ScalatraListener (wrong name: org/scalatra/RailsRouteMatcher$Builder)
Several weeks later, I decided it was time to tackle this again. I needed to know that I could deploy a Scala web application in OSGi. These are two core components of my vision for the future architecture of AOE. However, this time around I was going to try Lift.
Again, I went through all of the hoops and iterations of digging through my Ivy cache and the output of my osgi-ifier to find the jars that I needed. I packaged up hello world for Lift, deployed and… you guessed it,
NoClassDefFoundError. <Insert obscenities>
java.lang.NoClassDefFoundError: net/liftweb/http/LiftFilter (wrong name: net/liftweb/http/ScreenWizardRendered$$anonfun$renderAll$5$$anonfun$apply$42)
This time, it’s even uglier and makes Scala look that much more suspicious.
Well, I noticed that both of the classes that are failing (the one for scalatra and the one for Lift) are configured in the web.xml for their respective bundles. This made me wonder if the issue was related to conjuring up Scala classes via reflection. I wrote a wrapper for my
LiftFilter in Java. Still broken. Then I thought maybe it’s because wabs are loaded differently. I wrote a quick bundle that would instantiate my wrapper. Still busted.
Then I thought perhaps its an incompatibility with Scala and karaf. I grabbed a copy of Equinox and tried it out. This guy turned out to be a pain to launch because the console option is no longer straight-forward. After wading through this, I jumped through all of my hoops again to deploy my dependencies, deployed my bundle to instantiate the wrapper… Busted.
Somewhere along the way, I had found out that Lift did in fact have the OSGi-ready manifests back in 2.4. This made me believe that surely this thing COULD run in OSGi. I decided to grab 2.4 and try loading it. But then all of the versions of everything was different (most notably it was dependent upon Scala 2.9.1 instead of 2.9.2). I quickly got annoyed by this idea.
Since that started to suck, I thought I’d try out the 2.4 manifest with a little bit of editing to make it 2.5 would help. After a little wrangling with it, I deployed the Lift webkit and my hello world wab. Same error… but different:
Caused by: java.lang.NoClassDefFoundError: net/liftweb/common/Box (wrong name: net/liftweb/common/LazyLoggable)
This time the class is in the common jar! So I repeated my porting of the 2.4 manifests to the common jar as well as the other handful of Lift jars. I finally got around this dreaded Java error! Along with some hints from Guofeng Zhang in the Lift forums, I was finally able to get the hello world Lift app running in karaf.
This problem took up far more time than I wanted. I always feel worse about chasing down an issue when I learn it was my own doing. However, it’s a lot easier to correct if it’s my fault, as opposed being stuck hoping someone else fixes something.
Next up, whip up a Lift app that displays the deployed bundles.