Prev Next

What is bnd?


Background

OSGi requires additional metadata in the JAR’s manifest to verify the consistency of your “class path”. This metadata must be closely aligned with the class files in the bundle and the policies that a company has about versioning. Without appropriate tooling, maintaining this metadata is an error prone chore.

bnd is the Swiss army knife of OSGi, directly addressing the requirement of creating and working with OSGi bundles.

bnd automatically creates the required manifest from the class files: this by analyzing the class files for dependencies. As bnd is able to to understand the semantics of a bundle it is able to detect many errors, and allow bundles to be created with almost no special information.

Workflow

Traditionally, JAR files were made with the JDK jar tool, the jar ant task, or the Maven packager. These tools share the same concept. The developer creates a directory image of the jar by copying files to a directory; this directory is then jarred. This can be described as a ‘‘push’’ model.

bnd works differently, it uses the ‘‘pull’’ model. Instructions in the bnd file describe the contents of the desired JAR file without writing this structure to disk. The contents from the output can come from the class path or from anywhere in the file system.

For example,

to include the designated packages in the JAR:

Private-Package: com.example.*

to add a version to all imported packages from a specific library:

Import-Package: com.library.*; version = 1.21

bnd can create a JAR from packages the sources, directories or other JAR files. You never have to copy files around, the instructions that Bnd receives are sufficient to retrieve the files from their original location, preprocessing or filtering when required.

After the JAR is created, the bnd program will verify the result.

Export-Package

The Jar is constructed from 3 different arguments:

Export-Package
Private-Package
Include-Resource

Private-Package and Export-Package contain ‘‘instructions’’. Instructions are patterns + attributes and directives, looking like normal OSGi attributes and directives. For example:

Export-Package: com.acme.*;version=1.2

Each instruction is applied to each package on the classpath in the definition order. That is, if an earlier instruction matches, the later instruction never gets a chance to do its work. If an instruction matches its attributes and properties are applied to the packages. The difference between the Private-Package argument and the Export-Package arguments is that the export version selects the packages for export. If the packages overlap between the two, the export wins.

An instruction can also be negative when it starts with a ‘!’. In that case the package is excluded from the selection. For example:

Export-Package: !com.acme.impl, com.acme.*;version=1.2

Note that the instructions are applied in order. If the ! instruction was at the end in the previous example, it would not have done its work because the com.acme.* would already have matched.

Include-Resource

The Include-Resource argument can be used to copy resources from the file system in the JAR: e.g. licenses, images, etc. The instructions in the argument can be a directory, a file, or an inline JAR. The default JAR path is the the root for a directory or the filename for a file. The path can be overridden. Instructions that are enclosed in curly braces, like {license.txt}, are pre-processed, expanding any macros in the file.

Import-Package

Once the JAR is created, the bnd program analyzes the classes and creates an import list with all the packages that are not contained in the jar but which are referred to. This import list is matched against the Import-Package instructions. Normally, the Import-Package argument is *; all referred packages will be imported. However, sometimes it is necessary to ignore an import or provide attributes on the import statement, or specify an additional import.

For example, to make the import optional, or to discard the import:

Import-Package: !com.acme.*, *;resolution:=optional

The arguments to bnd are normal given as a set of properties. Properties that begin with an upper case are copied to the manifest (possibly after processing). Lower case properties are used for macro variables but are not set as headers in the manifest.

Tips

There are some common pitfalls that can be prevented by following the tips:

  • Keep it simple. bnd’s defaults are pretty good and not specifying is usually the best solution. KISS!
  • bnd will not create an output file if none of the resources is newer than an existing output file.
  • Think packages … yes it feels redundant to specify the packages that are in your source directory but your artifact will get a life of its own over time. Many IDEs and build tools restricted us to one artifact per project but bnd allows many artifacts, allowing the choice of granularity to you. As OSGi’s packages can be easily refactored you can design the contents of your artifacts depending on the deployment needs. Think packages!
  • Private is always better than export, only use export when you absolute need it.
  • Not versioning an exported package is at your own peril. Sorry, that is false, it is at the peril of your users.
  • Do not use the Bundle-ClassPath, if you need to include whole JARs, see the @ option at Include-Resource.
  • If you do not understand a header, remove it.
  • If you have a problem, make an example that is as small as possible and send it to Peter Kriens.

Further Information?

bnd is available in several forms: command line, ant task, maven plugin, and an Eclipse plugin.

The bnd site provides further in depth information.