• No results found

3. Bundle Dependencies

3.5. Interlude: How Bnd Works

then the runtime resolution of the two bundles will be as in Figure 3.1. The thick, dashed line in this figure represents the “wiring” together by the frame- work of the import with its corresponding export.

org.osgi.book.reader.api mailbox_api

org.osgi.book.reader.api fixed_mailbox

Figure 3.1.: The runtime resolution of matching import and export. A package import is one of the constraints that the framework must satisfy in order to resolve a bundle, i.e. move it from the INSTALLED state to the RESOLVED state. In this case the constraint on the fixed_mailboxbundle was satisfied by matching it with the corresponding export on themailbox_api bunde. In general the framework must match all of the imported packages against packages exported from RESOLVED bundles before it can satisfy the import constraints of a bundle. Note that the framework can move two or more bundles into RESOLVED state simultaneously, making it possible to resolve bundles that have circular dependencies.

3.5. Interlude: How Bnd Works

In the previous example, the bnd descriptor for the mailbox implementation bundle contained only a single line — thePrivate-Packageinstruction — yet the generated manifest contained a correct Import-Packagestatement. How did that happen?

In fact this is one of the main features of bnd: it is able to calculate the imports of a bundle through careful inspection of the class files that we tell it to include in the bundle. Since we are making so much use of bnd, we need to take a closer look at how it generates bundles and manifests.

Bnd has several modes in which it can be used, but we will mostly be using it in its “build” mode for constructing bundles. In build mode, bnd follows a two-stage process: first it works out what the contents of the bundle should be, i.e. which packages and classes need to be included; and second, it calculates the dependencies of the included classes and generates an Import-Package statement.

TheExport-Packageand Private-Packageinstructions determine the con- tents of the bundle. Any package named in either of these instructions, either explicitly or through a wildcard pattern, will be included in the bundle JAR. Listing3.8shows an example.

Listing 3.8Bnd Sample: Controlling Bundle Contents # b n d s a m p l e

E x p o r t−P a c k a g e: o r g.o s g i.b o o k.r e a d e r∗ P r i v a t e−P a c k a g e: o r g.o s g i.t u t o r i a l

This will result in all packages beginning withorg.osgi.book.readerbeing included in the bundle and exported; and the package org.osgi.tutorial included but not exported.

Once bnd knows what should be in the JAR, it can calculate the imports. As mentioned, it inspects the bytecode of each class file found in the included packages, which yields a list of classes and packages. By default, every package found is added to theImport-Packageheader, but we can assert more control over this process by including anImport-Packageinstructionin our bnd file. For example, Listing3.9shows how to apply a specific version range to some imports and mark others as optional.

Listing 3.9Bnd Sample: Controlling Imports # b n d s a m p l e

I m p o r t−P a c k a g e: o r g.a p a c h e.l o g 4 j∗ ;v e r s i o n= " [ 1 . 2 . 0 , 1 . 3 . 0 ) " , \ j a v a x.s w i n g∗ ;r e s o l u t i o n:=o p t i o n a l, \

The entries in this list arepatterns. Each package dependency found through bytecode analysis is tested against the patterns here in order, and if a match is found then the additional attributes are applied to the import. In this sample, if a dependency on a Log4J package is found then it will be marked with the version attribute specified; if a dependency on any Swing package is found then it will be marked as optional. The final “*” is a catch-all; any packages matching neither of the first two patterns will pass straight into the manifest without any additional attributes.

The use of wildcards like this can be initially alarming if one does not under- stand the way that bnd checks the actual discovered dependencies against the patterns in the Import-Package statement. For example the pattern javax.swing* may appear to be importing the whole of Swing; i.e. all 17 packages of it. If that were the case then the simple *on its own would be even more alarming! The confusion arises because bnd’s instructions, such as