Archive

Archive for the ‘OSGi’ Category

Split Packages – An OSGi nightmare

September 2, 2010 2 comments

A “split package” is a pretty old Java term where you have packages in different libraries with the same name providing related (or sometimes unrelated functionality).  The classes in one package can access classes in the other package (with the same name) across library boundaries without any problem at both compile and runtime. This is true even for package-private classes. This works fine in the Java world as you deal with only a single hierarchical class loader. If you bring this concept to the OSGi (or Eclipse) world, you are in for trouble, where each bundle has its own class loader. This is what happened to me while I was doing some heavy refactoring recently.

I had the task of making a “monolithic” Eclipse system modular. Refactoring in JDT did a great job and in the end I had a modular system with no compile time errors. The pain started when I ran the application and started getting exceptions, I have never seen until now working with Eclipse framework.

Here’s what I did in short. I split a plug-in into two plugins, “Plugin A” and “Plugin B”, where “Plugin A” contained the main functionality and “Plugin B” was providing some library functions. So naturally “Plugin A” depended on “Plugin B” (or in OSGi terms, “Plugin A” had a “Require-Bundle: Plugin B” declared). Though not intentional, both plugins ended up having a package with the same name “SplitPackage”. A “Class A” in “SplitPackage” in “Plugin A” had a method call on “Class B” in “SplitPackage” in “Plugin B”.

PDE did not complain nor did I get any compile time errors. Now when I ran it, I got a “java.lang.IllegalAccessError:  tried to access Class B from Class A”. I kept wondering why I would get this linkage error which I should normally get at compile time from PDE. After spending half a day on it, I found the cause. “Class B” was declared as package-private . The moment I changed this into a public class, all was well again (although this wasn’t my final solution).

The root cause here was that OSGi loaded “Plugin A” and “Plugin B” using different class loaders and the packages “SplitPackage” in both bundles  are not the same and they live in two different worlds with a clear boundary between them. “Class A” in “Plugin A” cannot see package-private “Class B” after the bundles are resolved.  This resulted in the java.lang.IllegalAccessError exception at runtime. The exception doesn’t pop up at compile time as a Java compiler doesn’t know these boundaries and sees them as split packages. May seem strange but true!

Moral of the story is that never have split packages in the Eclipse environment. For OSGi, a package is the atomic unit and it should be as cohesive as possible. If you have functionality split into two packages with the same name, then they are not cohesive and ideally the packages should have different names or the classes should live within one package. If you really need split packages, make one of them an Eclipse fragment plugin. A fragment plugin always lives within a host plugin and both of them are loaded by the same class loader.

Tags: , , ,

OSGi debugging

November 28, 2008 Leave a comment

OSGi debugging can turn out to be a nightmare at times, especially when using OSGi declarative services. The steps below might provide some solace.

1. Using diag OSGi command

The OSGi console is automatically enabled if you launch your bundle from eclipse launch configuration as a “OSGi Framework”. Else you could add the argument -console to your launch configuration. This will enable the OSGi console upon run.

There are lot of OSGi commands that can be used from the console. You could get the list by simply typing help at the console.

To diagnose a particular bundle, type ss at the console to see its status. This would give you a list like, for example:

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 ACTIVE org.eclipse.osgi.services_3.1.200.v20071203
2 ACTIVE org.eclipse.equinox.ds_1.0.0.v20080427-0830
3 ACTIVE org.my.bundle._1.0.0
4 ACTIVE org.his.bundle_1.0.0
5 ACTIVE org.her.bundle_1.0.0
6 ACTIVE org.eclipse.equinox.util_1.0.0.v20080414

Use the command diag to diagnose a particular bundle.

For instance,

osgi> diag 3

initial@reference:file:plugins/org.my.bundle._1.0.0.jar/ [1]
Direct constraints which are unresolved:
Missing imported package org.someones.bundle_0.0.0.

3 is the id of the bundle org.my.bundle._1.0.0 above

2. Using -Dequinox.ds.print=true

Using VM argument -Dequinox.ds.print=true in your Launch configuration will echo all error messages to your console.

3. Using OSGi logging service

Start the OSGI bundle org.eclipse.equinox.log. With this bundle enabled, you could use the command log in your OSGi console.

For example,

osgi> log

>Info [2] Log created; Log Size=100; Log Threshold=4 initial@reference:file:plugins/org.eclipse.equinox.log_1.1.0.v20080414.jar/
>Info [2] ServiceEvent REGISTERED {service.id=23}
>Info [2] ServiceEvent REGISTERED {service.id=24}
>Info [2] ServiceEvent REGISTERED {service.id=25}