4.7. Library Bundles

It is often the case that certain standard class libraries, or utility or helper classes need to be shared by many bundles. Library bundles fill this role.

In a conventional Java runtime environment, you usually add additional class libraries to the CLASSPATH before running an application. However, by packaging them into library bundles, you can gain additional manageability and flexibility: You can choose to install them only when needed and you may be able to update the bundles with a newer version without shutting down the framework.

Generally, library bundles do not register any services or have activators. They can be constructed with these two steps:

1.
Define the library classes and interfaces in their appropriate packages. Generally they should be public classes and interfaces.

2.
Declare the packages with the Export-Package header in the manifest.

Imagine that Acme has a data structure package that needs to be packaged as a library bundle. The following is a skeleton definition for a linked list:

package com.acme.util;

public class LinkedList {

   public LinkedList() {
      // construct an empty linked list
   }

   public void append(Object e) {
      // append an object to the linked list
   }

   public java.util.Enumeration elements() {
      // return an enumeration of all elements in the list
   }

   // Other operations on the LinkedList.
   class Node {   // an element in the list
      Object data;
      Node next;
   }
}

We export the package by declaring it in the manifest:

Export-Package: com.acme.util

This tells the framework that the classes from the com.acme.util package are to be made accessible to any bundle that chooses to import this package. Use the jar command to pack up the bundle, whose contents look like

META-INF/
META-INF/MANIFEST.MF
com/acme/util/LinkedList.class
com/acme/util/LinkedList$Node.class

You can install and activate this bundle just like any other bundle. Using the Java Embedded Server software, library bundles must be activated before any other bundles can use the exported classes.

To use these data structures from another bundle, declare the manifest in the other bundle like this:

Import-Package: com.acme.util

We can then write code similar to the following, directly referencing the LinkedList class:

import com.acme.util.*;
...
LinkedList list = new LinkedList();
list.append(new String("Some text"));
list.append(new Integer(100));

Put the library bundle's JAR file on the CLASSPATH only when you compile the previous code. See “Compiling Client Bundles” on page 65.

A bundle can package other JAR files inside its own bundle JAR file. This mechanism is very convenient when dealing with units of classes that are functionally self-contained. Imagine that you are developing a bundle that depends on some class packages from a third party. It is much cleaner and less error prone to include the JAR file from external sources inside your own bundle than to extract and manipulate classes written by others. The latter may not even be an option if the JAR file has been digitally signed to ensure its authenticity and integrity, or disassembling is forbidden by the license terms.

Suppose a demonstration version of a thesaurus service is packaged as a nested JAR file in the dictionary bundle. We would have the following layout of the dictionary bundle:

META-INF/
META-INF/MANIFEST.MF
com/acme/service/DictionaryService.class
com/acme/extra/thesaurus.jar
com/acme/impl/Activator.class
com/acme/impl/Webster.class
com/acme/impl/webster.properties

The new kid on the block is the nested JAR, thesaurus.jar. Suppose its contents are as follows:

META-INF/
META-INF/MANIFEST.MF
com/acme/demo/service/ThesaurusService.class
com/acme/demo/impl/ThesaurusImpl.class

In situations like this, the containing bundle's manifest may declare a new manifest header, Bundle-ClassPath. This header determines the CLASSPATH for the bundle. That is, when Bundle-ClassPath is present, only the packages from the JARs listed in the header are accessible to the bundle itself or to other bundles (if an Export-Package header is also declared). The search order for loading a class from the bundle is also dictated by the order in which the JARs are enumerated in this header. Let's see how this header works for the following three cases:

  1. No Bundle-ClassPath is specified in the containing bundle's manifest. In this case, only packages in the containing bundle are accessible. Packages in nested JARs are completely ignored, as if thesaurus.jar didn't exist in the dictionary bundle at all.

  2. The Bundle-ClassPath header is defined in the containing bundle's manifest. Only packages in the JARs that are listed are accessible. Packages in nested JARs not listed in Bundle-ClassPath are ignored. Nested JARs are identified by their paths internal to the bundle. A special path, a dot (.), is used to identify the containing bundle itself.

    For example, suppose the dictionary bundle has the following declaration in its manifest:

    Bundle-Classpath: .,com/acme/extra/thesaurus.jar
    Export-Package: com.acme.service, com.acme.demo.service
    

    If so, then all packages in the dictionary bundle and thesaurus.jar are accessible to the bundle itself. They are

    com.acme.service
    com.acme.impl
    com.acme.demo.service
    com.acme.demo.impl
    

    During class loading, the dictionary bundle is searched before the nested thesaurus.jar, following the declarative order in the header.

    The Export-Package declaration in the dictionary bundle then only allows the com.acme.service and com.acme.demo.service packages to be exported and accessible to other bundles.

    Beware that the paths to the nested JARs are relative inside the containing bundle. Had thesaurus.jar been packaged at the top level in the dictionary bundle instead of at com/acme/extra, Bundle-ClassPath would have been defined as

    Bundle-ClassPath: .;thesaurus.jar
    
  3. Bundle-ClassPath does not include the dot (.).

    Packages in the containing bundle are skipped. For example, if dictionary bundle's manifest is defined as

    Bundle-ClassPath: com/acme/extra/thesaurus.jar
    

    then only the com.acme.demo.service and com.acme.demo.impl packages of nested thesaurus.jar are accessible.

    The Bundle-ClassPath header controls not only the classes but also the resources in the JARs. For example, in the last case, the webster.properties resource is inaccessible because it resides in the containing bundle, which is bypassed entirely.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.71.28