load
method.
A ResourceLibLoader is initialized by providing it with an XML specification file that determines which resource names will be searched for library files. The DTD for this specification file is given below. The top level element is defined by
An<!ELEMENT libloaderspec (archdef | archfamily | osinfo)*>
archdef
element provides a mapping from an OS
architecture name to the canonical name (the standard name to
use as part of a library resource name.)
If archdef elements are not provided, the name provided by the OS is assumed to be the canonical name.<!ELEMENT archdef EMPTY> <!ATTLIST archdef name CDATA #REQUIRED cname CDATA #REQUIRED>
Architectures are sometimes grouped in families, where newer
versions of a microprocessor have instruction sets compatible
with older versions. The archfamily
element defines
such families, and consists a series of arch elements ordered from
the newest architecture to the oldest.
The<!ELEMENT archfamily (arch)*>
arch
element defines an architecture than can be part
of a family.
The<!ELEMENT arch EMPTY> <!ATTLIST arch cname CDATA #REQUIRED>
cname
attribute provides the canonical name of the
architecture. A particular architecture
can have at most one older architecture associated with it. That is,
if one archfamily element contains one arch element followed by
another, a different archfamily element cannot contain the same
arch element followed by a different arch element. An arch element
must also appear only once in any given arch family. *
The osinfo
element can be used to indicate the suffix
used for the file and resource names of native-method libraries.
Typical suffixes are ".so
" and ".dll
".
A set of version elements contained in an osinfo element can be
used to define a single version name for a number of versions.
This is particularly useful for Linux systems, where the version
changes whenever new kernel is provided. These elements are defined
as follows:
The<!ELEMENT osinfo (version)*> <!ATTLIST osinfo name CDATA #REQUIRED prefix CDATA #IMPLIED suffix CDATA #IMPLIED>
name
attribute is mandatory and specifies the
OS name for the element.
The suffix
attribute provides a suffix string, and
must contain a leading period ("."). Any number of nested version
elements can be provided.
Each version element contains a pattern (using the Java regular expression syntax) to match against the os.version system property. The replacement used is the one specified by the first version element whose pattern matches the version provided by<!ELEMENT version EMPTY> <!ATTLIST version pattern CDATA #REQUIRED replacement CDATA #REQUIRED>
System.getProperty("os.version")
.
The default specification file contains the following:
<?xml version="1.0" ?> <libloaderspec> <archfamily> <arch cname="i686"/> <arch cname="i386"/> </archfamily> <osinfo name="Linux" suffix=".so"> <version pattern="2\.4\..*" replacement="2.4"/> <version pattern="2\.5\..*" replacement=2.5"/> <version pattern="2\.6\..*" replacement=2.6"/> ... <version pattern="4\.0\..*" replacement=4.0"/> ... <version pattern="4\.14\..*" replacement=4.14"/> </osinfo> </libloaderspec>
The following code prints the order in which the software will search for a shared-library resource:
Will create list the following resource names on a Linux system running Linux version 3.2.0-126-generic on an Intel i3 processor (Java's os.arch system property reports amd64 instead of the correct x86_64):org.bzdev.lang.ResourceLibLoader rl = new org.bzdev.lang.ResourceLibLoader(); java.util.Iterator<String> it = rl.getResources("foo"); while (it.hasNext()) { System.out.println(it.next()); } }
libfoo-Linux-3.2.0-126-generic-amd64.so libfoo-Linux-3.2-amd64.so libfoo-Linux-amd64.so libfoo-amd64.so libfoo-Linux-3.2.0-126-generic-x86_64.so libfoo-Linux-3.2-x86_64.so libfoo-Linux-x86_64.so libfoo-x86_64.so libfoo-Linux-3.2.0-126-generic-i386.so libfoo-Linux-3.2-i386.so libfoo-Linux-i386.so libfoo-i386.so
The object files are stored as resources. For the example above, a
resource with one or more of the names listed above should be used
as the resource name. If the resource should start with a path,
the path must be prepended to the library name. These paths
contain names that are separated by a '/' (but may not start with a
'/'). For example, when "com/foo/foo" is used as an argument to
getResources(String)
or
load(String)
, the corresponding resource
names are com/foo/libfoo-x86_64.so, com/foo/libfoo-Linux-x86_64.so,
etc., depending on how specific the code is to a particular OS
version.
Because the os.arch system property is not a reliable indication of the CPU, one should make conservative assumptions about which binaries to include (e.g., provide a binary for x86_64 rather than one for an amd64 system, unless you know that the jar file will only be used on an AMD system.)
While there is a default specification file, it is intended for cases where version-specific libraries are used primarily for work-arounds for bugs in specific OS versions or libraries: when using the default specification file, one will nearly always provide a resource that does not contain an OS version in its name. For more complex cases, a custom specification file should be used.
-
Constructor Summary
ConstructorsConstructorDescriptionClass constructor.ResourceLibLoader
(String specResource) Class constructor configured via a resourceResourceLibLoader
(String specResource, boolean validating) Class constructor configured via a resource and option. -
Method Summary
-
Constructor Details
-
ResourceLibLoader
public ResourceLibLoader() throws FactoryConfigurationError, SAXException, IOException, ParserConfigurationExceptionClass constructor. Uses the default configuration file in resource org/bzdev/lang/rlibloader.xml- Throws:
FactoryConfigurationError
- if ther was an XML factory configuration errorSAXException
- if there was an SAX parser exceptionIOException
- if there was an IO exceptionParserConfigurationException
- if a parser configuration exception
-
ResourceLibLoader
public ResourceLibLoader(String specResource) throws FactoryConfigurationError, SAXException, IOException, ParserConfigurationException Class constructor configured via a resource- Parameters:
specResource
- the string naming a resource.- Throws:
FactoryConfigurationError
- if ther was an XML factory configuration errorSAXException
- if there was an SAX parser exceptionIOException
- if there was an IO exceptionParserConfigurationException
- if a parser configuration exception- See Also:
-
ResourceLibLoader
public ResourceLibLoader(String specResource, boolean validating) throws FactoryConfigurationError, SAXException, IOException, ParserConfigurationException Class constructor configured via a resource and option.- Parameters:
specResource
- the string naming a resource.validating
- true to use a validating parser; false otherwise- Throws:
FactoryConfigurationError
- if ther was an XML factory configuration errorSAXException
- if there was an SAX parser exceptionIOException
- if there was an IO exceptionParserConfigurationException
- if a parser configuration exception- See Also:
-
-
Method Details
-
getResources
Get the resource names that will be tried to find libraries. This method is used internally to generate candidate resource names. If the values produced by the iterator are strings so they may be printed. This is useful for debugging new spec files and to debug problems regarding library resource names. For systems in which shared library names always start with a prefix (e.g., "lib" on Unix and Linux systems), the prefix must be omitted.- Parameters:
resource
- a resource name for a library without the os, version, and architecture substrings (which are described in theload
method)- Returns:
- an iterator that will produce the resources that will be tried in an appropriate order.
-
load
Load a class from a resource. Several resource names will be tried and the first one that matches a resource will be used to load a library. The resource names are constructed from the argument and from substrings based on the Java system properties os.name, os.version, and os.arch. The first resource name tried is composed of the prefix (which may be an empty string), followed by the base resource name provided in the argument, followed by a '-' character, followed by the OS name and then another '-' character, followed by the version and then another '-' character, and finally followed by the OS architecture,in turn followed by the suffix. If a replacement for the version is provided in the configuration file, both the version and the replacement are tried, the actual version first.The next resource name is composed of the the prefix, followed by the base resource name provided in the argument, followed by a '-' character, followed by the OS name, again followed by a '-' character, and then followed by the OS architecture, which is in turn followed by the suffix. The last resource names starts with the prefix, followed by the base resource name, followed by a '-' character, and finally followed by the OS architecture, in turn followed by the suffix.
In all cases, the suffix is determined by the name of the operating system. If a suffix for the OS is not specified in the xml configuration file, the suffix defaults to ".dll" for any OS whose name starts with "Windows" and ".so" otherwise. Similarly, if a prefix is not defined, it defaults to the empty string for any OS whose name starts with Windows and to "lib" for all other OS names. Both defaults can be overridden in the configuration specification.
The sequence described above will be repeated for each architecture that is an ancestor of the architecture corresponding to the system property "os.arch": the
archfamily
directives describe a collection of trees with each directive describing a sequence of nodes in a tree leading towards the root of the tree.The OS name, OS version and OS architecture are by default the values of the os.name, os.version, and os.arch system properties. If a mapping is defined by the
archdef
directive, however, the architecture name will be replace in all cases with a canonical version of this name.For example, if the specification maps the version string to 2.4 for all 2.4 version, then with Linux 2.4.X running on an i386 system, the resource names tried for
foo
will belibfoo-Linux-2.4.20-6-i386.so
,libfoo-Linux-2.4-i386.so, libfoo-Linux-i386.so
andlibfoo-i386.so
, followed bylibfoo.so
itself. On a windows system, the ".so" suffix will be replaced with a ".dll" suffix. On a Linux system where the system propertyos.arch
isi686
, using the default specification file, the resource names that will be tried arelibfoo-Linux-2.4.20-6-i686.so
,libfoo-Linux-2.4-i686.so, libfoo-Linux-i686.so
,libfoo-Linux-2.4.20-6-i386.so
,libfoo-Linux-2.4-i386.so
,libfoo-Linux-i386.so
andlibfoo-i386.so
. Two architectures appear because the specification defines a family of architectures, so all are tried.The resource as specified should not end in a suffix (e.g., ".so" on Linux) and should not contain a prefix as part of the resource name (e.g., "lib"on Linux): those are provided by the
load(String)
method. If detailed information is not available, the default suffixes are ".dll" for Windows systems and ".so" for Linux/Unix systems.- Parameters:
resource
- a string naming the resource (the name for a shared library) excluding the OS, version, and architecture components, but excluding the suffix and prefix.- Throws:
UnsatisfiedLinkError
- the library could not be loaded.SecurityException
- the library could not be loaded.
-