The framework layout

The modular entity in an OSGi framework is referred to as a bundle. A bundle is a collection of code, resources, and configuration files that are packaged as a Java ARchive (JAR).

A bundle can be compared to a Web ARchive (WAR) in the context of a web container, or to an Enterprise ARchive (EAR) in the context of a Java Enterprise Platform. For example, a web container would inspect the contents of a WAR for configuration, resources, and code that it needs to publish the web application and manage its lifecycle.

In the OSGi world, the framework focuses on the functionality that's required to operate the bundle as an entity with a lifecycle and provides code and services. It then communicates changes to the other components in the framework and the installed bundles.

For example, as we will see in Chapter 13, Improving the Graphics, a web container installed as a bundle listens to bundles that are installed and grabs those that are identified as web applications for registration. The web container would be a service published by a bundle on the framework. In this case, both the web container and the web application are bundles installed on the framework one bundle using the other to provide a service.

Such a split of responsibilities (for example, web application publishing and lifecycle management) offers a greater flexibility in the design of a service platform. It is also applied within the framework in the organization of its components.

The functional layers

The components in the OSGi framework are grouped into distinct functional layers. Each layer is responsible for a specific set of tasks related to the integration of the bundle with the framework. Those layers are explained as follows:

  • The execution environment layer, which is the bottom layer on which the bundles live, is selected to fit the underlying hardware or operating system. Two examples of the common execution environments are CDC-1.1/Foundation-1.1 and JavaSE-1.6. Others can be found in Table 3.2 of the OSGi Core specification.
  • The module layer, which is the bundle space, holds the bundles that are installed on the framework and are managed through the lifecycle layer.
  • The lifecycle layer manages and keeps track of the frameworks and bundles lifecycle state. It is used to install or uninstall framework objects and start or stop them.
  • The service layer, which holds the service-side of the framework, keeps the service registry and manages it.
  • The security layer, which extends the Java 2 security architecture, is optional. When active, it validates bundle signatures, and controls component access rights.

Although we're only going to use the service layer to register our services during this case study, it is interesting to understand the functional breakdown of the framework.

The clear definition of the interfaces of the components in each layer allows for a better flexibility in the implementation of a framework, as well as a well-defined means for bundles to communicate with the service platform.

For example, a different execution environment layer would be selected depending on the target system on which the framework will run. This will happen without affecting the other layers or the bundles that are installed on the platform.

The following diagram depicts this layering and shows some of the interaction between the layers of the framework:

The functional layers

The bundles are kept in a sort of a sandbox and wired together, based on their declared requirements. This not only allows you to enforce a tight control over class visibility, but it also keeps track of which packages a bundle is using from other bundles. This control helps manage bundles better, resulting in the possibility to decide when a bundle can be updated without resetting the bundles that depend on it, allowing runtime update of bundles.

The bundle lifecycle states

The lifecycle of a bundle within a framework starts with its install. A bundle can be installed either by another bundle in the framework, using the framework API, or via the framework implementation.

For example, as we will see in Chapter 5, The Book Inventory Bundle, the Felix framework provides a shell command (the install command) that is used to install bundles. The shell service is installed as a bundle and exposes the command for use as part of the console.

Before a bundle is active on the framework, it must go through the resolution process, in which the module layer reads its manifest headers, performs required checks, and identifies the bundle's dependencies.

When a bundle is successfully resolved, it can be started and the lifecycle layer takes over the process. If a bundle activator is provided with the bundle (using the Bundle-Activator header), then the framework will use it to activate the bundle for initialization. The framework gives control to the bundle activator through the start() method. We'll look more closely at bundle activation in Chapter 5.

The activation can be eager or lazy, as defined by the Bundle-ActivationPolicy header we introduced a bit earlier.

With the eager activation policy, the bundle is activated as soon as it is done starting. When the activation policy is set to lazy, then the bundle is only activated when the first class from that bundle is loaded.

The following state machine describes the states that a bundle can go through during its lifecycle. It also shows the actions that are performed on the bundle to shift its state.

The bundle lifecycle states

Those states are as follows:

  • INSTALLED: The bundle has been successfully installed. The framework knows enough about this bundle to attempt to load it.
  • RESOLVED: All resources needed for this bundle have been loaded successfully and the bundle is ready to be started. This is also the state the bundle would be in, once successfully stopped.
  • STARTING: The bundle is being started, but has not finished starting.
  • ACTIVE: The bundle has been successfully activated and is running, ready to be used.
  • STOPPING: The bundle is being stopped, but has not finished stopping.
  • UNINSTALLED: The bundle has been uninstalled. Once uninstalled, nothing can be done with the module.

As we'll see in Chapter 5, by defining a bundle activator, the framework will temporarily give the bundle control of the execution flow when it is in the starting and stopping states by calling the bundle activator's start() and stop() methods.

Unless instructed otherwise (that is, by requesting start or stop in transient mode), the framework will keep track of whether a bundle is active and attempt to restore that state at the next startup. When the bundle is started, it is persistently marked for start.

Bundle wiring

Without going into the details of the class loading and visibility constraints, it's worth knowing that the framework keeps separate codebases for the different bundles, controlling how each bundle's classes are loaded and which classes a bundle can "see". The process of linking a bundle to provide its access to another bundle's content is called wiring.

When the framework resolves a bundle for installation, it reads the bundle manifest looking for its capabilities (the packages it provides or exports) and its requirements (those that it imports). It uses this information to wire the bundles together in a mesh of dependencies, thus constructing the class space visible to each bundle.

This mechanism allows each bundle to clearly define which of its packages (and classes) are hidden from other bundles and which are shared.

For example, if Bundle B exports package b and Bundle C exports package c, then those packages are made available for bundles that require them on the framework.

Here, Bundle A imports packages b and c. Those bundle capabilities and requirements are expressed in the form of the Import-Package and Export-Package OSGi headers that we'll see in a bit.

Bundle wiring

The preceding diagram is a simple view of this wiring. The wires are actually a bit more complex and keep track of constraints such as dependency version ranges, optional dependencies, and so on.

If Bundle C were not installed and package c is not provided by another bundle, then Bundle A cannot be resolved successfully because of its missing dependency.

..................Content has been hidden....................

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