Basics about OSGi Classloading

In our opinion one of the biggest improvements to OSGi comes by classloading. Just as basic as it is the more important it becomes.

This topic will present some basics of OSGi classloading – what you can do, what it implies and what’s the meaning of.

Let us start off from the ground.

The basic of java:

Every Class object contains a reference to the ClassLoader that defined it. (Javadoc ClassLoader in Java)

Load a class included in the same bundle

As simple as it is :) Write an Activator and in start() get the classloader of this class

Code:

ClassLoader myClassClassLoader = Activator.class.getClassLoader();
System.out.println("ClassLoader of BasicOneActivator is " + myClassClassLoader);

Result:

ClassLoader of BasicOneActivator is
       org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@65d0e0

The result is a DefaultClassLoader. Every Bundle has its own Classloader, a DefaultClassLoader. To get the allocated Bundle of a DefaultClassLoader we can call the getDelegate() Method.

Code:

System.out.println("Delegate to: " + ((DefaultClassLoader) myClassClassLoader).getDelegate());

Result:

Delegate to: org.codescale.osgi.classloading.basic.one_1.0.0.qualifier

Load a class exported from another bundle

To get a better opinion of classloading in osgi we’re going to load a class from another bundle with the same classloader as before.

Code:

Class<?> classA = myClassClassLoader.loadClass("org.codescale.osgi.classloading.basic.two.ClassA");
ClassLoader classLoaderA = classA.getClassLoader();
((DefaultClassLoader) oneActivator.getClassLoader()).getDelegate());

Result:

ClassLoader to load "org.codescale.osgi.classloading.basic.two.ClassA" is
       org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@d6d61d
Delegate to: org.codescale.osgi.classloading.basic.two_1.0.0.qualifier

The outcome of this is:

1. Every bundle (and every class in there) obtains his own Classloader

2. The Classloader of a bundle will be created if one class of this bundle is required by another bundle

Stacktrace to create a defaultclassloader

Image 1: Stacktrace

This binds any class of any bundle to one specific DefaultClassLoader.

Now we know that every Bundle has a DefaultClassLoader and we know that a DefaultClassLoader has a Bundle to delegate to. But what does this delegation mean?

If we take a look at the implementation of the class ‘DefaultClassLoader’ we will see that the DefaultClassLoader is only going to delegate nearly everything!

If a class needs to be loaded – he calls the ‘ClassLoaderDelegate’ (which is a ‘BundleLoader‘). If he has to find a local class – he calls the ‘ClasspathManager‘.

First we will address our attention to the ‘BundleLoader’.

The BundleLoader and his OSGi delegation model

In the Stacktrace in Image 1 we have made our first acquaintance to a ‘BundleLoader’. There he is blamed to call the creation of a DefaultClassLoader.

Also we will find the OSGi delegation model (implemented in the methods findClass(…) and findClassInternal(…)). It declares the following order to load classes:

  1. if startsWith “java.” delegate to parent and terminate search
  2. if part of the bootdelegation list then delegate to parent
  3. searchHooks and call preFindClass()
  4. search the imported packages
  5. search the required bundles
  6. search the local bundle
  7. attempt to find a dynamic import source; only do this if a required source was not found
  8. searchHooks and call postFindClass()
  9. do buddy policy loading
  10. or last resort; do class context trick to work around VM bugs

Note: The vmarg -Dosgi.classloader.singleThreadLoads=true allows only one thread to find a class by the delegation model (except step 1)

After delegating to the required part every classloading in the delegation model returns to the method findLocalClass(String name) in the DefaultClassLoader. There the call is delegated to the ClasspathManager.

The ClasspathManager and his locking mechanism

The ClasspathManager calls a BundlyEntry to read the bytes of a *.class file. And he calls (via DefaultClassLoader) the JVM to define the class. These steps need to be thread safe. And in case of that one of two locking mechanisms may be applied.

  1. Default: Only one thread can lock a DefaultClassLoader to define the class
  2. One thread locks the whole VM during defining a class (identified by the FQN) (enabled by vmarg -Dosgi.classloader.lock=classname)

This locking may become a problem (e.g. Deadlocks with Buddy-Classloading – Bug 121737 ) so stay observant.
be happy until cancelled,
Your Codescale’s

