Thursday, July 14, 2011

Starting and immediately using OSGi bundle: possible?

Lately I had this little thing to do: an OSGi bundle (SuperTool) comes with some other OSGi bundle (GreatSdk) included.
SuperTool depends on logic in GreatSdk so the first thing it needs to do during activation is to install GreatSdk and immediately after that start loading classes from GreatSdk.

At first thought it seems logical to make SuperTool-GreatSdk dependency optional, to let SuperTool install and start safely without GreatSdk. Once installed, during startup SuperTool should install GreatSdk and start using it, for example:


BundleActivator.start(BundleContext context) {
greatSdk = context.installBundle("file:///path/to/great.sdk_1.0.0.jar");
greatSdk.start();

GreatSdkStarter gss = new GreatSdkStarter(); // separate class in SuperTool that references some classes from GreatSdk
gss.start(); // creates some GreatSdk classes
}


Unfortunately this fails in gss.start() with ClassNotFoundException:


java.lang.ClassNotFoundException: greatSdk.Sdk
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:513)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:429)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at supertool.GreatSdkStarter.start(GreatSdkStarter.java:8)
at supertool.Activator.start(Activator.java:63)


What does work is reflectively creating GreatSdk class instance via obtained Bundle:


// again in superTool activator.start()
Class clazz = b.loadClass("greatSdk.Sdk");
Object ob = clazz.newInstance();


So problem seems to be in the SuperTool information about the world. It looks like SuperTool is not yet aware that greatSdk was installed in the meantime.

Another thing that works is refreshing SuperTool via OSGi console:


osgi> start superTool
// loads greatSdk, but fails with ClassNotFoundException for classes referenced in GreatSdk
java.lang.ClassNotFoundException: greatSdk.Sdk....
osgi> ss
,,,
1 ACTIVE greatSdk
2. RESOLVED superTool

osgi> refresh superTool // magic
osgi > start superTool


After the refresh, starting superTool again makes it properly see greatSdk. Unfortunately doing refresh from within superTool activator.start() doesn't work so sweet. PackageAdmin.refreshBundles(superTool) terminates successfully, but CNFE is still thrown.

What's other way to activate and immediately use optional dependencies in an OSGi bundle?


(Except 'don't do it' :-) )

2 comments:

  1. After short chat with OSGi expert @nbartlett on Twitter, it turned out optional dependencies are not the best way to go. Optional dependency simply means that my superTool is fine without greatSdk. Since it's not, I need other way to make sure that greatSdk is installed first, before calling superTool. One way would be to use services, which greatly help to use APIs that come and go.

    ReplyDelete
  2. Thanks JACEK POSPYCHALA !! Well said. I am absolutely agree with you what said in comment. I also think that optional dependencies are not the best way for going. Thanks a lot !!

    comment system

    ReplyDelete