Monday, April 3, 2006

Misconceptions about OSGi Headers

This week there was an interesting discussion on a mailing list that showed a number of misconceptions about the difference between importing a package (Import-Package) or importing a Bundle (Require Bundle). This is a complicated and subtle area so the misconceptions are likely to be widespread. I'll try to clear up some of these misconceptions in this blog.

Require-Bundle ensures that the required bundles are initialized before you can use them.
False. Require-Bundle and Import-Package only relate to resolving. Resolving is the process where different bundles are wired to each other on package level. From the perspective of a bundle, this is an atomic process. The start/stop primitives are completely independent from this resolving process. The only difference between Require bundle and Import Package is granularity. Require bundle is internally transformed to the same wires as import package uses (except when the more esoteric split packages are desired).

Any bundle can contribute classes to imported packages False. The Framework must select a single exporter for a package that is imported. We call the case where a package can come from multiple sources a split package. This is a common case with the traditional Java class path and a potential source for errors because a package should contain highly cohesive classes; there are also security implications. To address this problem Java added sealed packages. On top of this, the OSGi Specifications added the constraint that a package must have a single source.

This said, there is an exception because in certain cases (Java localization for example), split packages are a necessity. Require Bundle can therefore be used as a façade to multiple bundles that are aggregated. From the outside it looks like the bundle exports a single package but it gets the content from its bundle classpath or other required bundles. Fragments can also be used to provide split packages. However, split packages should be exceptions because of the related security and confusion problems.

With require bundle you are ensured all packages come from the same source This is true, but the same result can be better achieved with Import-Package and the uses directive. When packages are not cohesive and are aware of each other’s implementation details then it is paramount that they actually import the same package. In those cases packages can not be substituted independently. Import-Package solves this problem with a package directive that lists the referred (used) packages. For example bundle A has package p that uses package q. The Framework ensures that A, and all its wired bundles, share the same class loader for package q.

Require-Bundle can actually worsen the problem because it can use packages that are internal. The requiree can easily get into trouble if it imports these private packages. For example, a bundle requiring Xerces could separately import javax.xml.parsers. If this package is also available privately to the Xerces bundle then a class cast exception will occur.

You must import all packages of an exporter False. A bundle should only import the packages that it actually uses. This list is easy to generate from the class files (next generation Eclipse PDE will track this) and it is usually shorter than most people think. Well designed libraries have a few access points. These access points must be exported to use the library, however, all the packages that can be referred from the exported package do not have to be exported or imported. Once you have an object from a library, any classes that are linked from this object are automatically loaded from the same class loader. Most Java standards limit the use of a library to a single package that is shared between all implementations. For example, if you use the Apache Derby database you should not have to import any packages from that library, importing java.sql from the Java runtime should be sufficient.

Bundles are versioned, packages not False. Both bundles and packages are versioned. It is true that most programmers tend to ignore versions all together but good developers version both their bundles and packages.

A Required Bundle is a closed collection of code False. A bundle can be extended by fragments.

Peter Kriens

No comments:

Post a Comment