Advertisement
    • Nitu
    • April 26th, 2011

    The class loading mechanism has been described nicely. I have a query related to the plug-in class loading.

    Below is the description and the structure of my project and plug-ins code base.

    Scenario:
    ———
    1. A java project named ‘SampleProject’ having package ‘com.sample.action’.
    2. A plug-in project named ‘SamplePluginA’ having reference of above java project’s jar file which is set as Bundle-ClassPath also.
    3. A plug-in project named ‘SamplePluginB’ having reference of the exported package ‘sample.action’ from ‘SamplePluginA’ for ‘SampleProject’.

    Now, at runtime execution of the plug-in ‘SamplePluginB’, the class ‘sample.action.A’ of ‘SampleProject’ is invoked which tries to load the class ‘B’ located under the ‘SamplePluginB’. While loading this class, it throws the ClassCastException because the class loaders for both the classes differs. Whereas, if ‘sample.action.A’ tries to load a class located under the ‘SampleProject’ then it succeeds.

    I would like to know the way of loading classes of ‘SamplePluginB’ from a class located in ‘SampleProject’.

    The quick response will be appreciated.

    Thanks & Regards,
    Nitu

    • Hi Nitu,

      Do I’ve understood you right that your Plug-Ins are looking like that:
      - SamplePluginA.jar
      – SampleProject.jar
      — sample.action.A.class
      – META-INF/MANIFEST.MF

      - SamplePluginB.jar
      – META-INF/MANIFEST.MF

      and SamplePluginB —requires—> SamplePluginA ?

      How does the ‘sample.action.A’ can load the Class ‘B’ without an dependency of ‘SamplePluginA’ to ‘SamplePluginB’ (anyway this would lead to a dependency cycle)? Maybe you can give me some pice of code which is involved…

      Greetings

        • Nitu
        • April 27th, 2011

        The configuration in the respective MANIFEST.MF is done as follows:

        1. MANIFEST.MF of SamplePluginA has the entry for SampleProject.jar:

        Bundle-ClassPath: lib/SampleProject.jar
        Export-Package: sample.action.A;x-friends:=”SamplePluginB”

        2. build.properties of SamplePluginA has the entry:
        bin.includes = lib/SampleProject.jar
        jars.extra.classpath = lib/SampleProject.jar

        3. MANIFEST.MF of SamplePluginB has the entry:
        Require-Bundle: com.sample.samplepluginA;bundle-version=”1.0.0″

        The Class B is the implementation of an interface that belongs to SampleProject and a Decorator is implemented which tried to load implementor classes of this interface which are registered within the chain. This chain is build by the builder class located under the SamplePluginB.

        I have tried to load the Class B from the Class located under the SampleProject by the ClassLoader object obtained from the Activator class of the SamplePluginB. This approach works fine because the class will always be loaded from its class loader. But, i need a way where i dont need to pass a ClassLoader to my core class.

        I would also like to know whether am i missing any configuration in the plugin.xml or have i made mistake by creating SamplePluginB as a plugin and i would have created it as a fragment?

        Thanks & Regards,
        Nitu

      • The Class B is the implementation of an interface that belongs to SampleProject and a Decorator is implemented which tried to load implementor classes of this interface which are registered within the chain. This chain is build by the builder class located under the SamplePluginB.

        Have you thought about using the Whiteboard Pattern with OSGi Services? If you have implementations of an interface registered in the chain – then you can use the OSGi Service Registry for this as well (and for free :-) )

        I have tried to load the Class B from the Class located under the SampleProject by the ClassLoader object obtained from the Activator class of the SamplePluginB. This approach works fine because the class will always be loaded from its class loader. But, i need a way where i dont need to pass a ClassLoader to my core class.

        If you do not have the dependency from A to B but have to load a Class from there, you have to get anything at all (another Class, the Classloader, Bundle or BundleContext) to be able to load a Class out of this Bundle.

        I would also like to know whether am i missing any configuration in the plugin.xml or have i made mistake by creating SamplePluginB as a plugin and i would have created it as a fragment?

        OK some suggestions.
        1. If you register the Class B (which implements an interface from SampleProject) as a service you can use the service registry one more time to receive this Class (an ldap filter might help you (Constants.OBJECTCLASS=com.sample.B)).
        2. Use the Eclipse BuddyPolicy (but with caution! it’s only a possibility if there is really no other way out).
        3. Set you project ‘SamplePluginB’ up as a fragment. See my blog post to learn what a fragment will do.

        Thanks & Regards,
        Nitu

        You are welcome.

  1. Good blogpost, great looking blog, added it to my favs.

  2. Writing special classloader is good idea. The question is how to delegate classloading to the bundle-classloader? An example?

    • If a class will be loaded by your classloader you need to check first of all if you can load the class by the bundle-classloader. If not – do it by yourself… and throw a classnotfound if you also can not load the class… (you will get your bundle-classloader by simply ask an already loaded class ‘getClassLoader()‘)

  3. I have one question: I wrote my own eclipse plugin and I want to dynamicly load external Class from file. How to do it with DefaultClassLoader? I know I can use URLClassLoader (system class loader) but my class use plugin’s jar so it must be the same ClassLoader.

    • You need to bring the class onto the classpath of your plugin. The classpath is defined in the manifest (Bundle-ClassPath).
      Another possible idea could be to use an OSGi-Service or Extension-Point.

      Maybe you can tell me what your meaning of “external Class from file” is. And what’s the idea behind.

      Greetings

      • My plugin is something like dynamic wizard to generate files. I load wizard description at runtime (including classes description for this wizard), so at the begining I don’t know where this classes will be.

      • Maybe you can use JDT to read the required information from the class. If that is not possible you can write a special classloder to define the required binary-class from filestream and delegate classloading to the bundle-classloader.

  1. April 16th, 2011

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.