Wednesday, April 22, 2009

The difference between a jar and a bundle

I spoke with someone yesterday about a jar file dependency problem. In the middle of the conversation it became clear that the other person did not know anything about OSGi bundles (also known as plug-ins.) I forget that most Java programmers don't dwell in OSGi. As a way of informing my colleague, here's a high-level enumeration of the features of OSGi bundles and plug-ins:
  • They are the same thing. Plug-ins are bundles, and bundles are plug-ins: they mean the same thing.

  • They are jars, and more than jars: OSGi bundles are jar files with yummy metadata inside. Much of this metadata is in the jar's manifest, found at META-INF/MANIFEST.MF. This metadata, when read by an OSGi runtime container, is what gives the bundle its power.

  • They limit visibility: With OSGi, just because a class is public doesn't mean you can get to it. All bundles include an export list of package names, and if a package isn't in the export list, it doesn't exist to the outside world. This allows developers to build an extensive internal class hierarchy and minimize the surface area of the bundle's API without abusing the notion of package-private visibility. A common pattern, for instance, is to put interfaces in one package and implementations in another, and only export the interface package.

  • They have versions: All OSGi bundles are given a version number, so it's possible for an application to simultaneously access different versions of the same bundle (e.g. junit 3.8.1 and junit 4.0.) Since each bundle has its own classloader, both bundles' classes can coexist in the same JVM.

  • They express their dependencies on other bundles: OSGi bundles declare which other bundles they depend upon. This allows them to ensure that any dependencies are met before the bundle is resolved. Only resolved bundles can be activated. Because bundles have versions, versioning can be included in the dependency specification, so one bundle can depend on version junit version 3.8.1 and another bundle can depend on junit version 4.0.

  • They have lifecycle events: Bundles can contain code that is run when the bundle is activated, and again when the bundle is deactivated. You can read more information in the documentation for the BundleActivator interface.

  • They collaborate with each other through an extension mechanism: Bundles may define a contract for extension, and in kind they can extend other bundles' extensions. This is how bundles configure each other. If bundles are black boxes, this would be the wires and junctures connecting them.

    Most of these configurations can expressed through code, but by using XML the configurations can be read and processed without instantiating the associated bundles or classes. Sometimes I find the use of a plugin.xml file to be more of a pain than just writing code, but it delays helps delay unnecessary performance penalties for as long as possible.

  • They are meant to be run in an OSGi runtime container: Sure, these are jar files, and you can put them on the classpath just like any other plain-ol' jar file. If you do that, though, you lose all the benefits of the bundle architecture like limited package visibility, verioning, et cetera. It's the OSGi runtime container that provides the power behind bundles. Well-known implementations include Eclipse's Equinox, Knopflerfish, Apache Felix and Concierge.

    Some bundles are often used as plain-ol' jars due to their structure and power: SWT and JFace (combined they are Eclipse's answer to Swing) and JDT (a powerful Java parsing library) are well-known examples.
OSGi also supports package versions (in addition to bundle versions, listed above) and declarative services, but I know almost nothing about those features.

If you want to get started with OSGi, try this introductory tutorial, read the OSGi specifications, or look at the soon-to-be released book Equinox and OSGi: The Power Behind Eclipse (currently available on Safari Rough Cuts.)

Parenthetically: I realize there is a battle between Sun camp and OSGi camp over the future of the Java module specification. This post isn't about that, but if you want some details, you can start by looking at JSR 294.

Thanks to Jeff McCaffer and Chris Lopez for their valuable feedback on the draft.

2 comments:

Peter Kriens said...

Nice post! Some small notes:

Extensions defined in XML are provided by an bundle from Eclipse, they're not built into the OSGi framework. The framework natively has services. These services are any Java object registered with properties at the framework, where other bundles can search for them and then bind.

The preferred model in OSGi is to import/export packages and not require other bundles. The advantage is a much smaller change you have to change your bundles when you refactor and a much higher chance bundles are compatible with each other. The spec has a section that details this more.

Peter Kriens

konberg said...

When I was warned that not mentioning import packages would get me in trouble, I didn't realize it would take so little time! :) Thanks for the clarification.