Wednesday, August 5, 2015

Avoiding Class Loader Muck with the Weaver. Wonkish

We're quite busy to finalize OSGi enRoute (the 1.0 date is September 1) and one of the significant parts of OSGi enRoute is bnd(tools). A shameful secret of bnd is that it knows a lot about OSGi but its plugin system is actually not based on OSGi. Fifteen years ago when bnd started OSGi was deemed too heavy to run as a command line tool. Ah, the crimes we commit in the name of optimizations.

The bnd plugin system regularly makes me want to pull out my (by now grey) hair;  it confirms my believe that class loaders originated from Dante's ninth circle. Things that work correct without effort in an OSGi environment are yucky in a raw class loader environment. They work, but the solutions are surprisingly fragile without writing another OSGi.

That said, bndlib is used in several OSGi frameworks; it is a real bundle. As can be expected, OSGi is pretty obnoxious when it comes to class loader muck. (Google for OSGi and class loader problems.) The worst part is of course that OSGi is actually right in being obnoxious.

Over time bnd got expanded with several repository types, a resolver, and other plugins. In bndtools (the Eclipse version) we actually install these plugins as bundles but due to reason I will not explain here, they were not always used. So we needed to clean up this mess.

Initially I created a mucky class loader solution that would do the evil thing of searching a class name in all bundles, a.k.a. buddy loading. Evil because you are in lala land, the whole OSGi engine to make sure proper classes are aligned is utterly ignored. You also create wiring dependencies that are not visible to the OSGi framework and this can cause other nastiness. Yuck.

After making my hands dirty and getting it to work I discussed the solution with BJ Hargrave. He, however, came up with a very interesting solution: the Weaving Hook.

The Weaving Hook is normally used to do byte code weaving. I am not that crazy about weaving because it is hard to make it work in an open and shared environment like OSGi. However, in this case it was actually quite easy and useful. Let me elucidate you.

When you change the byte codes of the classes, you need to add imports for any new dependencies. However, nothing in the Weaving specification forces you to weave, you can also use it to just add imports any bundle you want.

So this is what we ended up doing. In bndtools (or any OSGi environment) we register a Weaving Hook service. The hook tracks bundles that can provide plugins (They opt-in with an attribute on an exported package) and then adds these packages to the bndlib bundle as new imports.

This solution worked the first time and provided us with all the OSGi goodies. For the OSGi Framework it looks like the bndlib bundle now imports the plugin bundles. No more class loader yuck!

Peter Kriens

No comments:

Post a Comment