3 Module Layer

3.1 Introduction

The standard Java platform provides only limited support for packaging, deploying, and validating Java-based applications and components. Because of this, many Java-based projects, such as JBoss and NetBeans, have resorted to creating custom module-oriented layers with specialized class loaders for packaging, deploying, and validating applications and components. The OSGi Framework provides a generic and standardized solution for Java modularization.

3.2 Bundles

The Framework defines a unit of modularization, called a bundle. A bundle is comprised of Java classes and other resources, which together can provide functions to end users. Bundles can share Java packages among an exporter bundle and an importer bundle in a well-defined way. In the OSGi framework, bundles are the only entities for deploying Java-based applications.

A bundle is deployed as a Java ARchive (JAR) file. JAR files are used to store applications and their resources in a standard ZIP-based file format. This format is defined by [9] Zip File Format. Bundles normally share the Java Archive extension of .jar. However, there is a special MIME type reserved for OSGi bundles that can be used to distinguish bundles from normal JAR files. This MIME type is:

application/vnd.osgi.bundle

The type is defined in [15] OSGi IANA Mime Type.

A bundle is a JAR file that:

  • Contains the resources necessary to provide some functionality. These resources may be class files for the Java programming language, as well as other data such as HTML files, help files, icons, and so on. A bundle JAR file can also embed additional JAR files that are available as resources and classes. This is however not recursive.

  • Contains a manifest file describing the contents of the JAR file and providing information about the bundle. This file uses headers to specify information that the Framework needs to install correctly and activate a bundle. For example, it states dependencies on other resources, such as Java packages, that must be available to the bundle before it can run.

  • Can contain optional documentation in the OSGI-OPT directory of the JAR file or one of its sub-directories. Any information in this directory is optional. For example, the OSGI-OPT directory is useful to store the source code of a bundle. Management systems may remove this information to save storage space in the OSGi framework.

  • Can be a multi-release JAR. See Multi-release JAR.

Once a bundle is resolved, its functionality is provided to other bundles installed in the OSGi framework.

3.2.1 Bundle Manifest Headers

A bundle can carry descriptive information about itself in the manifest file that is contained in its JAR file under the name of META-INF/MANIFEST.MF.

The Framework defines OSGi manifest headers such as Export-Package and Bundle-ClassPath, which bundle developers use to supply descriptive information about a bundle. Manifest headers must strictly follow the rules for manifest headers as defined in [10] Manifest Format.

A Framework implementation must:

  • Process the main section of the manifest. Individual sections of the manifest are only used during bundle signature verification.

  • Ignore unrecognized manifest headers. The bundle developer can define additional manifest headers as needed.

  • Ignore unknown attributes and directives.

All specified manifest headers are listed in the following sections. All headers are optional, unless specifically indicated.

3.2.1.1 Bundle-ActivationPolicy: lazy

The Bundle-ActivationPolicy specifies how the framework should activate the bundle once started. See Activation Policies.

3.2.1.2 Bundle-Activator: com.acme.fw.Activator

The Bundle-Activator header specifies the name of the class used to start and stop the bundle. See Starting Bundles.

3.2.1.3 Bundle-Category: osgi, test, nursery

The Bundle-Category header holds a comma-separated list of category names.

3.2.1.4 Bundle-ClassPath: /jar/http.jar,.

The Bundle-ClassPath header defines a comma-separated list of JAR file path names or directories (inside the bundle) containing classes and resources. The full stop ('.' \u002E) specifies the root directory of the bundle's JAR. The full stop is also the default. See Bundle Class Path.

3.2.1.5 Bundle-ContactAddress: 2400 Oswego Road, Austin, TX 74563

The Bundle-ContactAddress header provides the contact address of the vendor.

3.2.1.6 Bundle-Copyright: OSGi (c) 2002

The Bundle-Copyright header contains the copyright specification for this bundle.

3.2.1.7 Bundle-Description: Network Firewall

The Bundle-Description header defines a short description of this bundle.

3.2.1.8 Bundle-Developers: pkriens; [email protected]; name="Peter Kriens"; organization="OSGi Alliance"

The Bundle-Developers header provides an optional machine readable form of information about the developers of the bundle. This header is purely informational and must not be processed by the OSGi Framework.

The syntax for this header is as follows:

Bundle-Developers ::= developer ( ',' developer ) *
developer         ::= identifier ( ';' developer-attr ) *
identifier        ::= argument
developer-attr    ::= email | name | organization | 
                        organization-url | roles | timezone
email             ::= 'email' '=' <email>
name              ::= 'name' '=' argument
organization      ::= 'organization' '=' argument
organization-url  ::= 'organizationUrl' '=' <url>
roles             ::= 'roles' '=' argument
timezone          ::= 'timezone' '=' argument

This header has the following attributes:

  • email - (optional) The email address of the developer.

  • name - (optional) The name of the developer.

  • organization - (optional) The name of the organization of the developer.

  • organization-url - (optional) The URL for the organization of the developer.

  • roles - (optional) The roles of the developer. This is a comma separated list of role names.

  • timezone - (optional) The time zone of where the developer resides. The time zone can be an id such as America/New_York or a numerical offset in hours from UTC.

See [26] Maven POM Reference, Developers for more information. Tools can use the information in this header for POM generation.

3.2.1.9 Bundle-DocURL: http://www.example.com/Firewall/doc

The Bundle-DocURL headers must contain a URL pointing to documentation about this bundle.

3.2.1.10 Bundle-Icon: /icons/acme-logo.png;size=64

The optional Bundle-Icon header provides a list of URLs to icons representing this bundle in different sizes. The following attribute is permitted:

  • size - (integer) Specifies the size of the icon in pixels horizontal. It is recommended to always include a 64x64 icon.

The URLs are interpreted as relative to the bundle. That is, if a URL with a scheme is provided, then this is taken as an absolute URL. Otherwise, the path points to an entry in the JAR file, taking any attached fragments into account. Implementations that want to use this header should at least support the Portable Network Graphics (PNG) format, see [18] Portable Network Graphics (PNG) Specification (Second Edition).

3.2.1.11 Bundle-License: Apache-2.0; link="http://opensource.org/licenses/apache2.0.php"

The Bundle-License header provides an optional machine readable form of license information. The purpose of this header is to automate some of the license processing required by many organizations like for example license acceptance before a bundle is used. The header is structured to provide the use of unique license naming to merge acceptance requests, as well as links to human readable information about the included licenses. This header is purely informational for management agents and must not be processed by the OSGi Framework.

The syntax for this header is as follows:

Bundle-License ::= '<<EXTERNAL>>' | 
                      ( license ( ',' license ) * )
license        ::= license-identifier ( ';' license-attr ) *
license-attr   ::= description | link
description    ::= 'description' '=' string
link           ::= 'link' '=' <url>

This header has the following attributes:

  • license-identifier - Provides a globally unique identifier for this license, preferably world wide, but it should at least be unique with respect to the other clauses. The magic identifier <<EXTERNAL>> is used to indicate that this artifact does not specify any license information but that licensing information is provided in some other way. This is also the default value of this header.

    This identifier should be one of the identifiers defined by [25] Software Package Data Exchange (SPDX) License List. Clients of this bundle can assume that licenses with the same identifier refer to the same license. This can for example be used to minimize the click through licenses.

    Alternatively, the identifier can be the canonical URL of the license, it must not be localized by the translator. This URL does not have to exist but must not be used for later versions of the license. It is recommended to use URLs from [19] Open Source Initiative. Other licenses should use the following structure, but this is not mandated:

    http://<domain-name>/licenses/
              <license-name>-<version>.<extension>
  • description - (optional) Provide the description of the license. This is a short description that is usable in a list box on a UI to select more information about the license.

  • link - (optional) Provide a URL to a page that defines or explains the license. If this link is absent, the name field is used for this purpose. The URL is relative to the root of the bundle. That is, it is possible to refer to a file inside the bundle.

If the Bundle-License statement is absent, then this does not mean that the bundle is not licensed. Licensing could be handled outside the bundle and the <<EXTERNAL>> form should be assumed. This header is informational and may not have any legal bearing. Consult a lawyer before using this header to automate licensing processing.

3.2.1.12 Bundle-Localization: OSGI-INF/l10n/bundle

The Bundle-Localization header contains the location in the bundle where localization files can be found. The default value is OSGI-INF/l10n/bundle. Translations are by default therefore OSGI-INF/l10n/bundle_de.properties, OSGI-INF/l10n/bundle_nl.properties, etc. See Manifest Localization.

3.2.1.13 Bundle-ManifestVersion: 2

The Bundle-ManifestVersion header defines that the bundle follows the rules of this specification. The Bundle-ManifestVersion header determines whether the bundle follows the rules of this specification. It is 1 (the default) for Release 3 Bundles, 2 for Release 4 and later. Future version of the OSGi framework can define higher numbers for this header.

3.2.1.14 Bundle-Name: Firewall

The Bundle-Name header defines a readable name for this bundle. This should be a short, human-readable name that can contain spaces.

3.2.1.15 Bundle-NativeCode: /lib/http.DLL; osname = QNX; osversion = 3.1

The Bundle-NativeCode header contains a specification of native code libraries contained in this bundle. See Loading Native Code Libraries.

3.2.1.16 Bundle-RequiredExecutionEnvironment: CDC-1.0/Foundation-1.0

The Bundle-RequiredExecutionEnvironment contains a comma-separated list of execution environments that must be present on the OSGi framework. See Execution Environment. This header is deprecated.

3.2.1.17 Bundle-SCM: url=https://github.com/bndtools/bnd, connection=scm:git:https://github.com/bndtools/bnd.git, developerConnection=scm:git:[email protected]:bndtools/bnd.git

The Bundle-SCM header provides an optional machine readable form of information about the source code of the bundle. This header is purely informational and must not be processed by the OSGi Framework.

The syntax for this header is as follows:

Bundle-SCM           ::= scm-attr ( ',' scm-attr ) *
scm-attr             ::= url | connection | developer-connection | tag
url                  ::= 'url' '=' <url>
connection           ::= 'connection' '=' <uri>
developer-connection ::= 'developerConnection' '=' <uri>
tag                  ::= 'tag' '=' argument

This header has the following attributes:

  • url - (optional) The URL to browse the source code repository.

  • connection - (optional) The scm: URI for read access to the source code repository.

  • developer-connection - (optional) The scm: URI for write access to the source code repository.

  • tag - (optional) The tag within the source code repository.

See [27] Maven POM Reference, SCM for more information. Tools can use the information in this header for POM generation.

3.2.1.18 Bundle-SymbolicName: com.acme.daffy

The Bundle-SymbolicName header specifies a non-localizable name for this bundle. The bundle symbolic name together with a version must identify a unique bundle though it can be installed multiple times in a framework. The bundle symbolic name should be based on the reverse domain name convention, see Bundle-SymbolicName. This header must be set.

3.2.1.19 Bundle-UpdateLocation: http://www.acme.com/Firewall/bundle.jar

The Bundle-UpdateLocation header specifies a URL where an update for this bundle should come from. If the bundle is updated, this location should be used, if present, to retrieve the updated JAR file.

3.2.1.20 Bundle-Vendor: OSGi Alliance

The Bundle-Vendor header contains a human-readable description of the bundle vendor.

3.2.1.21 Bundle-Version: 1.1

The Bundle-Version header specifies the version of this bundle. See Version. The default value is 0.0.0

3.2.1.22 DynamicImport-Package: com.acme.plugin.*

The DynamicImport-Package header contains a comma-separated list of package names that should be dynamically imported when needed. See Dynamic Import Package.

3.2.1.23 Export-Package: org.osgi.util.tracker;version=1.3

The Export-Package header contains a declaration of exported packages. See Export-Package.

3.2.1.24 Export-Service: org.osgi.service.log.LogService

Deprecated.

3.2.1.25 Fragment-Host: org.eclipse.swt; bundle-version="[3.0.0,4.0.0)"

The Fragment-Host header defines the host bundles for this fragment. See Fragment-Host

3.2.1.26 Import-Package: org.osgi.util.tracker,org.osgi.service.io;version=1.4

The Import-Package header declares the imported packages for this bundle. See Import-Package.

3.2.1.27 Import-Service: org.osgi.service.log.LogService

Deprecated

3.2.1.28 Provide-Capability: com.acme.dict; from=nl; to=de; version:Version=1.2

Specifies that a bundle provides a set of Capabilities, see Dependencies.

3.2.1.29 Require-Bundle: com.acme.chess

The Require-Bundle header specifies that all exported packages from another bundle must be imported, effectively requiring the public interface of another bundle. See Require-Bundle

3.2.1.30 Require-Capability: osgi.ee; filter:="(&(osgi.ee=AcmeMin)(version=1.1))"

Specifies that a bundle requires other bundles to provide a capability, see Dependencies.

3.2.2 Custom Headers

The manifest is an excellent place to provide metadata belonging to a bundle. This is true for the OSGi Alliance but it is also valid for other organizations. For historic reasons, the OSGi Alliance claims the default namespace, specifically headers that indicate OSGi related matters like names that contain Bundle, Import, Export, etc. Organizations that want to use headers that do not clash with OSGi Alliance defined names or bundle header names from other organizations should prefix custom headers with x-, for example x-LazyStart.

Organizations external to the OSGi Alliance can request header names in the OSGi namespace. The OSGi Alliance maintains a registry of such names at [16] OSGi Header Registry.

The Header annotation can be used on a class or package to specify a header for a bundle. This annotation can be processed by bundle assembly tools to generate the specified header information in the bundle's manifest.

3.2.3 Header Value Syntax

Each Manifest header has its own syntax. In all descriptions, the syntax is defined with [11] W3C EBNF. These following sections define a number of commonly used terminals.

3.2.4 Common Header Syntax

Many Manifest header values share a common syntax. This syntax consists of:

header ::= clause ( ',' clause ) *
clause ::= path ( ';' path ) *  
              ( ';' parameter ) *     // See 1.3.2

A parameter can be either a directive or an attribute. A directive is an instruction that has some implied semantics for the Framework. An attribute is used for matching and comparison purposes.

3.2.5 Version

Version specifications are used in several places. A version has the following grammar:

version     ::= 
        major( '.' minor ( '.' micro ( '.' qualifier )? )? )?

major       ::= number                   // See 1.3.2
minor       ::= number
micro       ::= number
qualifier   ::= ( alphanum | '_' | '-' )+

A version must not contain any white space. The default value for a version is 0.0.0.

Versions are supported in the API with the Version class.

The Version annotation can be used in package-info.java source files to document the version of a package. This annotation can be processed by bundle assembly tools when generating the version information for a bundle's Export-Package manifest header.

3.2.6 Version Ranges

A version range describes a range of versions using a mathematical interval notation. See [12] Mathematical Convention for Interval Notation. The syntax of a version range is:

version-range ::= interval | atleast
interval      ::= ( '[' | '(' ) floor ',' ceiling ( ']' | ')' )
atleast       ::= version
floor         ::= version
ceiling       ::= version

If a version range is specified as a single version, it must be interpreted as the range [version,). The default for a non-specified version range is 0, which maps to [0.0.0,).

Note that the use of a comma in the version range requires it to be enclosed in double quotes. For example:

Import-Package: com.acme.foo;version="[1.23,2)", «
   com.acme.bar;version="[4.0, 5.0)"

In the following table, for each specified range in the left-hand column, a version x is considered to be a member of the range if the predicate in the right-hand column is true.

Table 3.1 Examples of version ranges

Example Predicate

[1.2.3, 4.5.6)

1.2.3 <= x < 4.5.6

[1.2.3, 4.5.6]

1.2.3 <= x <= 4.5.6

(1.2.3, 4.5.6)

1.2.3 < x < 4.5.6

(1.2.3, 4.5.6]

1.2.3 < x <= 4.5.6

1.2.3

1.2.3 <= x


Version Ranges are supported in the API with the VersionRange class.

3.2.7 Filter Syntax

The OSGi specifications use filter expressions extensively. Filter expressions allow for a concise description of a constraint. The syntax of a filter string is based upon the string representation of LDAP search filters as defined in [5] A String Representation of LDAP Search Filters. It should be noted that RFC 2254: A String Representation of LDAP Search Filters supersedes RFC 1960, but only adds extensible matching and is not applicable to this OSGi Framework API.

The string representation of an LDAP search filter uses a prefix format and is defined by the following grammar:

filter      ::= '(' filter-comp ')'
filter-comp ::= and | or | not | operation
and         ::= '&' filter-list
or          ::= '|' filter-list
not         ::= '!' filter
filter-list ::= filter | filter filter-list
operation   ::= simple | present | substring
simple      ::= attr filter-type value
filter-type ::= equal | approx | greater-eq | less-eq
equal       ::= '='
approx      ::= '~='
greater-eq  ::= '>='
less-eq     ::= '<='
present     ::= attr '=*'
substring   ::= attr '=' initial any final
initial     ::= () | value
any         ::= '*' star-value
star-value  ::= () | value '*' star-value
final       ::= () | value
value       ::= <see text>
attr        ::= <see text>

