Native libraries in OSGi bundles

To support loading native code in OSGi bundles, the framework defines a specific header, Bundle-NativeCode, which defines the libraries that are available to the bundle via the System.loadLibrary call.

The Bundle-NativeCode header defines one or more native libraries and a clause which states what operating systems and processor architectures are valid for each library. Calls to System.loadLibrary will then look for libraries mentioned in this list and use only those found for the appropriate architecture. In effect, the Bundle-NativeCode header replaces the java.library.path property.

In the prior example, the maths library was used for performing calculations. In an OSGi bundle, this could be packaged with the bundle itself and referred to via a manifest header:

Bundle-NativeCode: native/maths.dll

When calling System.loadLibrary("maths") on Windows, the native/maths.dll library will be automatically extracted to a suitable location on the filesystem and passed to the operating system for loading.

Note

Note that the directory of the library in the bundle is neither relevant nor consulted in the loading of the library itself.

If a bundle is being designed to support more than one operating system, then the library needs to be qualified accordingly. To do this, clauses can be appended to each native library to determine which osname or operating system they can run on:

Bundle-NativeCode:
 native/maths.dll;osname=win32,
 native/libmaths.dylib;osname=macosx,
 native/libmaths.so;osname=linux

Now when run on a Windows platform, System.loadLibrary("maths") will load the native/maths.dll library; for Linux platforms, native/libmaths.so will be loaded instead; and for Mac OS X, native/libmaths.dylib will be used.

Note

The OSGi R6 specification translates requirements in the Bundle-NativeCode header to a set of generic requirements on the osgi.native namespace. An osname=win32 clause is automatically translated to a Require-Capability: osgi.native.osname~=win32 clause. This allows resolvers to choose the right dependency automatically. Eclipse Luna has an OSGi R6 compatible version of Equinox.

Although each operating system has its own naming convention (and thus the libraries can all be in the same directory in this instance), this approach doesn't work when providing multiple libraries for the same operating system. Although Mac OS X can create multi-architecture bundles, other operating systems are restricted to a single-processor architecture per library.

If the bundle needs to support both 32-bit and 64-bit operating systems, two versions of the library are required and the processor attribute disambiguates between them:

Bundle-NativeCode:
 native/x86/maths.dll;osname=win32;processor=x86,
 native/x86_64/maths.dll;osname=win32;processor=x86_64,
 native/libmaths.dylib;osname=macosx,
 native/x86/libmaths.so;osname=linux;processor=x86,
 native/x86_64/libmaths.so;osname=linux;processor=x86_64

The correct version of the maths library is loaded depending upon whether it is a 32-bit (x86) or 64-bit (x86_64) processor.

Note

This is the reason why directories are neither consulted nor necessary in the lookup of the native libraries; this permits the directories themselves to be used to partition the native libraries into different directories without affecting the logical runtime.

Optional resolution of native code

A side effect of the Bundle-NativeCode header is that if it is present, then it must have an associated entry that matches the operating system. If it is not, then the bundle will fail to resolve.

As a result, specifying the following will mean that the bundle cannot resolve on platforms other than Mac OS X:

Bundle-NativeCode: native/libmaths.dylib;osname=macosx

This is desirable in cases where there is a dependency on a framework specific to an operating system (such as a dependency on Cocoa.framework), but in other cases, a native library can be useful to accelerate certain actions but will work fine without the native library.

To declare that the native library is optional, place an asterisk (*) as another option in the Bundle-NativeCode header:

Bundle-NativeCode: native/libmaths.dylib;osname=macosx,*

This special syntax indicates that the bundle should still resolve normally even if the operating system isn't Mac OS X, but with the expectation that System.loadLibrary will only be called when running on a Mac OS X platform; or alternatively, that the code can handle an UnsatisifedLinkError when calling the method.

Multiple libraries for the same platform

When providing multiple libraries on a single platform, they all need to be referenced on the same clause. The OSGi resolution iterates through the clauses in order, and stops at the first one matching the current environment. As a result, this will never load the maths library:

Bundle-NativeCode: 
 native/libother.dylib;osname=macosx,
 native/libmaths.dylib;osname=macosx

Even though this looks like it should work, calls to System.loadLibrary("other") will work as expected, while calls to System.loadLibrary("maths") will fail.

To define multiple libraries, concatenate them into the same clause:

Bundle-NativeCode:
 native/libother.dylib;native/libmaths.dylib;osname=macosx

Now, the resolution of other and maths will work on the macosx platform.

Multiple libraries with the same name

If there are multiple libraries with the same name in the same clause, then only the first one is loaded. For example, if a separate debug version of the maths library was used and placed in a separate directory, then there would be no way to load it:

Bundle-NativeCode:
 native/libmaths.dylib;debug/libmaths.dylib;osname=macosx

Since folders are ignored and cannot be supplied as part of the System.loadLibrary call, any reference to maths will always result in the first native/libmaths.dylib library.

The right way to resolve this is to either rename the library, for example, libmaths-debug.dylib, or use an alternative mechanism, such as the filter or fragment solutions discussed later in this chapter.

Additional filters and constraints

It is possible to attach additional filters and constraints on loading the native libraries in an OSGi bundle. There are a number of standard attributes that can be specified along with a generic filter:

  • osname: This is the name of the operating system (win32, macosx, or linux)
  • osversion: This is the version number of the operating system (8.1, 10.9, or 3.2)
  • processor: This is the processor type (x86, x86_64)
  • language: This is the ISO language code, in case the DLL has textual content
  • selection-filter: This is an OSGi LDAP filter, which can be applied for other system properties

For a full list of supported values, see the OSGi specification or on the OSGi website at http://www.osgi.org/Specifications/Reference.

The selection-filter can be used to provide a specific debug variant of an available library by specifying a system property for the Java VM. For example, if two versions of a library were required, one with debugging symbols, then the filter can be set as follows:

Bundle-NativeCode:
 native/libmaths.dylib;selection-filter=(!(debug=true))
 debug/libmaths.dylib;selection-filter=(debug=true)

Running the VM with a -Ddebug=true flag would result in the debug libraries being loaded by System.loadLibrary, whereas with any other value (or unset), the normal one would be used.

selection-filter can also be used to test for other conditions, for example:

Bundle-NativeCode:
 native/libmaths.dylib;selection-filter=(file.encoding=UTF-8)

This can be used to selectively load different libraries based on the windowing system installed:

Bundle-NativeCode:
 native/libgtk.so;selection-filter=(osgi.ws=gtk),
 native/libcocoa.dylib;selection-filter=(osgi.ws=cocoa),
 native/mfc.dll;selection-filter=(osgi.ws=win32)
..................Content has been hidden....................

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