Skip to content
This repository has been archived by the owner on Dec 9, 2018. It is now read-only.

JARs, Bundles, & Packages

bnd edited this page Feb 1, 2013 · 2 revisions

Once you've got started with bndtools you will have to start thinking how to layout your bundles and how use other bundles. This article gives some background about the choices you face.

Terminology

  • JAR - A Java Archive
  • Bundle - A JAR with specific OSGi metadata
  • bnd file - This is either the bnd.bnd file or another .bnd file.

bnd Concepts

A bnd file has a -buildpath (look at the source tab of the bnd file). The -buildpath can contain either bundles or plain jars. These jars are put on the class path for the compiler. So this can be any Java artifact, either a plain JAR or a bundle. This means that certain OSGi things do not work (e.g. Bundle-Classpath) so avoid those in your own outputs. Classic Java build tools work like zip and tar. They basically create a directory and gobble it up in a JAR (=zip) file without knowing what they actually gobble up, usually just the bin directory.

In contrast, bnd is more like a Java linker, it does not require you to create an image in a directory but it requires you to specify what you want in the output. This specification is done with package names. Any package on the -buildpath (which automatically includes your bin folder) can be copied to your bundle with Export-Package and Private-Package. Since bnd knows the scope (the -buildpath) you can use wildcards to specify these packages. Other content can be copied with Include-Resource. After the contents are established, bnd calculates the manifest on this content. This is also very similar to a linker that creates the symbol table.

It should be clear why bndtools support multiple outputs per project. Since the content of the output is independent of the project, you can easily make different bundles in one project, or make variations of a bundle in one project.

Designing Your Modules

So the BIG difference with bnd(tools) is that you design your bundle. Classic tools let you design your project but rarely give you flexibility in what then is selected for your output. This design aspect is crucial since the idea of OSGi is that you will deploy this in many unknown frameworks. Since you can specify dependencies in OSGi, there is a tendency to use this facility. Actually, most classic tools actively promote the use of dynamic dependencies with their 1-project == 1 binary model. The problem is that though sometimes necessary, they are a pain in the ass for deployment. If you look at modern OS's, there is a tendency to force the app developers to just supply all their dependencies except the ones provided by the platform. This prevents DLL hell. For an Apple App Store app you even have to include the VM nowadays. Even if you have 6 apps all having the same deps you're forced to all the deps 6x. The reason is that memory and bandwidth is cheap and dependency problems are really expensive since they require experts to solve them.

So what should you include in your bundle? In general, you want to include all non-API code in your bundle. A perfect bundle imports only API packages and has no exports. Sometimes you implement (provide) an API package. In that case it is highly recommended to also export that API package. There are many bad bundles that lack this API packages and they are hard to use. In general, you have then to include a bundle containing the API, for example the OSGi compendium API. There are then two choices that are equally bad. Or you package each API package as a separate bundle (lot of work, error prone) or you package them together (binding different APIs together). Since a provider of an API is closely bound to that API (unlike a consumer of that API) there is no trade off including it in the bundle. In general, Apache Felix bundles are really good in this, bundles from Eclipse PDE projects tend to rely on outside bundles for their API, making them much harder to deploy.

Example

So now you have your perfect bundle: well designed and proper metadata. For testing or running, bndtools uses the -runbundles property. As the name indicates, the list must consist of bundles, it is not a path like -buildpath with general jars. When you run the code bndtools launches a new framework and installs all of these bundles. Though you can install a non-bundle JAR it is not very useful. So here it is really useful to have actual bundles.

Looking at XOM you can see that the latest version is 1.2.5. There are a number of other JARs that seem to be a wrapped version of XOM. Especially interesting is the SpringSource XOM. This one is coming from he Enterprise Bundle Repository maintained (until now at least) by SpringSource. These are always bundles. However, looking at the 1.2.5 revision you see an OSGi icon at the 'Summary' line, indicating that it is actually provided with OSGi metadata.

If you go to the end you see the imports and exports as white (imports) and black (imports) boxes. Unfortunately, the exported packages are not versioned as you can see, they all have version 0.0.0. The SpringSource bundle for XOM has the latest version but versions the packages with 1.2.5, which is kind of arbitrary.

Another difference is that the original bundle only exports the following packages:

nu.xom 0.0.0
nu.xom.canonical 0.0.0
nu.xom.converters 0.0.0
nu.xom.xinclude 0.0.0
nu.xom.xslt 0.0.0

The SpringSource bundle is more promiscuous and exports everything. In that aspect, the original is better since it only seems to export its API (less is more!). There is an implicit promise in here that they will maintain their API but can change all other packages which are considered private packages:

nu.xom.jaxen
nu.xom.jaxen.expr
nu.xom.jaxen.expr.iter
nu.xom.jaxen.function
nu.xom.jaxen.function.ext
nu.xom.jaxen.function.xslt
nu.xom.jaxen.saxpath
nu.xom.jaxen.saxpath.base
nu.xom.jaxen.saxpath.helpers
nu.xom.jaxen.util
nu.xom.tests
org.w3c.dom (!)

You now have the following solutions

Copy the XOM bundle into your own bundle

You can copy either the SpringSource or the XOM bundle into your own bundle:

Private-Package: nu.xom.*

Use the SpringSource bundle

You get properly versioned packages but you are also exposed to non-API packages.

Use the XOM bundle

Package versions are not present, which might be problematic in the future.