DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
1. Overview
The OSGi framework supports deploying bundles into a flat and basically globally bundle space. The idea behind this approach can be summarized as, "the deployed set of bundles is your application configuration." This approach has performed well over the years; however, as OSGi technology is used in more and more complicated scenarios, this approach is not always sufficient. For example, when trying to run multiple applications in a single framework instance or when applications become so large that sets of bundles start mapping onto logical subsystems. In these types of situations, it is possible for the configurations of different applications or subsystems to interfere with each other.
To address some of these issues, this proposal introduces a composite bundle concept built on top of virtual bundles. The main goal of this proposal is to provide an isolation mechanism for groups of bundles, while still allowing collaboration among those groups and to manage everything as a layer above the framework.
2. Use cases
Some potential use cases for composite bundles:
- Large application subsystems can be modeled as a composite bundle.
- Different applications running in the same framework instance can be isolated from each other inside of composite bundles.
- Web servers could model EARs and composite bundles.
- Groups of bundles needing lifecycle management as a whole can be modeled as a composite bundle.
This list is not intended to be exhaustive.
3. Terminology
The following terms are used in this document:
- Composite bundle - a bundle whose contents is actually a set of bundles that appear to be running inside of another framework instance.
- Parent framework - the framework in which a composite bundle is installed.
- Composite framework - the framework running inside the composite bundle (this term may not be necessary).
4. Technical approach
The overall technical approach is to use the virtual bundle concept (proposed separately) to manage composite bundles as a layer above the framework. This proposal forgoes an API-based approach to support a simple, declarative approach. The technical approach is divided into two halves for supporting a more simplistic composite model and extending this model to support additional scenarios at the expense of making it more complicated.
NOTE: The goal is not to completely rule out any API, but to keep things simple until some real-world experience is gained at which point API could potentially be introduced.
4.1 Simple composite model
The simple composite model supports installing groups of bundles as a single composite bundle with the ability to import packages/services from the parent framework into the composite bundle and to export packages/services from the composite bundle to the parent framework. The lifecycle of the constituent bundles are managed by the lifecycle of the composite bundle in the parent framework.
4.1.1 Simple composite description
A composite bundle is declared using a set of manifest-like headers, which is familiar to bundle developers and fits well with the virtual bundle proposal, where virtual bundles are installed with a given set of headers. The following headers are reused for declaring a composite bundle:
Import-Package- the packages imported by the composite bundle from the parent framework.Export-Package- the packages exported by the composite bundle to the parent framework.Import-Service- the services imported by the composite bundle (exact syntax is yet to be defined, but a list of filters is a reasonable starting point).Export-Service- the services exported by the composite bundle (exact syntax is yet to be defined, but a list of filters is a reasonable starting point).
From the parent framework's perspective, the composite bundle is a normal bundle importing/exporting packages and services. Internally, the imported/exported packages and services are mapped onto and made available to the composite bundle's constituent bundles by the composite layer. A new header is introduced to declare the composite bundle's constituent bundles:
Include-Bundle- A comma-separate list of bundle URLs.
The constituent bundles of a composite bundle are isolated from the other bundles in the parent framework. In other words, they can only see their sibling constituent bundles and bundles in the parent framework can only see the composite bundle, not its constituent bundles.
To simplify mapping a composite bundle's exported packages to its constituent bundles, this proposal introduces a new from directive for Export-Package, which is used to specify the symbolic name of the providing bundle. Consider the following composite declaration:
Bundle-ManifestVersion: 2 Bundle-Name: Paint Program Bundle-SymbolicName: org.foo.paint.composite Include-Bundle: \ file:/Users/rickhall/Projects/book-trunk/code/chapter04/paint-example/bundles/shape-4.0.jar, \ file:/Users/rickhall/Projects/book-trunk/code/chapter04/paint-example/bundles/paint-4.0.jar, \ file:/Users/rickhall/Projects/book-trunk/code/chapter04/paint-example/bundles/circle-4.0.jar, \ file:/Users/rickhall/Projects/book-trunk/code/chapter04/paint-example/bundles/square-4.0.jar, \ file:/Users/rickhall/Projects/book-trunk/code/chapter04/paint-example/bundles/triangle-4.0.jar Export-Package: org.foo.shape; from:=org.foo.shape; version="4.0" Import-Package: org.osgi.service.log; version=1.0.0 Import-Service: org.foo.shape.SimpleShape
This composite contains five bundles and exports org.foo.shape from the bundle with the symbolic name org.foo.shape. Further, it also imports the log service package and any services implementing the org.foo.shape.SimpleShape interface from the package it exports.
These declarative headers define the entire capabilities of a simple composite bundle. To summarize, these capabilities are: containing bundles, importing/exporting packages, and importing/exporting services.
NOTE 1: It is not clear if Import-Package should essentially support an "export as" directive where the composite creator explicitly specifies how the imported package gets converted to an export internally or if this should be somehow automatically derived from the actual injected wire. If the latter, then this relates to the rich wiring section in the open issues.
NOTE 2: Any "uses" constraints for the composite bundle's exported packages must be specified in the metadata, which will be used by parent framework to ensure consistency like normal.
4.1.2 Simple composite lifecycle management
Since composite bundles are implemented as virtual bundles, access to their content and portions of their lifecycle are controlled by an external manager. This section describes various lifecycle management issues for simple composite bundles.
4.1.2.1 Composite manager
The composite manager results from the use of virtual bundles and is largely responsible for realizing the capabilities embodied in the composite description. This means it is the composite manager's responsibility to:
- Manage a composite bundle's constituent bundles.
- Provide constituent bundles access to imported packages and imported services.
- Provide the parent framework access to exported packages and exported services.
- Manage the overall lifecycle of composite bundles.
The precise approach the composite manager uses to accomplish these responsibilities is not specified, but one potential approach is for the composite manager to create different a separate framework instance for each composite bundle. Another approach would be to create a static wiring of the constituent bundles and just mimic framework behavior for them.
4.1.2.2 Installing composites
If an "install hook" is introduced in the virtual bundle proposal, then the composite manager can use it to seamlessly install composite bundles via the BundleContext.installBundle() method like a normal bundle. If install hooks are not proposed, then it could provide a simple service for installing composites. A composite is installed with a complete composite description, which forms the manifest of the installed virtual bundle. As such, composite installation is effectively atomic from the perspective of the parent framework.
4.1.2.3 Resolving composites
The composite bundle's wires for its imported packages are injected into the composite's virtual module by the framework, like for all virtual bundles. The composite manager uses these wires for delegation purposes out to the parent framework for the constituent bundles. If a composite bundle is resolved, then it is possible to load classes from it.
NOTE: Resolving a composite bundle could actually be combined with some sort of verification step, where the manager verifies whether or not the composite bundle can provide what it says it can provide. It is not clear if this needs to be specified, since such verification does not happen for normal bundles. In other words, it is a reasonable approach to just trust the metadata.
4.1.2.4 Starting and stopping composites
Starting a composite bundle starts all internal constituent bundles. Likewise, stopping a composite bundle stops all constituent bundles. Composite bundles do not have user-defined activators, although the composite manager may make use of an activator. For active composites, the composite manager must provide constituent bundles access to services imported from the parent framework and must make exported services available in the parent framework. Conversely, when a composite bundle is no longer active, it must stop providing access to these services.
After a composite bundle is stopped, it should remain resolved and continue to provide access to its exported packages and provided bundles.
NOTE: Since this proposal does not propose an API to expose the constituent bundles, individual lifecycle manipulation of the constituent bundles is not expected. To keep things simple, constituent bundles are either active or not based on the state of their composite bundle. If more fine-grained control is required it would be possible. Starting and stopping individual constituent bundles would offer no real issue, although allowing them to be refreshed or uninstalled might cause the composite manager to force the outer composite bundle to refresh if the export signature is impacted.
4.1.2.5 Refreshing a composite
When refreshing a composite bundle, all constituent bundles are refreshed and the composite bundle returns to the installed state. Following normal framework behavior, any bundles depending on the composite bundle will also be refreshed. Likewise, if the composite bundle depends on another bundle being refreshed in the parent framework, then it will be refreshed too.
4.1.2.6 Uninstalling a composite
The normal bundle uninstall operation does not directly mean that a bundle is no longer in use, since it is still possible to load classes from it. Further, the framework provides to additional callbacks or state changes to notify when it is really done with a bundle. As a result, if a composite bundle is uninstalled, the composite manager must immediately refresh it to perform proper clean up, since it will not be able to get a later lifecycle callback when the bundle is eventually refreshed.
NOTE: This could be improved with a VirtualModule.dispose() method, which would be invoked by the framework to indicate it done with the virtual module.
4.1.2.7 Relationship to composite manager lifecycle
Since the composite manager manages all aspects of the composite's content, its active lifetime scopes its managed composites. In other words, if the composite manager is stopped, then it explicitly causes all of its managed composites to refresh and return to the installed state.
4.2 Extended composite model
4.2.1 Extended composite description
This proposal introduces one final header, which is:
Provide-Bundle- a comma-delimited set of symbolic names specifying the constituent bundles provided by the composite bundle to the parent framework.
The provided bundles will be manifested in the parent framework as virtual bundles themselves.
4.2.2 Extended composite lifecycle management
NOTE: For a provided bundle into the parent framework, it is not clear how we should tie its lifecycle to the corresponding constituent bundle and/or whether it should be controllable in the parent framework. For simplicity, it is probably better to effectively make it a no-op.
When refreshing a composite, all constituent bundles are refreshed and the composite bundle returns to the installed state. Any provided bundles in the parent framework will also be refreshed and returned to the installed state and will not be resolvable until the composite is resolved.
NOTE 1: Another approach for provided bundles is to uninstall and refresh them.
NOTE 2: Refreshing a provided bundle should likely be a no-op internal to the composite bundle, although it will cause a refresh of dependent bundles in the parent framework.
4.1.2.8 Lifecycle flow
Lifecycle control flows down, not up
5. Open issues
5.1 Rich wiring information
Currently, the wiring information provided by the virtual bundle proposal has been kept purposely simplistic. To fully implement aspects of composites, like requiring/providing bundles, it is necessary to get richer information from the wires, such as the type of capability. Further, the wiring information needs to be at the module-level (i.e., bundle revision level), not at the bundle level.
6. Considered alternatives
TBD