attr is a string representing an attribute key or name. Attribute names are not case sensitive; that is, cn and CN both refer to the same attribute. attr must not contain the characters '=', '>', '<', '~', '(' or ')'. attr may contain embedded spaces but leading and trailing spaces must be ignored.

value is a string representing the value, or part of one, which will be compared against a value in the filtered properties.

If value must contain one of the characters reverse solidus ('\' \u005C), asterisk ('*' \u002A), parentheses open ('(' \u0028) or parentheses close (')' \u0029), then these characters should be preceded with the reverse solidus ('\' \u005C) character. Spaces are significant in value. Space characters are defined by Character.isWhiteSpace().

Although both the substring and present productions can produce the attr=* construct, this construct is used only to denote a presence filter.

The substring production only works for attributes that are of type String, Collection of String or String[]. In all other cases the result must be false.

The evaluation of the approximate match ('~=') filter type is implementation specific but should at least ignore case and white space differences. Codes such as Soundex or other smart closeness comparisons could be used.

Values specified in the filter are compared to values in the properties against which the filter is evaluated. The comparison of these values is not straightforward. Strings compare differently than numbers, and it is also possible for a property to have multiple values.

Property keys are case insensitive. The object class of the property's value defines the comparison type. The properties values should be of the following types:

Figure 3.1 Primary Property Types

type        ::=  scalar  | collection | array
scalar      ::=  String | Integer | Long | Float 
                    | Double | Byte | Short 
                    | Character | Boolean
primitive   ::= int | long | float | double | byte 
                    | short | char | boolean
array       ::= <Array of primitive>  
                    | <Array of scalar>
collection  ::= <Collection of scalar>

The following rules apply for comparison:

  • String - Use String comparison

  • Integer, Long, Float, Double, Byte, Short, Character objects and primitives - Use numerical comparison. The value should be trimmed of any extraneous white space before the comparison.

  • Boolean objects - Use comparison defined by Boolean.valueOf(value).booleanValue(). The value should be trimmed of any extraneous white space before this conversion is applied.

  • Array or Collection elements - Comparison is determined by the object type of the element

Array and Collection elements may be a mix of scalar types. Array and Collection elements may also be null. If the type of the property value is not one of the above types, then it could be possible to create an instance of the above type. The following conversions must be tried in the given order:

  1. A public static method on the required type called valueOf that returns an instance of the given type and takes a single String argument.

  2. A public constructor taking a single String argument.

If one of these methods is available then the Framework must construct a temporary object by passing the value as the String argument. If the constructor/function is not directly accessible then the invocation should use the setAccessible method to make it accessible.

The resulting object must be used to compare with the property value according to the following comparison rules:

  • Comparable objects - Comparison through the Comparable interface

  • Other objects - Equality comparison

If none of the above comparison rules apply, then the result of the comparison is false.

A filter matches a property with multiple values if it matches at least one of those values. For example:

Dictionary dict = new Hashtable();
dict.put( "cn", new String[] { "a", "b", "c" } );

The dict will match against a filter with (cn=a) as well as (cn=b).

Service properties are often defined to take a type, a collection of that type, or an array of that type. In those cases, a simple + will be suffixed to the type name. For example String+, indicates that a String, a String[], and a Collection<String> are all valid forms.

Filters are supported in the API with the Filter type. Filters can be created with the FrameworkUtil.createFilter(String) method or the BundleContext.createFilter(String) method.

3.2.8 Multi-release JAR

A bundle JAR file can be a multi-release JAR. See [28] Multi-release JAR File. When a bundle is a multi-release JAR, that is, the manifest contains

Multi-Release: true

then the Framework must look for a supplemental manifest file, OSGI-INF/MANIFEST.MF, in the versioned directories. For example:

META-INF/versions/9/OSGI-INF/MANIFEST.MF

The Framework must first look in the versioned directory for the major version of the current Java platform and then prior versioned directories in descending order. The first supplemental manifest file found must be used and the Framework must replace the values of the following manifest headers in the manifest with the values of these headers, if present, in the supplemental manifest file.

  • Import-Package

  • Require-Capability

Any other headers in the supplemental manifest file must be ignored.

The Framework APIs which provide access to the bundle metadata, such as getHeaders() and BundleRevision and BundleWiring, must present the supplemented manifest information. That is, the main manifest with the replacement values from a supplemental manifest, if any, for the running Java platform version.

Both fragment bundles as well as non-fragment bundles can be multi-release JARs.

Support for multi-release JARs must only be active on Java 9 and later. On Java 8 and earlier, the JAR must be treated as a non-multi-release JAR.

3.3 Dependencies

OSGi dependency handling is based on a very general model that describes the dependency relationships. This model consists of a small number of primitive concepts:

  • Environment - A container or framework that installs Resources.

  • Resource - An abstraction for an artifact that needs to become installed in some way to provide its intended function. A Bundle is modeled by a Resource but for example a display or secure USB key store can also be Resources.

  • Namespace - Defines what it means for the Environment when a requirement and capability match in a given Namespace.

  • Capability - Describing a feature or function of the Resource when installed in the Environment. A capability has attributes and directives.

  • Requirement - An assertion on the availability of a capability in the Environment. A requirement has attributes and directives. The filter directive contains the filter to assert the attributes of the capability in the same Namespace.

The relations between these entities are depicted in Figure 3.2.

Figure 3.2 Core Requirement/Capability model

Core Requirement/Capability model

A Resource in general has dependencies on other Resources or can satisfy other Resource's dependencies. Dependency types can vary wildly, a Bundle can require packages from another Bundle (Import-Package), or a Fragment needs a host Bundle (Fragment-Host), or a Bundle requires access to a high resolution display. The OSGi Core specification demonstrates that it is possible to describe these varying types of dependencies with dedicated headers, optimized for each case. However, this model requires that every type of dependency will go through a specification process, limiting the usefulness for parties not participating in this process. Therefore, this specification provides a generic dependency model based on Namespaces. A Namespace is the type of a dependency. For example, the osgi.wiring.package Namespace defines the semantics for Import-Package and Export-Package headers by specifying a number of attributes and directives. Attributes are used for matching and directives provide information about the semantics of the Namespace. For example, in the case of the osgi.wiring.host Namespace (Fragments) the capability's attributes are:

  • osgi.wiring.host - (String) The host's name.

  • bundle-version - (Version) The host's version.

  • * - Any other attributes are allowed.

The OSGi Framework Namespaces are defined in classes, see Framework Namespaces Specification.

The purpose of a Namespace is to create an attribute/directive based language that describes a dependency in a generic way unrelated to the specific dependency type. A number of Namespaces have been defined by the OSGi Alliance in this and other specifications. OSGi namespaces start with the reserved osgi. prefix. For example, the osgi.ee namespace defines a capability for specifying an execution environment. A Namespace can also be defined by other organizations and individuals. To minimize name clashes it is recommended to use the reverse domain name rule used for packages and bundle symbolic names. It is also recommended to register these Namespaces with the OSGi Alliance, see [17] OSGi Namespace Registry to prevent clashes.

Given a Namespace, it is possible to declare a capability of that Namespace. A capability provides the values for the attributes and directives defined in the Namespace. For example, it is possible to translate the Export-Package header to a capability in the osgi.wiring package Namespace.

Given a capability, it is possible to specify a requirement. A requirement has a filter that can match the attributes of the capability, if so, the requirement is satisfied. Requirements are always associated with a given Namespace, like the capability, and can therefore only be satisfied by Capabilities in the same Namespace. A requirement is satisfied when its filter, as specified with the filter directive, matches a capability's attributes. The filter language specification can be found in Filter Syntax. A requirement can be mandatory or optional, as set with its resolution directive. A requirement can have single or multiple cardinality, indicating it requires at least one or more Capabilities.

A Resource that declares requirements can only provide its intended functionality when its mandatory requirements are satisfied by one or more Capabilities, which in general means they come from other Resources. A Resource that has all its mandatory requirements satisfied is said to be resolved and must provide the functionality described by its Capabilities. A capability can only satisfy a requirement if its Resource is resolved.

The process of matching up requirements to capabilities is called resolving. In this process, the resolver must create Wires that link requirements to Capabilities. Both the Wire and the requirement/ Capability have a reference to a Resource. In certain cases the requirement/ capability can be declared in one Resource but wired from another Resource. Therefore, a requirement/ capability can have a declared Resource, which is the Resource that declares it. However, when a Resource is wired the Wire has a provider or requirer Resource which can differ from the corresponding declared Resource. When the declared Resource differs from the provider/requirer it is called hosting. This separation is caused by Fragments; with Fragments some requirements and Capabilities are hosted and others remain part of the Fragment.

Only requirements that are effective must be wired. Each requirement is intended for a certain state of the system. For example, the OSGi Framework only resolves requirements when the requirement has the effective directive set to resolve.

Once a set of Resources are resolved the Environment, for example the OSGi Framework for bundles, creates a Wiring per Resource to hold the resolved state. This state includes the Wires as well as all Capabilities and requirements, regardless if they are wired or not.

The Wires between a requirement and a capability must be created according to the semantics implied by their Namespace. The Wires coming out of a resolve operation can be used during run time as specified in their Namespace. For example, the osgi.wiring.* Namespaces are used to control the Class Loading, see Bundle Wiring API Specification. However, they can also serve other purposes as outlined by their Namespace. For example, a Wire could specify a Dependency Injection source and target.

Interfaces for the generic model are defined in Resource API Specification. The Bundle Wiring API Specification chapter describes the Wiring API that is based on this generic package. The generic API is intended for other specifications that want to be compatible with the generic OSGi Core framework's Capability /Requirement model.

3.3.1 Bundles

All bundles depend on one or more external entities and this is expressed as requirements and Capabilities. Once a bundle is resolved, it assumes that those dependencies are satisfied. The Require-Capability and Provide-Capability headers are manifest headers that declare generic requirements and Capabilities in any Namespace. However, a number of manifest headers in the OSGi specifications are actually requirements on Capabilities specified by other OSGi manifest headers. For example, an Import-Package clause is a requirement on the capability specified by an Export-Package clause. The attributes on an Import-Package clause are treated as assertions on the attributes of the corresponding Export-Package clause. This specification therefore contains a number of Namespaces for these OSGi manifest headers: osgi.wiring.bundle, osgi.wiring.package, and osgi.wiring.host. These namespaces influence the resolver and define the class loading process. For example, a Require-Bundle clause is a requirement that ensures that the exported packages of the required bundle are available to the requirer's class loader.

The OSGi resolving process is described in Resolving Process. The diagramming technique of the Requirement/Capability model is depicted in Figure 3.3, the details of the wiring are further explained in Bundle Wiring API Specification.

Figure 3.3 Requirements and Capabilities and their Wiring

Requirements and Capabilities and their Wiring

3.3.2 Example Use Case

A bundle has Windows 7 specific Java code and requires a display that has a resolution of at least 1000x1000 pixels. It also relies on a bundle providing an IP-number-to-location table.

These dependencies on the environment and another bundle can be expressed with the requirement header in the bundle as follows:

Require-Capability:
  com.microsoft;    filter:="(&(api=win32)(version=7))",
  com.acme.display; filter:="(&(width>=1000)(height>=1000))",
  com.acme.ip2loc

Each clause lives in a namespace, for example com.microsoft. A namespace defines the semantics of the attributes as well as optional rules.

The deployer of the environment sets the following launching property when starting the framework:

org.osgi.framework.system.capabilities.extra= «
  com.acme.display; width:Long=1920; height:Long=1080; interlace=p, «
  com.microsoft; edition=home; version:Version=7; api=win32

The framework will be able to satisfy the display requirement but it cannot satisfy the ip2loc table requirement. The deployer can then install the bundle with the ip2loc table. This bundle specifies the following header:

Provide-Capability: com.acme.ip2loc; version:Version=1.2

After installing and resolving this bundle, the framework can resolve the original bundle because there is now a provider of the ip2loc table.

3.3.3 Bundle Capabilities

A generic capability for a Bundle is defined with the Provide-Capability header. This header has the following syntax:

Provide-Capability  ::= capability (',' capability )*
capability          ::= name-space 
                            ( ';' directive | typed-attr )*
name-space          ::= symbolic-name
typed-attr          ::=  extended ( ':' type )? '=' argument
type                ::= scalar | list
scalar              ::= 'String' | 'Version' | 'Long' 
                            |   'Double' 
list                ::= 'List' ( '<' scalar '>' )?

The Capability annotation can be used on a class or package to specify a capability to be provided by the bundle. This annotation can be processed by bundle assembly tools to add the capability to the Provide-Capability header in the bundle's manifest.

The header has the following directives architected:

  • effective - (resolve) Specifies the time a capability is available, either resolve (default) or another name. The OSGi framework resolver only considers Capabilities without an effective directive or effective:=resolve. Capabilities with other values for the effective directive can be considered by an external agent.

  • uses - The uses directive lists package names that are used by this capability. This information is intended to be used for uses constraints, see Package Constraints.

Namespaces can define additional directives and attributes.

3.3.4 Bundle Capability Attributes

Attributes can be typed. Typing is important because it defines how attributes compare. Comparing two versions as strings does not provide the proper comparison semantics for versions. In similar vein, lexicographical ordering is different than numeric ordering.

Types are specified between the attribute name and the equal sign ('=' \u003D), the separator is a colon (':' \u003A). For example:, for a Long:

attr:Long=24

If no type is specified, the String type is assumed.

The parsing rules of the corresponding type's String constructor are then used to create a new instance that is placed in the capability's map. Numeric types must trim white space around the value, for other types spaces around the argument are not ignored, however, white space is skipped by the manifest parsing rules. That is:

attr:Long=        23       ,            //ok
attr:Version="    23      ",            // error
attr:Long="       23      ",            // ok, because nummeric

Multi-valued attributes can be constructed with the List type. The List type can specify a scalar type for the list elements. If no element type is specified, String is assumed. Parsing of the corresponding argument list must be done according to the following rules:

  • Element values in the list are separated by commas (',' \u002C).

  • White space around an element value must be trimmed for non-String element types.

  • Commas or reverse solidi ('\' \u005C) that are part of an element value must be escaped by prefixing them with a reverse solidus. In practice, this requires escaping with two reverse solidi because a reverse solidus must already be escaped in strings.

The whole argument must be surrounded by quotes because the comma is a significant token in the manifest grammar.

The version attribute requires the Version type to be specified to be compared as a Version rather than as a String:

version:Version=1.23

For example:

Provide-Capability: «
   com.acme.dictionary; from:String=nl; to=de; version:Version=3.4, «
   com.acme.dictionary; from:String=de; to=nl; version:Version=4.1, «
   com.acme.ip2location;country:List="nl,be,fr,uk";version:Version=1.3, «
   com.acme.seps;       tokens:List<String>="\\,,;,\\\""

3.3.5 System Bundle Capabilities

Capabilities can also be provided by the system bundle by specifying the following launch properties:

org.osgi.framework.system.capabilities
org.osgi.framework.system.capabilities.extra

The format for these system properties is identical to the Provide-Capability header. A framework must parse these properties and use them in the resolving process as if provided by the system bundle.

There are two properties so that the framework can specify its default Capabilities in org.osgi.framework.system.capabilities while the deployer can specify specific deployment Capabilities in the org.osgi.framework.system.capabilities.extra system property. Frameworks can often deduce many Capabilities from their environment.

The following is an example capability header for the system bundle as defined by the deployer:

map.put("org.osgi.framework.system.capabilities.extra",
    "com.acme.screen; width:Long=640; height:Long=480; card=GeForce");

3.3.6 Bundle Requirements

The Bundle's Require-Capability header has the following grammar:

Require-Capability ::= requirement ( ',' requirement )* 
requirement        ::= name-space ( ';' directive | typed-attr )*

Requirements have attributes that can be set with the Require-Capability header. The purpose of these attributes are to provide further information about the requirement; they are not assertions as they are in the Import-Package, Require-Bundle, and Fragment-Host headers. The attributes of these headers are mapped to the filter directive in their corresponding namespaces.

The Requirement annotation can be used on a class or package to specify a capability to be required by the bundle. This annotation can be processed by bundle assembly tools to add the requirement to the Require-Capability header in the bundle's manifest.

The following directives are architected for the Require-Capability header:

  • effective - (resolve) Specifies the time a requirement is considered, either resolve (default) or another name. The OSGi framework resolver only considers requirements without an effective directive or effective:=resolve. Other requirements can be considered by an external agent. Additional names for the effective directive should be registered with the OSGi Alliance.

  • resolution - (mandatory|optional) A mandatory requirement forbids the bundle to resolve when the requirement is not satisfied; an optional requirement allows a bundle to resolve even if the requirement is not satisfied. No wirings are created when this requirement cannot be resolved, this can result in Class Not Found Exceptions when the bundle attempts to use a package that was not resolved because it was optional. The default is mandatory.

  • filter - (Filter) A filter expression that is asserted on the Capabilities belonging to the given namespace. The matching of the filter against the capability is done on one capability at a time. A filter like (&(a=1)(b=2)) matches only a capability that specifies both attributes at the required value, not two capabilities that each specify one of the attributes correctly. A filter is optional, if no filter directive is specified the requirement always matches. The attribute names in the filter expression are used to locate capability attributes in a case sensitive manner.

  • cardinality - (single|multiple) Indicates if the requirement can be wired a single time or multiple times. The default is single.

Additional directives are ignored during resolving. Attributes on the requirement clause are also ignored.

3.4 Execution Environment

The Java environment provides all packages in the java.* namespace. Prior to Java SE 9, this namespace was not well defined and could be different for different runtime environments. For example, Java SE 5 is not equal to Java SE 7 and an Android environment has substantial differences to a Java SE environment. However, Java SE 6 is backward compatible for Java SE 5, Java SE 1.4, Java SE 1.3 and Java SE 1.2. That is, applications written for Java SE 1.3 must run unchanged on a Java SE 5 environment.

These differences and backward compatibilities can not be captured using versions because they are variations. For example, [22] Google Android is a variation of a Java SE 5 environment, as is [23] Google App Engine and [24] Google Web Toolkit. All these variations have a different set of packages, types, and methods in the java.* namespace.

Starting in Java SE 9, the platform has been modularized and its packages organized into a set of modules. Depending upon how the platform is configured for execution, some modules and their contained packages may not be present at runtime. However, Java SE 9 provides a standard way to interrogate the Java platform for the packages currently available at runtime. Therefore, the Framework must set the org.osgi.framework.system.packages launching property, see Launching Properties, to the list of Java platform packages currently available at runtime.

For Java platform versions prior to Java SE 9, the Framework must also set the org.osgi.framework.system.packages launching property to the list of Java platform packages generally known to be available at runtime. Since there is no standard way to interrogate the Java platform for the packages currently available at runtime, a Framework implementation may use a predefined list of packages for the Java platform version.

In additional to specifying the version of the execution environment via an osgi.ee requirement, see osgi.ee Namespace, a Bundle may also import java.* packages using the Import-Package header. Imports of java.* packages by a bundle will be used during the resolution process, see Resolving Process, to ensure the bundle has visibility to the requested packages by wiring the bundle's import of a java.* package to the export of the java.* package by the Framework's system bundle. However, a bundle always loads classes in java.* packages via parent delegation. See Parent Delegation. Therefore, a bundle is not required to import a java.* package to have visibility to the classes in the package, if the package is present in the current runtime. It only needs to import a java.* package to have the resolution process ensure the package is available from the execution environment. This can avoid a NoClassDefFoundError during execution of the bundle due to a missing java.* package required by the bundle.

3.4.1 Bundle-RequiredExecutionEnvironment

The Bundle-RequiredExecutionEnvironment manifest header provides the same function as the osgi.ee Namespace. It allows a bundle to depend on the execution environment. This header is deprecated but must be fully supported by a compliant framework. Bundles should not mix these headers but use either an osgi.ee requirement or this header. If both are used, both constraints must be met to resolve.

The syntax of this header is a list of comma-separated names of execution environments.

Bundle-RequiredExecutionEnvironment ::= ee-name ( ',' ee-name )*

ee-name  ::= bree | <ee name>
bree     ::= token ( '-' version )? ( '/' token ( '-' version )? )?

For example:

Bundle-RequiredExecutionEnvironment: CDC-1.0/Foundation-1.0, «
  OSGi/Minimum-1.1

If a bundle includes this header in the manifest then the bundle must only use methods with signatures that are contained within a proper subset of all mentioned execution environments. Bundles should list all (known) execution environments on which it can run the bundle.

A bundle can only resolve if the framework is running on a VM which implements one of the listed required execution environments. Frameworks should recognize that the current VM can implement multiple execution environments. For example, Java 6 is backward compatible with Java 5 and a bundle requiring the Java 6 execution environment must resolve on a Java 6 VM.

The Bundle-RequiredExecutionEnvironment header can not prevent a bundle from installing.

The org.osgi.framework.executionenvironment launching property defines the current execution environment with a comma separated list of execution environment names. If not set, the framework must provide an appropriate value. This property is also deprecated, its function is replaced with org.osgi.framework.system.capabilities[.extra].

An example:

org.osgi.framework.executionenvironment = 
     JavaSE-1.5, J2SE-1.4, JavaSE-1.4, JavaSE-1.3, OSGi/Minimum-1.1

Frameworks must convert a Bundle-RequiredExecutionEnvironment header to a requirement in the osgi.ee namespace when used in the Wiring API, see Bundle Wiring API Specification. Since the header uses opaque names for the execution environments there is no guaranteed algorithm to map the ee-name to a Require-Capability header. However, the suggested names so far for popular execution environments do have a structure that can be used to create such a header, this pattern was reflected in the bree term. The structure of the bree term for the existing recommendations is:

n1 ( '-' v )? ( '/' n2 ( '-' v )? )?

For example:

CDC-1.0/Foundation-1.0
OSGi/Minimum-1.2
J2SE-1.4
JavaSE-1.4

Each bree term that matches this pattern can thus be converted into an equivalent osgi.ee Require-Capability filter. First variable n1 must be replaced with JavaSE when it is J2SE since the Require-Capability header uses a single name for the Java Standard Edition. The filter directive can then be constructed from n1, v, and n2. If n2 is not defined or v is not defined then the parenthesized parts in which they participate are not used in the expansion.

bree-filter ::= '(&(osgi.ee=' n1 ( '/' n2 )? ')' ( '(version=' v ')' )? ')'

If the bree term cannot be parsed into the given constituents then the filter must look like:

filter    ::= '(osgi.ee=' <ee name> ')'

Some examples:

CDC-1.0/Foundation-1.0      (&(osgi.ee=CDC/Foundation)(version=1.0))
OSGi/Minimum-1.2            (&(osgi.ee=OSGi/Minimum)(version=1.2))
J2SE-1.4                    (&(osgi.ee=JavaSE)(version=1.4))
JavaSE-1.6                  (&(osgi.ee=JavaSE)(version=1.6))
AA/BB-1.7                   (&(osgi.ee=AA/BB)(version=1.7))
V1-1.5/V2-1.6               (osgi.ee=V1-1.5/V2-1.6)
MyEE-badVersion             (osgi.ee=MyEE-badVersion)

Each element of the Bundle-RequiredExecutionEnvironment is ORed together in the final osgi.ee requirement's filter directive. For example:

Bundle-RequiredExecutionEnvironment: 
    CDC-1.0/Foundation-1.0,
    OSGi/Minimum-1.2,
    J2SE-1.4,
    JavaSE-1.6,
    AA/BB-1.7,
    V1-1.5/V2-1.6,
    MyEE-badVersion

This must be converted into the following Require-Capability:

Require-Capability:osgi.ee; filter:="(|
    (&(osgi.ee=CDC/Foundation)(version=1.0))
    (&(osgi.ee=OSGi/Minimum)(version=1.2))
    (&(osgi.ee=JavaSE)(version=1.4))
    (&(osgi.ee=JavaSE)(version=1.6))
    (&(osgi.ee=AA/BB)(version=1.7))
    (osgi.ee=V1-1.5/V2-1.6)
    (osgi.ee=MyEE-badVersion)
 )"

Every org.osgi.resource.Resource representing a Bundle which has a Bundle-RequiredExecutionEnvironment header must have the converted osgi.ee requirement in the list returned by getRequirements(String) for the osgi.ee namespace. In cases where the bundle already has a requirement for the osgi.ee namespace no merging is done, the bundle will simply have an additional osgi.ee requirement added.

3.5 Class Loading Architecture

Many bundles can share a single virtual machine (VM), see [1] Java Virtual Machine Specification. Within this VM, bundles can hide packages and classes from other bundles, as well as share packages with other bundles.

The key mechanism to hide and share packages is the Java class loader that loads classes from a sub-set of the bundle-space using well-defined rules. Each bundle has a single class loader. That class loader forms a class loading delegation network with other bundles as shown in Figure 3.4.

Figure 3.4 Delegation model

Delegation model

The class loader can load classes and resources from:

  • Boot class path - The boot class path contains the java.* packages and its implementation packages.

  • Framework class path - The Framework usually has a separate class loader for the Framework implementation classes as well as key service interface classes.

  • Bundle Space - The bundle space consists of the JAR file that is associated with the bundle, plus any additional JAR that are closely tied to the bundle, like fragments, see Fragment Bundles.

A class space is then all classes reachable from a given bundle's class loader. Thus, a class space for a given bundle can contain classes from:

  • The parent class loader (normally java.* packages from the boot class path)

  • Imported packages

  • Required bundles

  • The bundle's class path (private packages)

  • Attached fragments

A class space must be consistent, such that it never contains two classes with the same fully qualified name (to prevent Class Cast Exceptions). However, separate class spaces in an OSGi Platform may contain classes with the same fully qualified name. The modularization layer supports a model where multiple versions of the same class are loaded in the same VM.

Figure 3.5 shows the class space for a Bundle A. The right top of Bundle A is not in the class space because it illustrates that sometimes packages inside a bundle are not accessible to the Bundle itself when an export is substituted.

Figure 3.5 Class Space

Class Space

The Framework therefore has a number of responsibilities related to class loading. Before a bundle is used, it must resolve the constraints that a set of bundles place on the sharing of packages. Then select the best possibilities to create a wiring. See Resolving Process for further information. The runtime aspects are described in Runtime Class Loading.

3.5.1 Resolving

The Framework must resolve bundles. Resolving is the process where any external dependencies are satisfied and then importers are wired to exporters. Resolving is a process of satisfying constraints; constraints that are provided by the Dependencies section and constraints by the different manifest headers like Import/Export Package, Require-Bundle, and Fragment-Host. The resolving process must take place before any code from a bundle can be loaded or executed.

A wire is an actual connection between an exporter and an importer, which are both bundles. A wire is associated with a number of constraints that are defined by its importer's and exporter's manifest headers. A valid wire is a wire that has satisfied all its constraints. Figure 3.6 depicts the class structure of the wiring model. Not all constraints result in a wire.

Figure 3.6 Example class structure of wiring

Example class structure of wiring

3.6 Resolving Metadata

The following sections define the manifest headers that provide the metadata for the resolver.

3.6.1 Bundle-ManifestVersion

A bundle manifest must express the version of the OSGi manifest header syntax in the Bundle-ManifestVersion header. Bundles exploiting this version of the Framework specification (or later) must specify this header. The syntax of this header is as follows:

  Bundle-ManifestVersion ::= number     //See 1.3.2

The Framework bundle manifest version must be '2'. Bundle manifests written to previous specifications' manifest syntax are taken to have a bundle manifest version of '1', although there is no way to express this in such manifests. Therefore, any other value than 2 for this header is invalid unless the Framework explicitly supports such a later version.

OSGi Framework implementations should support bundle manifests without a Bundle-ManifestVersion header and assume Framework 1.2 compatibility at the appropriate places.

Version 2 bundle manifests must specify the bundle symbolic name. They need not specify the bundle version because the version header has a default value.

3.6.2 Bundle-SymbolicName

The Bundle-SymbolicName manifest header is a mandatory header. The bundle symbolic name and bundle version identify a unique bundle. This does not always imply that this pair is unique in a framework, in certain cases the same bundle can be installed multiple times in the same framework, see Bundle Identifiers.

A bundle gets its unique Bundle-SymbolicName from the developer. The Bundle-Name manifest header provides a human-readable name for a bundle and is therefore not replaced by this header.

The Bundle-SymbolicName manifest header must conform to the following syntax:

Bundle-SymbolicName ::= symbolic-name 
                        ( ';' parameter ) *    // See 1.3.2

The framework must recognize the following directives for the Bundle-SymbolicName header:

  • singleton - Indicates that the bundle can only have a single version resolved in an environment. A value of true indicates that the bundle is a singleton bundle. The default value is false. The Framework must resolve at most one bundle when multiple versions of a singleton bundle with the same symbolic name are installed. Singleton bundles do not affect the resolution of non-singleton bundles with the same symbolic name.

  • fragment-attachment - Defines how fragments are allowed to be attached, see the fragments in Fragment Bundles. The following values are valid for this directive:

    • always - (Default) Fragments can attach at any time while the host is resolved or during the process of resolving.

    • never - No fragments are allowed.

    • resolve-time - Fragments must only be attached during resolving.

  • mandatory - Provide a list of mandatory attributes. If these attributes are not specifically used in the requirement (Require-Bundle, Fragment-Host) then this bundle must not match. See Mandatory Attributes.

The header allows the use of arbitrary attributes that can be required by the Require-Bundle and Fragment-Host headers. The following attribute is predefined:

  • bundle-version - The value of the Bundle-Version header or 0 if no such header is present. Explicitly setting this attribute is an error.

For example:

Bundle-SymbolicName: com.acme.foo;singleton:=true

3.6.3 Bundle-Version

Bundle-Version is an optional header; the default value is 0.0.0.

Bundle-Version ::= version  // See 3.2.5

If the minor or micro version components are not specified, they have a default value of 0. If the qualifier component is not specified, it has a default value of the empty string ("").

Versions are comparable. Their comparison is done numerically and sequentially on the major, minor, and micro components and lastly using the String class compareTo method for the qualifier.

A version is considered equal to another version if the major, minor, micro, and the qualifier components are equal (using String method compareTo).

Example:

Bundle-Version: 22.3.58.build-345678

3.6.4 Import-Package

The Import-Package header defines the constraints on the imports of shared packages. The syntax of the Import-Package header is:

Import-Package ::= import ( ',' import )*
import ::= package-names ( ';' parameter )*
package-names ::= package-name 
                    ( ';' package-name )* // See 1.3.2

The header allows many packages to be imported. An import definition is the description of a single package for a bundle. The syntax permits multiple package names, separated by semi-colons, to be described in a short form.

Import package directives are:

  • resolution - Indicates that the packages must be resolved if the value is mandatory, which is the default. If mandatory packages cannot be resolved, then the bundle must fail to resolve. A value of optional indicates that the packages are optional. See Optional Packages.

The developer can specify arbitrary matching attributes. See Attribute Matching. The following arbitrary matching attributes are predefined:

  • version - A version-range to select the exporter's package version. The syntax must follow Version Ranges. For more information on version selection, see Semantic Versioning. If this attribute is not specified, it is assumed to be [0.0.0, ).

  • specification-version - This attribute is an alias of the version attribute only to ease migration from earlier versions. If the version attribute is present, the values must be equal.

  • bundle-symbolic-name - The bundle symbolic name of the exporting bundle. In the case of a fragment bundle, this will be the host bundle's symbolic name.

  • bundle-version - A version-range to select the bundle version of the exporting bundle. The default value is [0.0.0, ). See Semantic Versioning. In the case of a fragment bundle, the version is from the host bundle.

In order to be allowed to import a package, a bundle must have PackagePermission[<package-name>, IMPORT]. See PackagePermission for more information.

An error aborts an installation or update when:

  • A directive or attribute appears multiple times, or

  • There are multiple import definitions for the same package, or

  • The version and specification-version attributes do not match.

Example of a correct definition:

Import-Package: com.acme.foo;com.acme.bar; «
    version="[1.23,1.24]"; «
    resolution:=mandatory

3.6.5 Export-Package

The syntax of the Export-Package header is similar to the Import-Package header; only the directives and attributes are different.

Export-Package  ::= export ( ',' export)*
export          ::= package-names ( ';' parameter )*
package-names   ::= package-name                // See 1.3.2
                        ( ';' package-name )*

The header allows many packages to be exported. An export definition is the description of a single package export for a bundle. The syntax permits the declaration of multiple packages in one clause by separating the package names with a semi-colon. Multiple export definitions for the same package are allowed for example, when different attributes are needed for different importers. The Export annotation can be applied to a package to specify the package is to be exported. This annotation can be processed by bundle assembly tools to add the annotated package to the Export-Package header in the bundle's manifest.

Export directives are:

  • uses - A comma-separated list of package names that are used by the exported package. Note that the use of a comma in the value requires it to be enclosed in double quotes. If this exported package is chosen as an export, then the resolver must ensure that importers of this package wire to the same versions of the package in this list. See Package Constraints.

  • mandatory - A comma-separated list of attribute names. Note that the use of a comma in the value requires it to be enclosed in double quotes. A bundle importing the package must specify the mandatory attributes, with a value that matches, to resolve to the exported package. See Mandatory Attributes.

  • include - A comma-separated list of class names that must be visible to an importer. Note that the use of a comma in the value requires it to be enclosed in double quotes. For class filtering, see Class Filtering.

  • exclude -A comma-separated list of class names that must be invisible to an importer. Note that the use of a comma in the value requires it to be enclosed in double quotes. For class filtering, see Class Filtering.

The following attributes are part of this specification:

  • version - The version of the named packages with syntax as defined in Version. It defines the version of the associated packages. The default value is 0.0.0.

  • specification-version - An alias for the version attribute only to ease migration from earlier versions. If the version attribute is present, the values must be equal.

Additionally, arbitrary matching attributes may be specified. See Attribute Matching.

The Framework will automatically associate each package export definition with the following attributes:

  • bundle-symbolic-name - The bundle symbolic name of the exporting bundle. In the case of a fragment bundle, this is the host bundle's symbolic name.

  • bundle-version - The bundle version of the exporting bundle. In the case of a fragment bundle, this is the host bundle's version.

An installation or update must be aborted when any of the following conditions is true:

  • a directive or attribute appears multiple times

  • the bundle-symbolic-name or bundle-version attribute is specified in the Export-Package header.

An export definition does not imply an automatic import definition. A bundle that exports a package and does not import that package will get that package via its bundle class path. Such an exported only package can be used by other bundles, but the exporting bundle does not accept a substitution for this package from another bundle.

In order to export a package, a bundle must have PackagePermission[<package>, EXPORTONLY].

Example:

Export-Package: com.acme.foo;com.acme.bar;version=1.23

3.6.6 Importing Exported Packages

Bundles that collaborate require the same class loader for types used in the collaboration. If multiple bundles export packages with collaboration types then they will have to be placed in disjoint class-spaces, making collaboration impossible. Collaboration is significantly improved when bundles are willing to import exported packages; these imports will allow a framework to substitute exports for imports.

Though substitution is recommended to increase collaboration, it is not always possible. Importing exported packages can only work when those packages are pure API and not encumbered with implementation details. Import of exported packages should only be done when:

  • The exported package does not use private packages. If an exported package uses private packages then it might not be substitutable and is therefore not clean API.

  • There is at least one private package that references the exported package. If no such reference exist, there is no purpose in importing it.

In practice, importing exported packages can only be done with clean API-implementation separation. OSGi services are carefully designed to be as standalone as possible. Many libraries intertwine API and implementation in the same package making it impossible to substitute the API packages.

Importing an exported package must use a version range according to its compatibility requirements, being either a consumer or a provider of that API. See Semantic Versioning for more information.

3.6.7 Interpretation of Legacy Bundles

Bundles that are not marked with a Bundle-ManifestVersion that equals 2 or more must treat the headers according the definitions in the Release 3. More specifically, the Framework must map the Release 3 headers to the appropriate Release 4 headers:

  • Import-Package - An import definition must change the specification-version attribute to the version attribute. An import definition without a specification version needs no replacement since the default version value of 0.0.0 gives the same semantics as Release 3.

  • Export-Package - An export definition must change the specification-version attribute to the version attribute. The export definition must be appended with the uses directive. The uses directive must contain all imported and exported packages for the given bundle. Additionally, if there is no import definition for this package, then an import definition for this package with the package version must be added.

  • DynamicImport-Package - A dynamic import definition is unmodified.

A bundle manifest which mixes legacy syntax with bundle manifest version 2 syntax is in error and must cause the containing bundle to fail to install.

The specification-version attribute is a deprecated synonym for the version attribute in bundle manifest version 2 headers.

3.7 Constraint Solving

The OSGi Framework package resolver provides a number of mechanisms to match imports to exports. The following sections describe these mechanisms in detail.

3.7.1 Diagrams and Syntax

Wires create a graph of nodes. Both the wires as well as nodes (bundles) carry a significant amount of information. In the next sections, the following conventions are used to explain the many details.

Bundles are named A, B, C,... That is, uppercase characters starting from the character A. Packages are named p, q, r, s, t,... In other words, lower case characters starting from p. If a version is important, it is indicated with a dash followed by the version: q-1.0. The syntax A.p means the package definition (either import or export) of package p by bundle A.

Import definitions are graphically shown by a white box. Export definitions are displayed with a black box. Packages that are not exported or imported are called private packages. They are indicated with diagonal lines.

Bundles are a set of connected boxes. Constraints are written on the wires, which are represented by lines.

Figure 3.7 Legend of wiring instance diagrams, and example

Legend of wiring instance diagrams, and example

For example:

A: Import-Package: p; version="[1,2)"
   Export-Package: q; version=2.2.2; uses:=p
   Require-Bundle: C
B: Export-Package: p; version=1.5.1
C: Export-Package: r

Figure 3.8 shows the same setup graphically.

Figure 3.8 Example bundle diagram

Example bundle diagram

3.7.2 Version Constraints

Version constraints are a mechanism whereby an import definition can declare a precise version or a version range for matching an export definition.

An import definition must specify a version range as the value for its version attribute, and the exporter must specify a version as the value for its version attribute. Matching is done with the rules for version range matches as described in Version Ranges.

For example, the following import and export definition resolve correctly because the version range in the import definition matches the version in the export definition:

A: Import-Package: p; version="[1,2)"
B: Export-Package: p; version=1.5.1

Figure 3.9 graphically shows how a constraint can exclude an exporter.

Figure 3.9 Version Constrained

Version Constrained

3.7.3 Semantic Versioning

Version ranges encode the assumptions about binary compatibility. Though the OSGi frameworks do not enforce a specific encoding for a compatibility policy, it is strongly recommended to use the following semantics.

Traditionally, compatibility has always been between two parties. One is the consumer of the code and the other is the provider of the code. API based design introduces a third party in the compatibility policy:

  • The API itself

  • The provider of the API

  • The consumer of the API

A provider of an API is closely bound to that API. Virtually any change to that API makes a provider implementation incompatible with the new version of the API. However, API changes have more leeway from the perspective of a consumer of that API. Many API changes can be made backward compatible for consumers but hardly any API change can be made backward compatible for a provider of that API.

A provider of an API should therefore import that API with a smaller range than a consumer of that API. This policy can be encoded in a version range. The rules are summarized as follows:

  • major - Changes for an incompatible update for both a consumer and a provider of an API.

  • minor - Changes for a backward compatible update for a consumer but not for a provider.

  • micro - A change that does not affect the API, for example, a typo in a comment or a bug fix in an implementation.

Both consumers and providers should use the version they are compiled against as their base version. It is recommended to ignore the micro part of the version because systems tend to become very rigid if they require the latest bug fix to be deployed all the time. For example, when compiled against version 4.2.1.V201007221030, the base version should be 4.2.

A consumer of an API should therefore import a range that starts with the base version and ends with the next major change, for example: [4.2,5). A provider of an API should import a range that starts with the base version up to the next minor change, for example: [4.2,4.3).

3.7.4 Type Roles for Semantic Versioning

As mentioned in Semantic Versioning, there are two roles for clients of an API package: API consumers and API providers. API consumers use the API and API providers implement the API. For the types in an API, it is important that the API clearly document which of those types are only to be implemented or extended by API providers and which of those types can be implemented or extended by API consumers. For example, listener interfaces are generally implemented by API consumers and instances of them passed to API providers.

API providers are sensitive to changes in types implemented or extended by both API consumers and API providers. An API provider must implement any new changes in API provider types and must understand and likely invoke any new changes in API consumer types. An API consumer can generally ignore compatible changes in API provider types unless it wants to invoke the new function. But an API consumer is sensitive to changes in API consumer types and will probably need modification to implement the new function. For example, in the org.osgi.framework package, the BundleContext type is implemented by the Framework which is the API provider. Adding a new method to BundleContext will require all Framework implementations to be updated to implement the new method. Bundles, which are the API consumers, do not have to change unless they wish to call the new method. However, the BundleActivator type is implemented by bundles and adding a new method to BundleActivator will require all bundles implementing this interface to be modified to implement the new method and will also require all Framework implementations to be modified to utilize the new method. Thus the BundleContext type has an API provider role and the BundleActivator type has an API consumer role in the org.osgi.framework API package.

Since there are generally many API consumer and few API providers, API evolution must be very careful when considering changes to API consumer types while being more relaxed about changes to API provider types. This is because you will need to change the few API providers to support an updated API but you do not want to require the many existing API consumers to change when an API is updated. API consumers should only need to change when the API consumer wants to take advantage of new API.

The ProviderType and ConsumerType annotations can be used in source files to document the roles of types in a package. API types marked ProviderType must not be implemented or extended by API consumers. These annotations can be processed by bundle assembly tools that support Semantic Versioning when generating the version range information for a bundle's Import-Package manifest header.

3.7.5 Optional Packages

A bundle can indicate that it does not require a package to resolve correctly, but it may use the package if it is available. For example, logging is important, but the absence of a log service should not prevent a bundle from running.

Optional imports can be specified in the following ways:

  • Dynamic Imports - The DynamicImport-Package header is intended to look for an exported package when that package is needed. The key use case for dynamic import is the Class forName method when a bundle does not know in advance the class name it may be requested to load.

  • Resolution Directive - The resolution directive on an import definition specifying the value optional. A bundle may successfully resolve if a suitable optional package is not present.

The key difference between these two mechanisms is when the wires are made. An attempt is made to establish a wire for a dynamic import every time there is an attempt to load a class in that package, whereas the wire for a resolution optional package may only be established when the bundle is resolved.

The resolution directive of the import definition can take the value mandatory or optional.

  • mandatory - (Default) Indicates that the package must be wired for the bundle to resolve.

  • optional - Indicates that the importing bundle may resolve without the package being wired. If the package is not wired, the class loading will treat this package as if it is not imported.

The following example will resolve even though bundle B does not provide the correct version (the package will not be available to the code when bundle A is resolved).

A: Import-Package: p; «
        resolution:=optional; «
        version=1.6
B: Export-Package: p; «
        q; «
        version=1.5.0

Figure 3.10 Optional import

Optional import

The implementation of a bundle that uses optional packages must be prepared to handle the fact that the packages may not be available: that is, an exception can be thrown when there is a reference to a class from a missing package. This can be prevented by including a fallback package on the bundle's class path. When an optional package cannot be resolved, any attempts by the bundle to load classes from it will follow normal bundle class loading search order as if the import never existed. It will load it from the bundle's class path or in the end through dynamic class loading when set for that bundle and package.

3.7.6 Package Constraints

Classes can depend on classes in other packages. For example, when they extend classes from another package, or these other classes appear in method signatures. It can therefore be said that a package uses other packages. These inter-package dependencies are modeled with the uses directive on the Export-Package header.

For example, org.osgi.service.http depends on the package javax.servlet because it is used in the API. The export definition of the org.osgi.service.http must therefore contain the uses directive with the javax.servlet package as its value.

Class space consistency can only be ensured if a bundle has only one exporter for each package. For example, the Http Service implementation requires servlets to extend the javax.servlet.http.HttpServlet base class. If the Http Service bundle would import version 2.4 and the client bundle would import version 2.1 then a class cast exception is bound to happen. This is depicted in Figure 3.11.

Figure 3.11 Uses directive in B, forces A to use javax.servlet from D

Uses directive in B, forces A to use javax.servlet from D

If a bundle imports a package from an exporter then the export definition of that package can imply constraints on a number of other packages through the uses directive. The uses directive lists the packages that the exporter depends upon and therefore constrains the resolver for imports. These constraints ensure that a set of bundles share the same class loader for the same package.

When an importer imports a package with uses constraints, the resolver must wire the import to the exporter named in the uses constraint. This exporter may in turn imply additional constraints, and so on. The act of wiring a single import of a package to an exporter can therefore imply a large set of constraints. The term implied package constraints refers to the complete set of constraints constructed from recursively traversing the wires. Implied package constraints are not automatic imports; rather, implied package constraints only constrain how an import definition must be wired.

For example, in Figure 3.12, bundle A imports package p. Assume this import definition is wired to bundle B. Due to the uses directive (the ellipse symbols indicates the uses directive) this implies a constraint on package q.

Further, assuming that the import for package q is wired to bundle C, then this implies a constraint on the import of package r and s. Continuing, assuming C.s and C.r are wired to bundle D and E respectively. These bundles both add package t to the set of implied packages for bundle A.

Figure 3.12 Implied Packages

Implied Packages

To maintain class space consistency, the Framework must ensure that none of its bundle imports conflicts with any of that bundle's implied packages.

For the example, this means that the Framework must ensure that the import definition of A.t is wired to package D.t. Wiring this import definition to package F.t violates the class space consistency. This violation occurs because bundle A could be confronted with objects with the same class name but from the class loaders of bundle D and F. This would potentially create ClassCastExceptions. Alternatively, if all bundles are wired to F.t, then the problem also goes away.

Another scenario with this case is depicted in Figure 3.11. Bundle A imports the Http Service classes from bundle B. Bundle B has grouped the org.osgi.service.http and the javax.servlet and bundle A is therefore constrained to wire javax.servlet to the same exporter as bundle B.

As an example of a situation where the uses directive makes resolving impossible consider the following setup that is correctly resolved:

A: Import-Package: q; version="[1.0,1.0]"
   Export-Package: p; uses:="q,r",r
B: Export-Package: q; version=1.0
C: Export-Package: q; version=2.0

These specific constraints can be resolved because the import A.q can be wired to the export B.q but not C.q due to the version constraint.

Adding a bundle D will now not be possible:

D: Import-Package: p, q; version=2.0

Package D.p must be wired to package A.p because bundle A is the only exporter. However, this implies the use of package q due the uses directive in the package A.q import. Package A.q is wired to B.q-1.0. However, import package D.q requires version 2.0 and can therefore not be resolved without violating the class space constraint.

This scenario is depicted in Figure 3.13.

Figure 3.13 Uses directive and resolving

Uses directive and resolving

3.7.7 Attribute Matching

Attribute matching is a generic mechanism to allow the importer and exporter to influence the matching process in a declarative way. In order for an import definition to be resolved to an export definition, the values of the attributes specified by the import definition must match the values of the attributes of the export definition. By default, a match is not prevented if the export definition contains attributes that do not occur in the import definition. The mandatory directive in the export definition can reverse this by listing all attributes that the Framework must match in the import definition. Any attributes specified in the DynamicImport-Package is ignored during the resolve phase but can influence runtime class loading.

For example, the following statements will match.

A: Import-Package: com.acme.foo;company=ACME
B: Export-Package: com.acme.foo; «
          company="ACME"; «
          security=false

Attribute values are compared string wise except for the version and bundle-version attributes which use version range comparisons. Leading and trailing white space in attribute values must be ignored.

Attribute matching also works for the Require-Bundle and Fragment-Host headers; the attributes to be matched are specified on the Bundle-SymbolicName header.

3.7.8 Mandatory Attributes

There are two types of attributes: mandatory and optional. Mandatory attributes must be specified in the import definition to match. Optional attributes are ignored when they are not referenced by the importer. Attributes are optional by default.

The exporter can specify mandatory attributes with the mandatory directive in the export definition. This directive contains a comma-separated list of attribute names that must be specified by the importer to match.

For example, the following import definition must not match the export definition because security is a mandatory attribute:

A: Import-Package: com.acme.foo;company=ACME

B: Export-Package: com.acme.foo; «
          company="ACME"; «
          security=false; «
          mandatory:=security

3.7.9 Class Filtering

An exporter can limit the visibility of the classes in a package with the include and exclude directives on the export definition. The value of each of these directives is a comma-separated list of class names. Note that the use of a comma in the value requires it to be enclosed in double quotes.

Class names must not include their package name and do not end with .class. That is, the class com.acme.foo.Daffy is named Daffy in either list. The class name can include multiple wildcard asterisks ('*' \u002A).

The default for the include directive is an asterisk ('*' \u002A) (wildcard matching all names), and for the exclude directive, so that no classes are excluded, an empty list that matches no names. If include or exclude directive are specified, the corresponding default is overridden.

A class is only visible if it is:

  • Matched with an entry in the included list, and

  • Not matched with an entry in the excluded list.

In all other cases, loading or finding fails, and a Class Not Found Exception is thrown for a class load. The ordering of include and exclude is not significant.

The following example shows an export statement, and a list of files with their visibility status.

Export-Package: com.acme.foo; include:="Qux*,BarImpl"; «
        exclude:=QuxImpl

com/acme/foo               
   QuxFoo            visible
   QuxBar            visible
   QuxImpl           excluded
   BarImpl           visible

Care must be taken when using filters. For example, a new version of a module that is intended to be backward compatible with an earlier version should not filter out classes that were not filtered out by the earlier version. In addition, when modularizing existing code, filtering out classes from an exported package may break users of the package.

For example, packages defined by standard bodies often require an implementation class in the standardized package to have package access to the specification classes.

package org.acme.open;
public class Specified {
    static Specified implementation;
    public void foo() { implementation.foo(); }
}

package org.acme.open;
public class Implementation {
    public void initialize(Specified implementation) {
        Specified.implementation = implementation;
    }
}

The Implementation class must not be available to external bundles because it allows the implementation to be set. By excluding the Implementation class, only the exporting bundle can see this class. The export definition for this header could look like:

Export-Package: org.acme.open; exclude:=Implementation

3.7.10 Provider Selection

Provider selection allows the importer to select which bundles can be considered as exporters. Provider selection is used when there is no specification contract between the importer and the exporter. The importer tightly couples itself to a specific exporter, typically the bundle that was used for testing. To make the wiring less brittle, the importer can optionally specify a range of bundle versions that will match.

An importer can select an exporter with the import attributes bundle-symbolic-name and bundle-version. The Framework automatically provides these attributes for each export definition. These attributes must not be specified in an export definition.

The export definition bundle-symbolic-name attribute will contain the bundle symbolic name as specified in the Bundle-SymbolicName header without any parameters. The export definition bundle-version attribute is set to the value of the Bundle-Version header or its default of 0.0.0 when absent.

The bundle-symbolic-name is matched as an attribute. The bundle-version attribute is matched using the version range rules as defined in Version Ranges. The import definition must be a version range and the export definition is a version.

For example, the following definitions will match:

A: Bundle-SymbolicName: A
   Import-Package: com.acme.foo; «
        bundle-symbolic-name=B; «
        bundle-version="[1.41,2.0.0)"

B: Bundle-SymbolicName: B
   Bundle-Version: 1.41
   Export-Package: com.acme.foo

The following statements will not match because bundle B does not specify a version and thus defaults to 0.0.0:

A: Bundle-SymbolicName: A
   Import-Package: com.acme.foo; «
          bundle-symbolic-name=B; «
          bundle-version="[1.41,2.0.0)"

B: Bundle-SymbolicName: B
   Export-Package: com.acme.foo;version=1.42

Selecting an exporter by symbolic name can result in brittleness because of hard coupling of the package to the bundle. For example, if the exporter eventually needs to be refactored into multiple separate bundles, all importers must be changed. Other arbitrary matching attributes do not have this disadvantage as they can be specified independently of the exporting bundle.

The brittleness problem of the bundle symbolic name in bundle refactoring can be partly overcome by writing a façade bundle using the same bundle symbolic name as the original bundle.

3.8 Resolving Process

Resolving is the process that creates a wiring between bundles. Constraints on the wires are statically defined by:

  • Any mandatory requirement must be matched to at least one capability in the same namespace provided by any of the resolved bundles, including itself and the system bundle.

  • The required execution environments as defined by the Bundle-RequiredExecutionEnvironment header.

  • Native code

  • Import and export packages (the DynamicImport-Package header is ignored in this phase)

  • Required bundles, which import all exported packages from a bundle as defined in Requiring Bundles.

  • Fragments, which provide their contents and definitions to the host as defined in Fragment Bundles

A bundle can only be resolved when a number of constraints are satisfied:

  • Execution Environment - The underlying VM implements at least one of the execution environments listed in the Bundle-RequiredExecutionEnvironment header. See osgi.ee Namespace.

  • Native code - The native code dependencies specified in the Bundle-NativeCode header must be resolved. See Loading Native Code Libraries.

The resolving process is then a constraint-solving algorithm that can be described in terms of requirements on wiring relations. The resolving process is an iterative process that searches through the solution space.

A bundle can be resolved if the following conditions are met:

  • All its mandatory requirements are satisfied

  • All its mandatory imports are wired

  • All its mandatory required bundles are available and their exports wired

A wire is only created when the following conditions are met:

  • The importer's version range matches the exporter's version. See Semantic Versioning.

  • The importer specifies all mandatory attributes from the exporter. See Mandatory Attributes.

  • All the importer's attributes match the attributes of the corresponding exporter. See Attribute Matching

  • Implied packages referring to the same package as the wire are wired to the same exporter. See Package Constraints.

  • The wire is connected to a valid exporter.

The following list defines the preferences, if multiple choices are possible, in order of decreasing priority:

  • A resolved exporter must be preferred over an unresolved exporter.

  • An exporter with a higher version is preferred over an exporter with a lower version.

  • An exporter with a lower bundle ID is preferred over a bundle with a higher ID.

3.8.1 Importing and Exporting the Same Package

If a bundle has both import and export definitions for the same package, then the Framework needs to decide which to choose.

It must first try to resolve the overlapping import definition. The following outcomes are possible:

  • External - If this resolves to an export statement in another bundle, then the overlapping export definition in this bundle is discarded.

  • Internal - If it is resolved to an export statement in this bundle, then the overlapping import definition in this bundle is discarded.

  • Unresolved - There is no matching export definition. In this case the framework is free to discard either the overlapping export definition or overlapping import definition in this bundle. If the export definition is discarded and the import definition is not optional then the bundle will fail to resolve.

The above only applies to the import and export package definitions of a bundle. For namespaces other than osgi.wiring.package, a requirement definition of a bundle may be wired to a capability definition of that same bundle.

3.9 Runtime Class Loading

Each bundle installed in the Framework must not have an associated class loader until after it is resolved. After a bundle is resolved, the Framework must create one class loader for each bundle that is not a fragment. The framework may delay creation of the class loader until it is actually needed.

One class loader per bundle allows all resources within a bundle to have package level access to all other resources in the bundle within the same package. This class loader provides each bundle with its own namespace, to avoid name conflicts, and allows resource sharing with other bundles.

This class loader must use the wiring as calculated in the resolving process to find the appropriate exporters. If a class is not found in the imports, additional headers in the manifest can control the searching of classes and resources in additional places.

The following sections define the factors that influence the runtime class loading and then define the exact search order the Framework must follow when a class or resource is loaded.

3.9.1 Bundle Class Path

JAR, ZIP, directories, etc. are called containers. Containers contain entries organized in hierarchical paths. During runtime, an entry from a bundle can actually come from different containers because of attached fragments. The order in which an entry can be found is significant because it can shadow other entries. For a bundle, the search order for a named entry is:

  • First the container of the (host) bundle

  • Then the (optional) fragment containers in ascending id order

This search order is called the entry path. A resource (or class) is not loaded via the entry path, but it is loaded through the bundle class path. The bundle class path provides an additional indirection on top of the entry path. It defines an ordered list of container paths. Each container path can be found on the entry path.

Each container, independent of any other containers, can be a multi-release container. See Multi-release Container.

The full stop ('.' \u002E) container path is a synonym for the solidus ('/' \u002F) or the root of a container. The full stop is the default value for a bundle or fragment if no Bundle-ClassPath header is specified.

The Bundle-ClassPath manifest header must conform to the following syntax:

Bundle-ClassPath ::= entry ( ',' entry )*
entry            ::= target ( ';' target )* ( ';' parameter ) *
target           ::= path | '.'     // See 1.3.2

The Framework must ignore any unrecognized parameters.

The content of the effective bundle class path is constructed from the bundle's Bundle-ClassPath header, concatenated with the Bundle-ClassPath headers of any fragments, in ascending bundle id order. The effective Bundle-ClassPath is calculated during resolve time, however, a dynamically attached fragment can append elements at the end if the Framework supports dynamically attached fragments.

An element from the bundle's Bundle-ClassPath header refers to the first match when searched through the entry path, while a fragment's Bundle-ClassPath can refer only to an entry in its own container.

An example can illustrate this:

A: Bundle-ClassPath: .,resource.jar
B: Fragment-Host: A

The previous example uses an effective bundle class path of:

/, resource.jar, B:/

The first element / is the root of a container. The bundle always has a root and can therefore always be found in the (host) bundle. The second element is first looked up in the host bundle's container, and if not found, the entry is looked up in the container of B. The Framework must use the first entry that matches. The last element in the effective bundle class path is the / from fragment B; the / is the default because there is no Bundle-ClassPath specified. However, a fragment can only refer to an internal entry. This full stop therefore refers to the root of the container of fragment B. Assuming, fragment B contains an entry for resource.jar and bundle A does not, then the search order must be:

A:/
B:resource.jar
B:/

The Framework must ignore a container path in the bundle class-path if the container cannot be located when it is needed, which can happen at any time after the bundle is resolved. However, the Framework should publish a Framework Event of type INFO once with an appropriate message for each entry that cannot be located at all.

An entry on the Bundle-ClassPath can refer to a directory in the container. However, it is not always possible to establish the directory's existence. For example, directories can be omitted in JAR/ZIP files. In such a case, a Framework must probe the directory to see if any resources can be found in this directory. That is, even if the directory construct is absent in the container, if resources can be found assuming this directory, than it must still be chosen for the Bundle-ClassPath.

A host bundle can allow a fragment to insert code ahead of its own code by naming a container in its Bundle-ClassPath that will be provided by a fragment. Fragments can never unilaterally insert code ahead of their host's bundle class path. The following example illustrates the possibilities of the bundle class path in more detail:

A: Bundle-SymbolicName: A
   Bundle-ClassPath: /,required.jar,optional,default.jar
   content ...
   required.jar
   default.jar
B: Bundle-SymbolicName: B
   Bundle-ClassPath: fragment.jar
   Fragment-Host: A
   content ...
   optional/
            content ...
   fragment.jar

The names of the bundle class path elements indicate their intention. The required.jar is a container that provides mandatory functionality, it is packaged in bundle A. The optional container is a directory containing optional classes, and the default.jar is a JAR entry with backup code. In this example, the effective bundle class path is:

A:/
A:required.jar
B:optional
A:default.jar
B:fragment.jar

This will expand to the following (logical) search order for a resource X.class:

    A:/X.class
    A:required.jar!X.class
    B:optional/X.class
    A:default.jar!X.class
    B:fragment.jar!X.class

The exclamation mark (!) indicates a load from a JAR resource.

3.9.1.1 Multi-release Container

A container can be a multi-release container . A multi-release container supports versioned directories as specified in [28] Multi-release JAR File. When a container is a multi-release container, that is, the container has a META-INF/MANIFEST.MF manifest which specifies

Multi-Release: true

then the Framework must search the container's versioned directories when attempting to locate an entry in the container.

Support for multi-release containers must only be active on Java 9 and later. On Java 8 and earlier, the container must be treated as a non-multi-release container.

3.9.2 Dynamic Import Package

Dynamic imports are matched to export definitions (to form package wirings) during class loading, and therefore do not affect module resolution. Dynamic imports apply only to packages for which no wire has been established and no definition could be found in any other way. Dynamic import is used as a last resort.

DynamicImport-Package ::= dynamic-description 
           ( ',' dynamic-description )*
dynamic-description ::= wildcard-names ( ';' parameter )*
wildcard-names      ::= wildcard-name ( ';' wildcard-name )*
wildcard-name       ::= package-name 
            | ( package-name '.*' )   // See 1.3.2
            | '*' 

No directives are architected by the Framework for DynamicImport-Package. Arbitrary matching attributes may be specified. The following matching attributes are architected by the Framework:

  • version -- A version range to select the version of an export definition. The default value is 0.0.0 .

  • bundle-symbolic-name - The bundle symbolic name of the exporting bundle.

  • bundle-version - a version range to select the bundle version of the exporting bundle. The default value is 0.0.0.

Packages may be named explicitly or by using wild-carded expressions such as org.foo.* and *. The wildcard can stand for any suffix, including multiple sub-packages. If a wildcard is used, then the package identified by the prefix must not be included. That is, org.foo.* will include all sub-packages of org.foo but it must not include package org.foo itself.

Dynamic imports must be searched in the order in which they are specified. The order is particularly important when package names with wildcards are used. The order will then determine the order in which matching occurs. This means that the more specific package specifications should appear before the broader specifications. For example, the following DynamicImport-Package header indicates a preference for packages supplied by ACME:

DynamicImport-Package: *;vendor=acme, *

If multiple packages need to be dynamically imported with identical parameters, the syntax permits a list of packages, separated by semicolons, to be specified before the parameters.

During class loading, the package of the class being loaded is compared against the specified list of (possibly wild-carded) package names. Each matching package name is used in turn to attempt to wire to an export using the same rules as Import-Package. If a wiring attempt is successful (taking any uses constraints into account), the search is forwarded to the exporter's class loader where class loading continues. The wiring must not subsequently be modified, even if the class cannot be loaded. This implies that once a package is dynamically resolved, subsequent attempts to load classes or resources from that package are treated as normal imports.

In order for a DynamicImport-Package to be resolved to an export statement, all attributes of the dynamic import definition must match the attributes of the export statement. All mandatory arbitrary attributes (as specified by the exporter, see Mandatory Attributes ) must be specified in the dynamic import definition and match.

Once a wire is established, any uses constraints from the exporter must be obeyed for further dynamic imports.

Dynamic imports are very similar to optional packages, see Optional Packages, but differ in the fact that they are handled after the bundle is resolved.

3.9.3 Parent Delegation

The Framework must always delegate any package that starts with java. to the parent class loader.

Certain Java virtual machines, also Oracle's VMs, appear to make the erroneous assumption that the delegation to the parent class loader always occurs. This implicit assumption of strictly hierarchical class loader delegation can result in NoClassDefFoundErrors. This happens if the virtual machine implementation expects to find its own implementation classes from any arbitrary class loader, requiring that packages loaded from the boot class loader not be restricted to only the java.* packages.

Other packages that must be loaded from the boot class loader can therefore be specified with the System property:

org.osgi.framework.bootdelegation

This property must contain a list with the following format:

org.osgi.framework.bootdelegation ::= boot-description 
            ( ',' boot-description )*
boot-description    ::= package-name        // See 1.3.2
            | ( package-name '.*' )           
            | '*' 

The .* wildcard means deep matching, that is, com.acme.*, matches any sub-package of package com.acme, however, it does not match com.acme. Packages that match this list must be loaded from the parent class loader. The java.* prefix is always implied; it does not have to be specified.

The single wildcard means that the Framework must always delegate to the parent class loader first, which is the same as the Release 3 behavior. For example, when running on an Oracle JVM, it may be necessary to specify a value like:

org.osgi.framework.bootdelegation=sun.*,com.sun.*

With such a property value, the Framework must delegate all java.*, sun.*, and com.sun.* packages to the parent class loader.

3.9.4 Overall Search Order

Frameworks must adhere to the following rules for class or resource loading. When a bundle's class loader is requested to load a class or find a resource, the search must be performed in the following order:

  1. If the class or resource is in a java.* package, the request is delegated to the parent class loader; otherwise, the search continues with the next step. If the request is delegated to the parent class loader and the class or resource is not found, then the search terminates and the request fails.

  2. If the class or resource is from a package included in the boot delegation list (org.osgi.framework.bootdelegation), then the request is delegated to the parent class loader. If the class or resource is found there, the search ends.

  3. If the class or resource is in a package that is imported using Import-Package or was imported dynamically in a previous load, then the request is delegated to the exporting bundle's class loader; otherwise the search continues with the next step. If the request is delegated to an exporting class loader and the class or resource is not found, then the search terminates and the request fails.

  4. If the class or resource is in a package that is imported from one or more other bundles using Require-Bundle, the request is delegated to the class loaders of the other bundles, in the order in which they are specified in this bundle's manifest. This entails a depth-first strategy; all required bundles are searched before the bundle class path is used. If the class or resource is not found, then the search continues with the next step.

  5. Search the bundle's embedded class path, see Bundle Class Path. If the class or resource is not found, then continue with the next step.

  6. If the class or resource is in a package that is exported by the bundle or the package is imported by the bundle (using Import-Package or Require-Bundle), then the search ends and the class or resource is not found.

  7. Otherwise, if the class or resource is in a package that is imported using DynamicImport-Package, then a dynamic import of the package is now attempted. An exporter must conform to any implied package constraints. If an appropriate exporter is found, a wire is established so that future loads of the package are handled in step 3. If a dynamic wire is not established, then the request fails.

  8. If the dynamic import of the package is established, the request is delegated to the exporting bundle's class loader. If the request is delegated to an exporting class loader and the class or resource is not found, then the search terminates and the request fails.

When delegating to another bundle class loader, the delegated request enters this algorithm at step 4.

The following non-normative flow chart illustrates the search order described above:

Figure 3.14 Flow chart for class loading (non-normative)

Flow chart for class loading (non-normative)

3.9.5 Parent Class Loader

The set of implicitly visible packages are all java.* packages, since these packages are required by the Java runtime, and using multiple versions at the same time is not easy. For example, all objects must extend the same Object class.

A bundle must not declare exports for java.* packages; doing so is an error and any such bundle must fail to install or update. A bundle may declare imports for java.* packages; but this is for resolution purposes only. All other packages visible through the parent class loader must be hidden from executing bundles.

However, the Framework must explicitly export relevant packages from the parent class loader. The system property

org.osgi.framework.system.packages 

contains the export packages descriptions for the system bundle. This property employs the standard Export-Package manifest header syntax:

org.osgi.framework.system.packages ::= package-description
                                       ( ',' package-description )*

Some classes on the boot class path assume that they can use any class loader to load other classes on the boot class path, which is not true for a bundle class loader. Framework implementations should attempt to load these classes from the boot class path.

The system bundle (bundle ID zero) is used to export non-java.* packages from the parent class loader. Export definitions from the system bundle are treated like normal exports, meaning that they can have version numbers, and are used to resolve import definitions as part of the normal bundle resolving process. Other bundles may provide alternative implementations of the same packages.

The set of export definitions for the parent class loader can either be set by this property or calculated by the Framework. The export definitions must have the bundle-symbolic-name and bundle-version attributes with the implementation-specific bundle symbolic name and bundle version value of the system bundle.

Exposing packages from the parent class loader in this fashion must also take into account any uses directives of the underlying packages. For example, the definition of javax.crypto.spec must declare its usage of javax.crypto.interfaces and javax.crypto.

3.9.6 Resource Loading

A resource in a bundle can be accessed through the class loader of that bundle but it can also be accessed with the getResource(String), getEntry(String), findEntries(String,String,boolean) and other methods or the methods on the Bundle Wiring API Specification. All these methods return a URL object or an Enumeration object of URL objects. The URLs are called bundle entry URLs. The schemes for the URLs returned by these methods can differ and are implementation dependent.

Bundle entry URLs are normally created by the Framework, however, in certain cases bundles need to manipulate the URL to find related resources. The Framework is therefore required to ensure that:

  • Bundle entry URLs must be hierarchical (See [13] RFC 2396 Uniform Resource Identifiers URI: Generic Syntax )

  • Usable as a context for constructing another URL.

  • The java.net.URLStreamHandler class used for a bundle entry URL must be available to the java.net.URL class to setup a URL that uses the protocol scheme defined by the Framework.

  • The getPath method for a bundle entry URL must return an absolute path (a path that starts with '/') to a resource or entry in a bundle. For example, the URL returned from getEntry("myimages/test.gif") must have a path of /myimages/test.gif.

For example, a class can take a URL to an index.html bundle resource and map URLs in this resource to other files in the same JAR directory.

public class BundleResource implements HttpContext{
    URL  root;  // to index.html in bundle
    URL getResource( String resource ) {
        return new URL( root, resource );
    }
    ...
}

3.9.7 Bundle Cycles

Multiple required bundles can export the same package. Bundles which export the same package involved in a require bundle cycle can lead to lookup cycles when searching for classes and resources from the package. Consider the following definitions:

A: Require-Bundle: B, C
C: Require-Bundle: D

These definitions are depicted in Figure 3.15.

Figure 3.15 Depth First search with Require Bundle

Depth First search with Require Bundle

Each of the bundles exports the package p. In this example, bundle A requires bundle B, and bundle C requires bundle D. When bundle A loads a class or resource from package p, then the required bundle search order is the following: B, D, C, A. This is a depth first search order because required bundles are searched before the bundle class path is searched (see step 4 ). The required bundles are searched in the order that they appear in the Require-Bundle header. The depth first search order can introduce endless search cycles if the dependency graph has a cycle in it.

Using the previous setup, a cycle can be introduced if bundle D requires bundle A as depicted in Figure 3.16.

D: Require-Bundle: A

Figure 3.16 Cycles

Cycles

When the class loader for bundle A loads a class or resource from package p then the bundle search order would be the following: B, B, B,... if cycles were not taken into account.

Since a cycle was introduced each time bundle D is reached the search will recurs back to A and start over. The framework must prevent such dependency cycles from causing endless recursive lookups.

To avoid endless looping, the Framework must mark each bundle upon first visiting it and not explore the required bundles of a previously visited bundle. Using the visited pattern on the dependency graph above will result in the following bundle search order: B, D, C, A.

3.9.8 Code Executed Before Started

Packages exported from a bundle are exposed to other bundles as soon as the bundle has been resolved. This condition could mean that another bundle could call methods in an exported package before the bundle exporting the package is started.

3.9.9 Finding an Object's Bundle

There are scenarios where a bundle is required in code that has no access to a Bundle Context. For this reason, the framework provides the following methods:

  • Framework Util - Through the FrameworkUtil class with the getBundle(Class) method. The framework provides this method to allow code to find the bundle of an object without having the permission to get the class loader. The method returns null when the class does not originate from a bundle.

  • Class Loader - An OSGi framework must ensure that the class loader of a class that comes from a bundle implements the BundleReference interface. This allows legacy code to find an object's bundle by getting its class loader and casting it to a BundleReference object, which provides access to the Bundle. However, this requires the code to have the permission to access the class loader. The following code fragment shows how to obtain a Bundle object from any object.


ClassLoader cl = target.getClassLoader();
if ( cl instanceof BundleReference ) {
    BundleReference ref = (BundleReference) cl;
    Bundle b = ref.getBundle();
    ...
}

In an OSGi system, not all objects belong to the framework. It is therefore possible to get hold of a class loader that does not implement the BundleReference interface, for example the boot class path loader.

3.10 Loading Native Code Libraries

Dependency on native code is expressed in the Bundle-NativeCode header. The framework must verify this header and satisfy its dependencies before it attempts to resolve the bundle. However, a bundle can be installed without an exception if the header is properly formatted according to its syntax. If the header contains invalid information, or can not be satisfied, errors will be reported during resolving.

A Java VM has a special way of handling native code. When a class loaded by a bundle's class loader attempts to load a native library, by calling System.loadLibrary, the findLibrary method of the bundle's class loader must be called to return the file path in which the Framework has made the requested native library available. The parameter to the findLibrary method is the name of the library in operating system independent form, like http. The bundle class loader can use the mapLibraryName method from the VM to map this name to an operating system dependent name, like libhttp.so.

The bundle's class loader must attempt to find the native library by examining the selected native code clauses, if any, of the bundle associated with the class loader and each attached fragment. Fragments are examined in ascending bundle ID order. If the library is not referenced in any of the selected native code clauses then null must be returned which allows the parent class loader to search for the native library.

The bundle must have the required RuntimePermission[loadLibrary. < library name>] in order to load native code in the OSGi framework.

The Bundle-NativeCode manifest header must conform to the following syntax:

Bundle-NativeCode   ::= nativecode 
        ( ',' nativecode )* ( ',' optional ) ?
nativecode          ::= path ( ';' path )*    // See 1.3.2
                        ( ';' parameter )*
optional            ::= '*'

When locating a path in a bundle the Framework must attempt to locate the path relative to the root of the bundle that contains the corresponding native code clause in its manifest header.

The following attributes are architected:

  • osname - Name of the operating system. The value of this attribute must be the name of the operating system upon which the native libraries run. A number of canonical names are defined in Table 4.3.

  • osversion - The operating system version. The value of this attribute must be a version range as defined in Version Ranges.

  • processor - The processor architecture. The value of this attribute must be the name of the processor architecture upon which the native libraries run. A number of canonical names are defined in Table 4.2.

  • language - The ISO code for a language. The value of this attribute must be the name of the language for which the native libraries have been localized.

  • selection-filter - A selection filter. The value of this attribute must be a filter expression that indicates if the native code clause should be selected or not.

If a selection-filter attribute contains an invalid filter, then the bundle must fail to install with a Bundle Exception of type NATIVECODE_ERROR. The following is a typical example of a native code declaration in a bundle's manifest:

Bundle-NativeCode: lib/http.dll ; lib/zlib.dll; «
        osname = Windows95 ; «
        osname = Windows98 ; «
        osname = WindowsNT ; «
        processor = x86 ; «
        selection-filter = «
            "(com.acme.windowing=win32)"; «
        language = en ; «
        language = se , «
    lib/solaris/libhttp.so ; «
        osname = Solaris ; «
        osname = SunOS ; «
        processor = sparc, «
    lib/linux/libhttp.so ; «
        osname = Linux ; «
        processor = mips; «
        selection-filter = «
            "(com.acme.windowing=gtk)"

If multiple native code libraries need to be installed on one platform, they must all be specified in the same clause for that platform.

If a Bundle-NativeCode clause contains duplicate parameter entries, the corresponding values must be OR'ed together. This feature must be carefully used because the result is not always obvious. This is highlighted by the following example:

// The effect of this header has probably 
// not the intended effect!
Bundle-NativeCode: lib/http.DLL ; «
    osname = Windows95 ; «
    osversion = "3.1" ; «
    osname = WindowsXP ; «
    osversion = "5.1" ; «
    processor = x86

The above example implies that the native library will load on Windows XP 3.1 and later, which was probably not intended. The single clause should be split in two clauses:

Bundle-NativeCode: lib/http.DLL ; «
        osname = Windows95 ; «
        osversion = 3.1; «
        processor = x86, «
    lib/http.DLL ; «
        osname = WindowsXP ; «
        osversion = 5.1; «
        processor = x86

Any paths specified in the matching clause must be present in the bundle or any of its attached fragments for a bundle to resolve. The framework must report a Bundle Exception with the NATIVECODE_ERROR as error code when the bundle can not be resolved due to a native code problem.

If the optional '*' is specified at the end of the Bundle-NativeCode manifest header, the bundle will still resolve even if the Bundle-NativeCode header has no matching clauses.

The following is a typical example of a native code declaration in a bundle's manifest with an optional clause:

Bundle-NativeCode: lib/win32/winxp/optimized.dll; «
        lib/win32/native.dll ; «
        osname = WindowsXP ; «
        processor = x86 , «
    lib/win32/native.dll ; «
        osname = Windows95 ; «
        osname = Windows98 ; «
        osname = WindowsNT ; «
        osname = Windows2000; «
        processor = x86 , «
        *

Frameworks must convert a Bundle-NativeCode header to a requirement in the osgi.native namespace when used in the Wiring API, see Bundle Wiring API Specification. Each native code clause specified in a Bundle-NativeCode header is converted into a filter component for the osgi.native requirement filter directive using the following architected matching attributes:

  • osgi.native.osname - Uses the approximate equals (~=) filter type to evaluate the value specified by the osname Bundle-NativeCode attribute.

  • osgi.native.osversion - Create a VersionRange using the value specified by the osversion Bundle-NativeCode attribute and then create a filter string out of the VersionRange.

  • osgi.native.processor - Uses the approximate equals (~=) filter type to evaluate the value specified by the processor Bundle-NativeCode attribute.

  • osgi.native.language - Uses the approximate equals (~=) filter type to evaluate the value specified by the language Bundle-NativeCode attribute.

In cases where the same Bundle-NativeCode attribute is specified multiple times within the same clause then the filter components for each value for that attribute are ORed together. For example, if osname attribute is specified as both "Windows95" and "Windows7" then the resulting filter will contain:

(|
        (osgi.native.osname~=Windows95)
        (osgi.native.osname~=Windows7)
)

If the selection-filter Bundle-NativeCode attribute is specified then the specified filter is included as a component of the native code clauses AND filter type. Consider the following Bundle-NativeCode header which contains a single clause:

Bundle-NativeCode: «
      lib/http.dll; lib/zlib.dll; «
      osname=Windows95; «
      osname=Windows98; «
      osname=WindowsNT; «
      processor=x86; «
      selection-filter="(com.acme.windowing=win32)";  «
      language=en; «
      language=se

This clause would get translated into the following AND filter type:

Require-Capability: «
      osgi.native; «
      filter:=" «
        (& «
          (| «
            (osgi.native.osname~=Windows95) «
            (osgi.native.osname~=Windows98) «
            (osgi.native.osname~=WindowsNT) «
          ) «
          (osgi.native.processor~=x86) «
          (| «
            (osgi.native.language~=en) «
            (osgi.native.language~=se) «
          ) «
          (com.acme.windowing=win32) «
        )"

The Bundle-NativeCode header may specify multiple clauses, each having their own list of native code paths and set of matching attributes. Instead of using a separate osgi.native requirement for each Bundle-NativeCode clause, the complete Bundle-NativeCode header is specified as a single osgi.native requirement. This is done by using an OR filter type using all of the individual Bundle-NativeCode clause filter components (as specified above) as components of a single filter directive. Consider the following Bundle-NativeCode header which contains three clauses:

Bundle-NativeCode: «
      lib/http.dll; lib/zlib.dll; «
        osname=Windows95; «
        osname=Windows98; «
        osname=WindowsNT; «
        processor=x86; «
        selection-filter = "(com.acme.windowing=win32)"; «
        language=en; «
        language=se, «
      lib/solaris/libhttp.so; «
        osname=Solaris; «
        osname=SunOS; «
        processor=sparc, «
      lib/linux/libhttp.so; «
        osname=Linux; «
        processor=mips; «
        selection-filter="(com.acme.windowing=gtk)"

This Bundle-NativeCode header would get translated into the following osgi.native filter directive:

(|
  (&
    (|
      (osgi.native.osname~=Windows95)
      (osgi.native.osname~=Windows98)
      (osgi.native.osname~=WindowsNT)
    )
    (osgi.native.processor~=x86)
    (|
      (osgi.native.language~=en)
      (osgi.native.language~=se)
    )
    (com.acme.windowing=win32)
  )
  (&
    (|
      (osgi.native.osname~=Solaris)
      (osgi.native.osname~=SunOs)
    )
    (osgi.native.processor~=sparc)
  )
  (&
    (osgi.native.osname~=Linux)
    (osgi.native.processor~=mips)
    (com.acme.windowing=gtk)
  )
)

If the optional '*' is specified at the end of the Bundle-NativeCode manifest header, then the native code for the bundle is considered to be optional. When the Framework converts a Bundle-NativeCode header into an osgi.native requirement which is designated as optional then the requirement resolution directive must be set to optional

3.10.1 Native Code Algorithm

In the description of this algorithm, [x] represents the value of the launching property x (see Launching Properties) and ~= represents the match operation. The match operation is a case insensitive comparison. Certain properties can be aliased. In those cases, the manifest header should contain the generic name for that property but the Framework should attempt to include aliases when it matches.

The Framework must select the native code clause using the following algorithm:

  1. Only select the native code clauses for which the following expressions all evaluate to true.

    • osname ~= [org.osgi.framework.os.name] or osname is not specified

    • processor ~= [org.osgi.framework.processor] or processor is not specified

    • osversion range includes [org.osgi.framework.os.version] or osversion is not specified

    • language ~= [org.osgi.framework.language] or language is not specified

    • selection-filter evaluates to true when using the values of the launching properties or selection-filter is not specified

  2. If no native clauses were selected in step 1, this algorithm is terminated. A Bundle Exception is thrown if the optional clause is not present.

  3. The selected clauses are now sorted in the following priority order:

    • osversion: floor of the osversion range in descending order, osversion not specified

    • language: language specified, language not specified

    • Position in the Bundle-NativeCode manifest header: lexical left to right.

  4. The first clause of the sorted clauses from step 3 must be used as the selected native code clause.

If a native code library in a selected native code clause cannot be found within the bundle then the bundle is still allowed to resolve. A missing native code library will result in an error being thrown at runtime when the bundle attempts to load the native code (for example, by invoking the method System.loadLibrary).

If the selected clause contains multiple libraries with the same base file name then only the lexically left most library with that base file name will be used. For example, if the selected clause contains the libraries lib1/http.dll; lib2/http.dll; lib3/foo.dll; a/b/c/http.dll then only http.dll in lib1 and foo.dll will be used.

Designing a bundle native code header can become quickly complicated when different operating systems, libraries, and languages are used. The best practice for designing the header is to place all parameters in a table. Every targeted environment is then a row in that table. See Table 3.2 for an example.

Table 3.2 Native code table

Libraries osname osversion processor language filter

nativecodewin32.dll, delta.dll

win32

x86

en

nativecodegtk.so

linux

x86

en

(com.acme.windowing=gtk)

nativecodeqt.so

linux

x86

en

(com.acme.windowing=qt)


This table makes it easier to detect missing combinations. This table is then mapped to the Bundle-NativeCode header in the following code example.

Bundle-NativeCode:  nativecodewin32.dll; «
        delta.dll; «
        osname=win32; «
        processor=x86; «
        language=en, «
    nativecodegtk.so; «
        osname=linux; «
        processor=x86; «
        language=en; «
        selection-filter= «
            "(com.acme.windowing=gtk)", «
    nativecodeqt.so; «
        osname=linux; «
        processor=x86; «
        language=en; «
        selection-filter = «
            "(com.acme.windowing=qt)"

3.10.2 Considerations Using Native Libraries

There are some restrictions on loading native libraries due to the nature of class loaders. In order to preserve namespace separation in class loaders, only one class loader can load a native library as specified by an absolute path. Loading of a native library file by multiple class loaders (from multiple bundles, for example) will result in a linkage error.

Care should be taken to use multiple libraries with the same file name but in a different directory in the JAR. For example, foo/http.dll and bar/http.dll. The Framework must only use the first library and ignore later defined libraries with the same name. In the example, only foo/http.dll will be visible.

A native library is unloaded only when the class loader that loaded it has been garbage collected.

When a bundle is uninstalled or updated, any native libraries loaded by the bundle remain in memory until the bundle's class loader is garbage collected. The garbage collection will not happen until all references to objects in the bundle have been garbage collected, and all bundles importing packages from the updated or uninstalled bundle are refreshed. This implies that native libraries loaded from the system class loader always remain in memory because the system class loader is never garbage collected.

It is not uncommon that native code libraries have dependencies on other native code libraries. This specification does not support these dependencies, it is assumed that native libraries delivered in bundles should not rely on other native libraries.

3.11 Localization

A bundle contains a significant amount of information that is human-readable. Some of this information may require different translations depending on the user's language, country, and any special variant preferences, a.k.a. the locale. This section describes how a bundle can provide common translations for the manifest and other configuration resources depending on a locale.

Bundle localization entries share a common base name. To find a potential localization entry, an underscore ('_' \u005F) is added plus a number of suffixes, separated by another underscore, and finally appended with the suffix .properties . The suffixes are defined in java.util.Locale. The order for the suffixes this must be:

  • language

  • country

  • variant

For example, the following files provide manifest translations for English, Dutch (Belgium and the Netherlands) and Swedish.

OSGI-INF/l10n/bundle_en.properties
OSGI-INF/l10n/bundle_nl_BE.properties
OSGI-INF/l10n/bundle_nl_NL.properties
OSGI-INF/l10n/bundle_sv.properties

The Framework searches for localization entries by appending suffixes to the localization base name according to a specified locale and finally appending the .properties suffix. If a translation is not found, the locale must be made more generic by first removing the variant, then the country and finally the language until an entry is found that contains a valid translation. For example, looking up a translation for the locale en_GB_welsh will search in the following order:

OSGI-INF/l10n/bundle_en_GB_welsh.properties
OSGI-INF/l10n/bundle_en_GB.properties
OSGI-INF/l10n/bundle_en.properties
OSGI-INF/l10n/bundle.properties

This allows localization files for more specific locales to override localizations from less specific localization files.

3.11.1 Finding Localization Entries

Localization entries can be contained in the bundle or delivered in fragments. The framework must search for localization entries using the following search rules based on the bundle type:

  • fragment bundle - If the bundle is a resolved fragment, then the search for localization data must delegate to the attached host bundle with the highest version. If the fragment is not resolved, then the framework must search the fragment's JAR for the localization entry.

  • other bundle - The framework must first search in the bundle's JAR for the localization entry. If the entry is not found and the bundle has fragments, then the attached fragment JARs must be searched for the localization entry.

The bundle's class loader is not used to search for localization entries. Only the contents of the bundle and its attached fragments are searched. The bundle will still be searched for localization entries even if the full stop ('.' \u002E) is not in the bundle class path.

3.11.2 Manifest Localization

Localized values are stored in property resources within the bundle. The default base name of the bundle localization property files is OSGI-INF/l10n/bundle. The Bundle-Localization manifest header can be used to override the default base name for the localization files. This location is relative to the root of the bundle and bundle fragments.

A localization entry contains key/value entries for localized information. All headers in a bundle's manifest can be localized. However, the Framework must always use the non-localized versions of headers that have Framework semantics.

A localization key can be specified as the value of a bundle's manifest header using the following syntax:

header-value ::= '%'text
text ::= < any value which is both a valid manifest headervalue
   and a valid property key name >

For example, consider the following bundle manifest entries:

Bundle-Name: %acme bundle
Bundle-Vendor: %acme corporation
Bundle-Description: %acme description
Bundle-Activator: com.acme.bundle.Activator
Acme-Defined-Header: %acme special header

User-defined headers can also be localized. Spaces in the localization keys are explicitly allowed.

The previous example manifest entries could be localized by the following entries in the manifest localization entry OSGI-INF/l10n/bundle.properties.

# bundle.properties
acme\ bundle=The ACME Bundle
acme\ corporation=The ACME Corporation
acme\ description=The ACME Bundle provides all of the ACME\ services
acme\ special\ header=user-defined Acme Data

The above manifest entries could also have French localizations in the manifest localization entry OSGI-INF/l10n/bundle_fr_FR.properties.

3.12 Bundle Validity

If the Bundle-ManifestVersion is not specified, then the bundle manifest version defaults to 1, and certain Release 4 syntax, such as a new manifest header, is ignored rather than causing an error. Release 3 bundles must be treated according to the Release 3 specification.

The following (non-exhaustive) list of errors causes a bundle to fail to install:

  • Missing Bundle-SymbolicName.

  • Duplicate attribute or duplicate directive (except in the Bundle-Native code clause).

  • Multiple imports of a given package.

  • Export of java.* packages.

  • Export-Package, Bundle-SymbolicName, or Fragment-Host with a mandatory attribute that is not defined.

  • Installing or updating a bundle to a bundle that has the same symbolic name and version as another installed bundle (unless this is allowed, see Bundle Identifiers).

  • Any syntactic error (for example, improperly formatted version or bundle symbolic name, unrecognized directive value, etc.).

  • Specification-version and version specified together (for the same package(s)) but with different values on manifest headers that treat them as synonyms. For example:

        Import-Package p;specification-version=1;version=2

    would fail to install, but:

        Import-Package p;specification-version=1,q;version=2

    would not be an error.

  • The manifest lists a OSGI-INF/permissions.perm file but no such file is present.

  • Bundle-ManifestVersion value not equal to 2, unless the Framework specifically recognizes the semantics of a later release.

  • Requiring the same bundle symbolic name more than once.

3.13 Requiring Bundles

The Framework supports a mechanism where bundles can be directly wired to other bundles. The following sections define the relevant headers and then discuss the possible scenarios. At the end, some of the (sometimes unexpected) consequences of using Require-Bundle are discussed.

3.13.1 Require-Bundle

The Require-Bundle manifest header contains a list of required bundle symbolic names, with optional attribute assertions. These bundles are searched after the imports are searched but before the bundle's class path is searched. Fragment or extension bundles cannot be required.

The framework must take all exported packages from a required bundle, including any packages exported by attached fragments, and wire these packages to the requiring bundle.

The Require-Bundle manifest header must conform to the following syntax:

Require-Bundle      ::= bundle-description 
    ( ',' bundle-description )*
bundle-description  ::= symbolic-name       // See 1.3.2
    (';' parameter )*

The following directives can be used in the Require-Bundle header:

  • visibility - If the value is private (default), then all visible packages from the required bundles are not re-exported. If the value is reexport then bundles that require this bundle will transitively have access to these required bundle's exported packages. That is, if bundle A requires bundle B, and bundle B requires bundle C with visibility:=reexport then bundle A will have access to all bundle C's exported packages as if bundle A had required bundle C.

  • resolution - If the value is mandatory (default) then the required bundle must exist for this bundle to resolve. If the value is optional, the bundle will resolve even if the required bundle does not exist.

The following matching attribute is architected by the Framework:

  • bundle-version - The value of this attribute is a version range to select the bundle version of the required bundle. See Version Ranges. The default value is [0.0.0,).

The Bundle-SymbolicName header can specify further arbitrary attributes that must be matched before a bundle is eligible.

A specific symbolic name can only be required once, listing the same symbolic name multiple times must be regarded as an install error.

Requiring bundles must get wired to all exported packages of all their required bundles including exported packages from their attached fragments. This means that any mandatory attributes on these exports must be ignored. However, if a required bundle's exported package is substituted for an imported package, then the requiring bundles must get wired to the same exported package that the required bundle is wired to ensure class space consistency.

For example, assume that bundle A exports and imports package p and bundle B requires bundle A:

Bundle A
Export-Package: p;x=1;mandatory:=x
Import-Package: p

Bundle B
Require-Bundle: A

In this constellation, bundle B will get package p from the same source as bundle A. Bundle A can get the package from itself if it is chosen as an exporter for p, but it can also get the package from another bundle because it also imports it. In all cases, bundle B must use exactly the same exporter for package p as bundle A.

A given package may be available from more than one of the required bundles. Such packages are named split packages because they derive their contents from different bundles. If these different bundles provide the same classes unpredictable shadowing of classes can arise, see Issues With Requiring Bundles. However, split packages without shadowing are explicitly permitted.

For example, take the following setup:

A:  Require-Bundle: B
    Export-Package: p
B:  Export-Package: p;partial=true;mandatory:=partial

If bundle C imports package p, it will be wired to package A.p, however the contents will come from B.p > A.p. The mandatory attribute on bundle B's export definition ensures that bundle B is not accidentally selected as exporter for package p. Split packages have a number drawbacks that are discussed in Issues With Requiring Bundles.

Resources and classes from a split package must be searched in the order in which the required bundles are specified in the Require-Bundle header.

As an example, assume that a bundle requires a number of required bundles and a number of language resources (also bundles) that are optional.

Require-Bundle: com.acme.facade;visibility:=reexport, «
 com.acme.bar.one;visibility:=reexport, «
 com.acme.bar.two;visibility:=reexport, «
 com.acme.bar._nl;visibility:=reexport;resolution:=optional, «
 com.acme.bar._en;visibility:=reexport;resolution:=optional

A bundle may both import packages (via Import-Package) and require one or more bundles (via Require-Bundle), but if a package is imported via Import-Package, it is not also visible via Require-Bundle: Import-Package takes priority over Require-Bundle, and packages which are exported by a required bundle and imported via Import-Package must not be treated as split packages.

In order to be allowed to require a named bundle, the requiring bundle must have BundlePermission[<bundle symbolic name>, REQUIRE], where the bundle symbolic name is the name of the bundle that is required. The required bundle must be able to provide the bundle and must therefore have BundlePermission[<bundle symbolic name>, PROVIDE], where the name designates the requiring bundle. In the case a fragment bundle requires another bundle, the Bundle Permission must be checked against the fragment bundle's Protection Domain.

3.13.2 Split Package Compatibility

A package is a split package whenever there are multiple sources for the package; only bundles using the Require-Bundle header can have split packages.

A source is a bundle that provides the given package. Both the required bundles as well as the requiring bundle can act as a source. The required bundles and the requiring bundle can only contribute their exported packages.

Exported split packages from two bundles are compatible if the package sources for one are a subset of the other.

3.13.3 Issues With Requiring Bundles

The preferred way of wiring bundles is to use the Import-Package and Export-Package headers because they couple the importer and exporter to a much lesser extent. Bundles can be refactored to have a different package composition without causing other bundles to fail.

The Require-Bundle header provides a way for a bundle to bind to all the exports of another bundle, regardless of what those exports are. Though this can seem convenient at first, it has a number of drawbacks:

  • Split Packages - Classes from the same package can come from different bundles with Require bundle, such a package is called a split package. Split packages have the following drawbacks:

    • Completeness - Split packages are open ended, it is difficult to guarantee that all the intended pieces of a split package have actually been included.

    • Ordering - If the same classes are present in more than one required bundle, then the ordering of Require-Bundle is significant. A wrong ordering can cause hard to trace errors, similar to the traditional class path model of Java.

    • Performance - A class must be searched in all providers when packages are split. This potentially increases the number of times that a ClassNotFoundException must be thrown which can potentially introduce a significant overhead.

    • Confusing - It is easy to find a setup where there is lots of potential for confusion. For example, the following setup is non-intuitive.

         A: Export-Package: p;uses:=q
            Import-Package: q
         B: Export-Package: q
         C: Export-Package: q
         D: Require-Bundle: B, C
            Import-Package: p

    Figure 3.17 Split packages and package constraints

    Split packages and package constraints

    In this example, bundle D merges the split package q from bundles B and bundle C, however, importing package p from bundle A puts a uses constraint on package p for package q. This implies that bundle D can see the valid package q from bundle B but also the invalid package q from bundle C. This wiring is allowed because in almost all cases there will be no problem. However, the consistency can be violated in the rare case when package C.q contains classes that are also in package B.q.

  • Mutable Exports - The feature of visibility:=reexport that the export signature of the requiring bundle can unexpectedly change depending on the export signature of the required bundle.

  • Shadowing - The classes in the requiring bundle that are shadowed by those in a required bundle depend on the export signature of the required bundle and the classes the required bundle contains. (By contrast, Import-Package, except with resolution:=optional, shadows whole packages regardless of the exporter.)

3.14 Fragment Bundles

Fragments are bundles that can be attached to one or more host bundles by the Framework. Attaching is done as part of resolving: the Framework appends the relevant definitions of the fragment bundles to the host's definitions before the host is resolved. Fragments are therefore treated as part of the host, including any permitted headers; they must not have their own class loader though fragments must have their own Protection Domain.

Fragments can be attached to multiple hosts with the same symbolic name but different versions. If multiple fragments with the same symbolic name match the same host, then the Framework must only select one fragment, this must be the fragment with the highest version.

A key use case for fragments is providing translation files for different locales. This allows the translation files to be treated and shipped independently from the main application bundle.

When an attached fragment is updated, the content of the previous fragment must remain attached to its host bundles. The new content of the updated fragment must not be allowed to attach to the host bundles until the Framework is restarted or the host bundle is refreshed. During this time, an attached fragment will have two versions: the old version, attached to the old version of the host, and a new fragment bundle that can get attached to a new version or to a different host bundle. The exact configuration can be discovered with the Bundle Wiring API Specification.

When attaching a fragment bundle to a host bundle the Framework must perform the following steps:

  1. Append the import definitions for the Fragment bundle that do not conflict with an import definition of the host to the import definitions of the host bundle. A Fragment can provide an import statement for a private package of the host. The private package in the host is hidden in that case.

  2. Append the Require-Bundle entries of the fragment bundle that do not conflict with a Require-Bundle entry of the host to the Require-Bundle entries of the host bundle.

  3. Append the export definitions of a Fragment bundle to the export definitions of the host bundle unless the exact definition (directives and attributes must match) is already present in the host. Fragment bundles can therefore add additional exports for the same package name.

  4. Append the Provide-Capability clauses of the fragment to the Provide-Capability clauses of the host

  5. Append the Require-Capability clauses of the fragment to the Require-Capability clauses of the host

A host and a fragment conflict when they cannot resolve to provide a consistent class space. If a conflict is found, the Fragment bundle is not attached to the host bundle.

A Fragment bundle must enter the resolved state only if it has been successfully attached to at least one host bundle.

During runtime, the fragment's JAR is searched after the host's bundle class path as described in Fragments During Runtime.

A Fragment bundle can not be required by another bundle with the Require-Bundle header.

3.14.1 Fragment-Host

The Fragment-Host manifest header links the fragment to its potential hosts. It must conform to the following syntax:

Fragment-Host       ::= bundle-description
bundle-description  ::= symbolic-name 
                            ( ';' parameter )* // See 1.3.2

The following directives are architected by the Framework for Fragment-Host:

  • extension - Indicates this extension is a system or boot class path extension. It is only applicable when the Fragment-Host is the System Bundle. This is discussed in Extension Bundles. The following values are supported:

    • framework - The fragment bundle is a Framework extension bundle (default).

    • bootclasspath - The fragment bundle is a boot class path extension bundle.

    The fragment must be the bundle symbolic name of the implementation specific system bundle or the alias system.bundle. The Framework should fail to install an extension bundle when the bundle symbolic name is not referring to the system bundle.

The following attributes are architected by the Framework for Fragment-Host:

  • bundle-version - The version range to select the host bundle. If a range is used, then the fragment can attach to multiple hosts. See Semantic Versioning. The default value is [0.0.0,).

The Fragment-Host header can assert arbitrary attributes that must be matched before a host is eligible.

When a fragment bundle is attached to a host bundle, it logically becomes part of it. All classes and resources within the fragment bundle must be loaded using the class loader (or Bunde object) of its host bundle. The fragment bundles of a host bundle must be attached to a host bundle in the order that the fragment bundles are installed, which is in ascending bundle ID order. If an error occurs during the attachment of a fragment bundle then the fragment bundle must not be attached to the host. A fragment bundle must enter the resolved state only if it has been successfully attached to one or more host bundles.

In order for a host bundle to allow fragments to attach, the host bundle must have BundlePermission[<bundle symbolic name>,HOST]. In order to be allowed to attach to a host bundle, a fragment bundle must have BundlePermission[<bundle symbolic name>,FRAGMENT].

3.14.2 Fragments During Runtime

All class or resource loading of a fragment is handled through the host's class loader or Bundle object, a fragment must never have its own class loader, it therefore fails the class and resource loading methods of the Bundle object. Fragment bundles are treated as if they are an intrinsic part of their hosts.

Though a fragment bundle does not have its own class loader, it still must have a separate Protection Domain when it is not an extension fragment. Each fragment can have its own permissions linked to the fragment bundle's location and signer.

A host bundle's class path is searched before a fragment's class path. This implies that packages can be split over the host and any of its fragments. Searching the fragments must be done in ascending bundle ID order. This is the order that the fragment bundles were installed.

Figure 3.18 Resource/class searching with fragments

Resource/class searching with fragments

Figure 3.18 shows a setup with two fragments. Bundle B is installed before bundle C and both bundle B and bundle C attach to bundle A. The following table shows where different packages originate in this setup. Note that the order of the append (>) is significant.

Table 3.3 Effect of fragments on searching

Package Requested From Remark
p A.p > B.p

Bundle A exports package p, therefore, it will search its class path for p. This class path consists of the JAR and then its Fragment bundles.

q D.q

The import does not handle split packages and package q is imported from bundle D. Therefore, C.q is not found.

r A.r > B.r

Package r is not imported and therefore comes from the class path.

s C.s

t B.t > C.t


In the example above, if package p had been imported from bundle D, the table would have looked quite different. Package p would have come from bundle D, and bundle A's own contents as well as the contents of bundle B would have been ignored.

If package q had bundle D, then the class path would have to be searched, and A.q would have consisted of A.q > C.q.

Fragments must remain attached to a host as long as the host remains resolved. When a host bundle becomes unresolved, then all its attached Fragment bundles must be detached from the host bundle. When a fragment bundle becomes unresolved the Framework must:

  • Detach it from the host

  • Re-resolve the host bundles

  • Reattach the remaining attached fragment bundles.

A Fragment bundle can become unresolved by calling the refreshBundles(Collection,FrameworkListener...) method.

3.14.3 Illegal Manifest Header for Fragment Bundles

The following list contains the headers that must not be used in a fragment bundle:

  • Bundle-Activator

3.15 Extension Bundles

Extension bundles can deliver optional parts of the Framework implementation. The contents of extension bundles cannot be provided by the normal bundles because they need to be loaded by the framework implementation.

Framework extensions are necessary to provide implementation aspects of the Framework. For example, a Framework vendor could supply the optional services like Permission Admin service and Start Level API with Framework extension bundles.

An extension bundle should use the bundle symbolic name of the implementation system bundle, or it can use the alias of the system bundle, which is system.bundle.

The following example uses the Fragment-Host manifest header to specify an extension bundle for any Framework implementation.

Fragment-Host: system.bundle

The following example uses the Fragment-Host manifest header to specify an extension bundle for a specific Framework implementation.

Fragment-Host: com.acme.impl.framework

The following describe the life cycle of an extension bundle:

  1. When an extension bundle is installed it enters the INSTALLED state.

  2. The extension bundle is allowed to enter the RESOLVED state at the frameworks discretion. For example, a framework may choose to immediately resolve the extension after it has entered the INSTALLED state. If all requirements of an extension bundle are satisfied then resolving the extension bundle must not require a framework restart.

  3. If a RESOLVED extension bundle is refreshed then the framework must shutdown and the framework must be re-launched. In this case a Framework Event is fired of type STOPPED_SYSTEM_REFRESHED.

  4. When a RESOLVED extension bundle is updated or UNINSTALLED, it is not allowed to re-enter the RESOLVED state. If the extension bundle is refreshed then the Framework must shutdown and the framework must be re-launched. In this case a Framework Event is fired of type STOPPED_SYSTEM_REFRESHED.

It is valid to update an extension bundle to a bundle of another type. If the old extension bundle is resolved then it must be attached as a fragment to the system bundle. When this bundle is updated the old content of the bundle must remain attached to the system bundle until the system bundle is refreshed or the extension bundle is refreshed (using the Wiring API). This must initiate and Framework shutdown and restart. When the framework comes back up the new content of the bundle may be resolved.

All Bundle events should be dispatched for extension bundles as for ordinary bundles.

3.15.1 Illegal Manifest Headers for Extension Bundles

An extension bundle must throw a Bundle Exception if it is installed or updated and it specifies any of the following headers.

  • Require-Bundle

  • Bundle-NativeCode

  • DynamicImport-Package

  • Bundle-Activator

Extension bundles are permitted to specify an Export-Package header. Any exported packages specified by an extension bundle must be hosted (exported) by the System Bundle when the extension bundle is resolved.

Extension bundles are permitted to specify Import-Package and Require-Capability headers to declare dependencies on packages and capabilities.

3.15.2 Resolving Extensions

Extension bundles may specify requirements on packages (Import-Package) and capabilities (Require-Capability). An extension bundle is allowed to become resolved when all of its mandatory requirements are wired to valid packages or capabilities.

Extension bundle requirements may only be wired to packages and capabilities provided by the system bundle or another extension bundle that is also attached to the system bundle. All other capabilities are considered invalid for resolving an extension bundle. This ensures that the system bundle wiring never hosts a requirement from an extension bundle which is wired to a capability hosted by another bundle other than the system bundle.

3.15.3 Class Path Treatment

A extension bundle's JAR is appended to the class path of the Framework. Extension bundles that are resolved together must have their JAR appended in the order in which the extension bundles are installed: that is, ascending bundle ID order.

3.15.4 Extension Bundle Activator

A extension may hook into the Framework initialization and shutdown process by specifying an Extension Bundle Activator. The BundleActivator interface defines methods that the Framework invokes when the Framework is initialized and shutdown.

To inform the OSGi environment of a fully qualified class name serving as its Extension Bundle Activator, a framework extension developer must declare an ExtensionBundle-Activator manifest header in the framework extension bundle's manifest file. The following is an example of an ExtensionBundle-Activator:

ExtensionBundle-Activator: com.acme.Activator

The class acting as an Extension Bundle Activator must implement the BundleActivator interface, be declared public, and have a public default constructor so an instance of it may be created with Class.newInstance.

Supplying an Extension Bundle Activator is optional and only valid for Extension Bundles. For normal Bundles and Fragments, the ExtensionBundle-Activator must be ignored.

3.15.4.1 Framework Initialization and Shutdown

An Extension Bundle Activator allows a framework extension to hook into the Framework initialization and shutdown process. Initializing the Framework describes how the start method for Extension Bundle Activators is called during Framework initialization. Stopping a Framework describes how the stop method for Extension Bundle Activators is called during Framework shutdown.

3.15.4.2 Installing

When an extension bundle is installed, a Framework must allow the extension to become resolved dynamically, without a Framework restart. When an extension bundle is resolved dynamically after Framework initialization, then the Extension Bundle Activator start method must be called as soon as the extension bundle is resolved. This must happen before the Bundle Event of type RESOLVED is fired for the extension bundle.

3.15.4.3 Update and Uninstall

Unlike normal bundles, updating or uninstalling an extension bundle does not take effect until the Framework is shutdown and restarted. The original content of the extension bundle must remain attached to the system bundle and the Extension Bundle Activator must not have its stop method called until the Framework is shutdown.

3.15.5 Support Properties

Frameworks must implement fragments, require bundle, and extensions. They must therefore set the following properties to true.

  • org.osgi.supports.framework.requirebundle

  • org.osgi.supports.framework.fragments

  • org.osgi.supports.framework.extension

3.16 Security

3.16.1 Extension Bundles

In an environment that has Java security enabled the Framework must perform an additional security check before allowing an extension bundle to be installed. In order for an extension bundle to successfully install, the Framework must check that the extension bundle has All Permissions assigned to it. This means that the permissions of an extension bundle must be setup before the extension bundle is installed.

AllPermission must be granted to extension bundles because they will be loaded under the Protection Domain of either the boot class path or the Framework implementation. Both of these Protection Domains have All Permissions granted to them. Attempting to install an extension bundle that has not already been granted All Permissions must result in a Bundle Exception.

The installer of an extension bundle must have AdminPermission[<extension bundle>,EXTENSIONLIFECYCLE] to install an extension bundle.

3.16.2 Bundle Permission

Most package sharing permissions are based on Package Permission. However, fragments and required bundles use the bundle symbolic name to handle sharing. The Bundle Permission is used to control this type of package sharing.

The name parameter of the Bundle Permission is a bundle symbolic name. The symbolic name is used as the identifier for the target bundle. A wild card (".*" \u002E,\u002A) is permitted at the end of the name.

For example, for fragment bundle A to attach to its host bundle B then fragment bundle A requires BundlePermission("B", "fragment") so that A is permitted to target host bundle B. The direction of the actions is depicted in Figure 3.19.

Figure 3.19 Permissions and bundle sharing

Permissions and bundle sharing

The following actions are architected:

  • provide - Permission to provide packages to the target bundle.

  • require - Permission to require packages from the target bundle.

  • host - Permission to attach to the target fragment bundle.

  • fragment - Permission to attach as a fragment to the target host bundle.

When a fragment contains a Require-Bundle header, the Framework must check the permission against the domain of the fragment.

3.16.3 Package Permission

Bundles can only import and export packages for which they have the required permission. A PackagePermission must be valid across all versions of a package.

A PackagePermission has two parameters:

  • The name, either the name of the target package (with a possible wildcard character at the end) or a filter expression that can verify the exporting bundle. A filter expression can test for the package name with the package.name key. A filter can only be used for an IMPORT action. Filters are described in Filter Based Permissions.

  • The action, either IMPORT or EXPORTONLY.

For example, the following Package Permission permits to import any package from a bundle downloaded from ACME:

PackagePermission("(location=http://www.acme.com/*",IMPORT)

When a fragment adds imports and exports to the host, the framework must check the protection domain of the fragment and not of the related host.

3.16.4 Resource Permissions

A Framework must always give a bundle the RESOURCE, METADATA, and CLASS AdminPermission actions to access the resources contained within:

  • Itself

  • Any attached fragments

  • Any resources from imported packages

A resource in a bundle may also be accessed by using certain methods on Bundle. The caller of these methods must have AdminPermission[bundle, RESOURCE].

If the caller does not have the necessary permission, a resource is not accessible and null must be returned. Otherwise, a URL object to the resource must be returned. These URLs are called bundle resource URLs. Once the URL object is returned, no further permission checks are performed when the contents of the resource are accessed. The URL object must use a scheme defined by the Framework implementation.

Bundle resource URLs are normally created by the Framework, however, in certain cases bundles need to manipulate the URL to find related resources. For example, a URL can be constructed to a resource that is in the same directory as a given resource.

URLs that are not constructed by the Framework must follow slightly different security rules due to the design of the java.net.URL class. Not all constructors of the URL class interact with the URL Stream Handler classes (the implementation specific part). Other constructors call at least the parseURL method in the URL Stream Handler where the security check can take place. This design makes it impossible for the Framework check the permissions during construction of a bundle resource URL.

The following constructors use the parseURL method and are therefore checked when a bundle resource URL is constructed.

URL(String spec)
URL(URL context, String spec)
URL(URL context, String spec, URLStreamHandler handler)

When one of these constructors is called for a bundle resource URL, the implementation of the Framework must check the caller for the necessary permissions in the parseURL method. If the caller does not have the necessary permissions then the parseURL method must throw a Security Exception. This will cause a Malformed URL Exception to be thrown by the URL constructor. If the caller has the necessary permissions, then the URL object is setup to access the bundle resource without further checks.

The following java.net.URL constructors do not call the parseURL method in the URL Stream Handler, making it impossible for the Framework to verify the permission during construction.

URL(String protocol, String host, int port,String file)
URL(String protocol, String host, int port, String file, URLStreamHandlerhandler)
URL(String protocol, String host, String file)

Bundle resource URLs that are created with these constructors cannot perform the permission check during creation and must therefore delay the permission check. When the content of the URL is accessed, the Framework must throw a Security Exception if the caller does not have AdminPermission[bundle, RESOURCE] for the bundle referenced by the URL.

3.16.5 Capability Permission

The Capability Permission provides a means to limit access to certain Capabilities when security is on. A Capability Permission is a Filter based Permission, as described in Filter Based Permissions, giving access to the following additional property:

  • capability.namespace - The namespace of the requirement or provided capability.

The filter can also assert information from the target bundle. The target bundle is always the bundle that provides the capability. This means that a requirer can be restricted to receive a capability from a specific bundle.

Capabilities in a namespace for which the resolving bundle has no permission are not available to other bundles. Requirements in a namespace for which a bundle has no permission can never be satisfied.

The Capability Permission has the following actions:

  • REQUIRE - Imply permission to require the given namespace. The target bundle that can be asserted in the filter is the bundle providing the capability.

  • PROVIDE - Imply permission to provide a capability in the given namespace, the target bundle is the bundle that is checked for the permission.

The Capability Permission has the following constructors:

3.16.6 Permission Checks

Since multiple bundles can export permission classes with the same class name, the Framework must make sure that permission checks are performed using the correct class. For example, a bundle that calls the checkPermission method provides an instance of the Permission class:

void foo(String name) {
   checkPermission(new FooPermission(name,"foo"));
}

This class of this Permission instance comes from a particular source. Permissions can only be tested against instances that come from the same source.

Therefore, the Framework needs to look up permissions based on class rather than class name. When it needs to instantiate a permission it must use the class of the permission being checked to do the instantiation. This is a complication for Framework implementers; bundle programmers are not affected.

Consider the following example:

  Bundle A 
        Import-Package: p
       Export-Package: q
  Bundle B 
        Import-Package: p
  • Bundle A uses a p.FooService. Usage of this class checks q.FooPermission whenever one of its methods is invoked.

  • Bundle B has a FooPermission in its Protection Domain in a (Conditional) Permission Info object.

  • Bundle B invokes a method in the FooService that was given by bundle A.

  • The FooService calls the checkPermission method with a new FooPermission instance.

  • The Framework must use a FooPermission object that is from the same class loader as the given FooPermission object before it can call the implies method. In this case, the FooPermission class comes from package A.q.

After the permission check, bundle B will have a FooPermission instantiated using a class from a package it does not import. It is therefore possible that the Framework has to instantiate multiple variations of the FooPermission class to satisfy the needs of different bundles.

3.17 References

[1]Java Virtual Machine Specificationhttps://docs.oracle.com/javase/specs/

[2]The Standard for the Format of ARPA Internet Text MessagesSTD 11, RFC 822, UDEL, August 1982
http://www.ietf.org/rfc/rfc822.txt

[3]The Hypertext Transfer Protocol - HTTP/1.1RFC 2068 DEC, MIT/LCS, UC Irvine, January 1997
http://www.ietf.org/rfc/rfc2068.txt

[4]Java Language Specificationhttps://docs.oracle.com/javase/specs/

[5]A String Representation of LDAP Search FiltersRFC 1960, UMich, 1996
http://www.ietf.org/rfc/rfc1960.txt

[8]Codes for the Representation of Names of LanguagesISO 639, International Standards Organization
http://lcweb.loc.gov/standards/iso639-2/langhome.html

[9]Zip File FormatThe Zip file format as defined by the java.util.zip package.

[12]Mathematical Convention for Interval Notationhttp://planetmath.org/encyclopedia/Interval.html

[13]RFC 2396 Uniform Resource Identifiers URI: Generic Syntaxhttp://www.ietf.org/rfc/rfc2396.txt

[14]Codes for the Representation of Names of LanguagesISO 639, International Standards Organization
http://lcweb.loc.gov/standards/iso639-2/langhome.html

[18]Portable Network Graphics (PNG) Specification (Second Edition)http://www.w3.org/TR/2003/REC-PNG-20031110/

[19]Open Source Initiativehttp://www.opensource.org/

[21]Specification Referenceshttps://docs.osgi.org/reference/

[24]Google Web Toolkithttp://www.gwtproject.org/

[25]Software Package Data Exchange (SPDX) License Listhttps://spdx.org/licenses/

[26]Maven POM Reference, Developershttps://maven.apache.org/pom.html#Developers

[27]Maven POM Reference, SCMhttps://maven.apache.org/pom.html#SCM

3.18 Changes