6 Resource API Specification

6.1 Introduction

This section describes the API for the generic Requirement-Capability model as introduced in the Dependencies. This API is not used directly by the Framework, the purpose of specifying this base API is to allow it to be used as building block for other specifications.

6.1.1 Entities

  • Resource - An entity that can be installed in an Environment where it will provide its Capabilities when all its Requirements are satisfied.

  • Environment - A framework or container that contains one or more Resources.

  • Namespace - Defines the semantics of the Requirements and Capabilities; a Requirement can only match a Capability when they are in the same Namespace. A Namespace is similar to a type in an object oriented language.

  • Requirement - An assertion on a Capability in a Namespace. The assertion uses the OSGi filter language to match the attributes of a Capability. The filter is specified as a directive; a Requirement can also have other directives and attributes.

  • Capability - An attribute based description of a quality of a Resource when installed in an Environment.

  • Wiring - The wired state of a Resource.

  • Wire - Connects a Requirement to a matching Capability.

Figure 6.1 Class diagram for org.osgi.resource

Class diagram for org.osgi.resource

6.2 Resources

The OSGi dependency model is introduced in Dependencies ; it is based on a generic Requirements/Capability model. In this model a Resource models something that can be installed in an Environment but has Requirements that must be satisfied by Capabilities available in that the Environment. However, once it is installed and resolved into the Environment it provides its declared Capabilities to that Environment. Bundles are Resources, an example of a Requirement is an Import-Package clause, and an example of a Capability is an Export-Package clause.

The org.osgi.resource package contains a base API that defines a number of interfaces that model this generic model.

The org.osgi.framework.wiring package provides an API for reflecting the wiring of an OSGi Framework. The purpose of the separation is to allow the management agents to treat the system in a uniform way. That is, it allows a wide array of resources and environments to be modeled, and thus managed, in a uniform way. The Resource API is therefore primarily a building block for other specifications.

The Capability and Requirement class are almost identical in their signature. They both provide the following methods:

  • getAttributes() - Return a map with the attributes

  • getDirectives() - Return a map with the directives

  • getNamespace() - Return the Namespace

  • getResource() - Return the Resource

The key difference between a Requirement and a Capability is that a Capability provides attributes that are matched by an OSGi filter specified in a Requirement's filter directive.

6.3 Namespaces

The Namespace acts as the type of a Capability and Requirement. A Capability and a Requirement can only match when they are in the same Namespace. The Namespaces in use by the OSGi Core specification are defined in Framework Namespaces Specification. Other specifications can, however, define their own Namespaces.

A Namespace defines:

  • Requirement Attributes - Any attributes that are allowed to be used on a Requirement declaration.

  • Requirement Directives - Any directives that are allowed to be used on a Requirement declaration.

  • Capability Attributes - Any attributes that are allowed to be used on a Capability, these attributes are available for matching.

  • Capability Directives - Any defined directives that are allowed to be used on the Capability

  • Semantics - The Namespace definition defines what the meaning is of a Capability. This can include actions in the Environment like for example being wired with certain rules.

6.3.1 Matching

A Requirement matches a Capability when:

  • They have the same Namespace, and

  • The Requirement's filter matches the Capability's attributes, and

  • If the Namespace is an osgi.wiring.* Namespace then the mandatory directive must be supported.

Other Namespaces must not introduce additional matching rules.

6.4 Resolution

Before a Resource can provide its functionality it must be resolved against the Environment. The Environment can provide a number of Capabilities of its own but in general the Capabilities come from the of the installed Resources. The resolver must find a set of Wires between Requirements and Capabilities in an Environment such that each mandatory Requirement is satisfied with at least one Capability, and the constraints of the involved Namespaces are all met.

Resolving is an NP-complete problem since there are many solutions, it is easy to test if a solution is right, but there is no algorithm to calculate a solution. In practice, for the OSGi resolvers it is possible to find solutions in a reasonable amount of time. However, the nature of NP-complete problems makes it difficult to set exact rules: many solutions are correct. Constraining the resolvers too much would stifle innovation and likely cause performance problems.

In general the Environment has an existing Wiring state for already installed Resources. The resolver then calculates a resolution, which is a set of Wires that should be added to the existing Wiring state by installing the Resources. A Wire is a connection from a Requirement to a Capability. A Requirement or Capability is declared in a Resource. This is depicted in Figure 6.2.

Figure 6.2 Wire and declared Resources

Wire and declared Resources

6.4.1 Hosted Requirements and Capabilities

Though each Capability and Requirement is declared in a Resource, it can however be hosted by another Resource. For example, when a Fragment has an Export-Package header it is in reality its host that will provide that package. There is therefore a clear distinction between the Resource that declares the Capability/Requirement and the run time Wiring state that hosts that Capability. For this reason, a Wire connects a Requirement and a Capability but links separately to the Resources that host the Requirement and the Capability. Figure 6.3 depicts a hosted Capability. The Capability from the Fragment bundle is hosted by Host A and Host B.

Figure 6.3 Hosted Capability Example

Hosted Capability Example

For this reason, the Wire class provides the following methods:

6.4.2 Resolution

Requirements can be optional or mandatory, as specified in the resolution directive, which is only available on the Requirement. Optional Requirements do not have to be satisfied by the Resolver. Environments can be eager or relaxed in finding Resources to resolve optional Requirements. All mandatory Requirements of a Resource must be satisfied before that Resource's Capabilities can be provided to the Environment.

The syntax of the resolution directive is therefore:

resolution ::= 'optional' | 'mandatory'

The default is mandatory.

6.4.3 Effectiveness

Both Requirements and Capabilities support the effective directive. This directive provides a name that can be used by the Environment to control the resolving process. During a resolve process, the Environment can then decide one or more names that must match the effective directive.

For the OSGi Framework, the name resolve is reserved, this is also the default. The syntax is therefore:

effective ::= <name>

6.4.4 Mandatory Attributes

If a Capability has declared a mandatory directive and the Namespace starts with osgi.wiring then it mandates that the names listed directive are used in the filter and must match. The syntax for the mandatory attribute is:

mandatory   ::= extended ( ',' extended )*

6.4.5 Cardinality

The cardinality directive defines if a Requirement can be wired to multiple Capabilities or must be wired to at most one. The syntax for the directive is:

cardinality ::= 'single' | 'multiple'

The default is single.

6.4.6 Class Space Consistency

Though the Requirement/Capability model is generic it is linked closely with the class loading architecture of OSGi frameworks, particularly class space consistency, see Constraint Solving. For this reason, each Capability can specify its uses constraints with the uses Capability directive. The uses directive always contains a comma separated list of package names. The resolver must ensure that any resolution does not violate the class space consistency based on these constraints. Uses constraints can be specified on any Capability, not just Capabilities related to class loading, and are always about Java packages. The syntax of the directive is:

uses ::= package-name ( ',' package-name )*

6.5 Wiring

A resolver calculates a set of Wires between Requirements and Capabilities based on an existing, potentially empty, state. The existing state in the Environment is represented in a set of Wiring objects. Such an object represents the Wiring state of a Resource in an Environment. It provides access to all hosted Requirements and Capabilities as well as existing Wires. It has the following methods to conveniently provide access to the state: