equinox
Prototype Overview and Design

 
Summary
This first prototype of the Eclipse Rich Client Platform is the result of the work of Olivier Gruber and Woody Huang, both at IBM T.J. Watson Research Center. This prototype is based on Eclipse RC3, in which OSGi has been integrated. It demonstrate a full dynamic stack: OSGi, dynamic plugin registry, and dynamic Workbench. This document describes this prototype in terms of its architecture, design, and status.


Last Modified: 1400 June 21, 2003


Nota Bene: This document describes the current prototype, not the final decisions of Equinox.
Overview

This prototype is based on Eclipse RC3 and integrates an implementation of OSGi specification ( www.osgi.org ). It follows a layered architecture. As a foundation, an OSGi layer manages OSGi bundles. It is designed to be a standalone independent layer—even though it is not yet the case in the current prototype (see roadmap for details). The OSGi layer provides the ability to create and deploy OSGi bundles, that is, Java components. A Java component is basically a set of Java packages (classes and resources) and services (as Java objects). Bundles are useful to deploy libraries such as SWT, JFace, Xerces, or even Ant. This OSGi layer has been extended to understand the concept of fragments as well as the Eclipse versioning model. The presence of this OSGi layer suggests light modifications to PDE and the update manager, which are pending.

The next layer up is the Eclipse registry, introducing plugins. While a bundle is not a plugin, a plugin is a bundle. A plugin adds the Eclipse concepts of extensions and extension points. A plugin defines its extensions and extension points in a "plugin.xml" resource. It contributes such extensions and extension points to the plugin registry when the bundle is resolved at the OSGi level. The plugin registry is the Eclipse plugin registry but limited to the management of extensions and extension points. All matters regarding class and resource loading remain down in the OSGi layer. Fragment support is still necessary to allow fragments to contribute dynamically their extensions and extension points to their corresponding plugins.

Above the plugin registry, the traditional integration plugins of Eclipse are found, i.e., mostly the plugins supporting the Workbench and Workspace. These plugins have been modified to react to lifecycle events of extensions. Indeed, extensions may dynamically appear or disappear as plugins are installed, updated, or removed as the RCP runs.

This prototype demonstrate a full dynamic stack, from top to bottom. Bundles, being plugins or not, can be installed, updated, and removed without restarting the overall platform. When a plugin happens to be installed, updated, or removed, the OSGi layer dynamically resolves the plugin (imports and exports of Java packages), the Eclipse registry dynamically reflects the plugin extensions and extension points, thereby changing the matching of extensions with extension points. Those changes trigger lifecycle events about the extensions, to which the Workbench dynamically reacts, adjusting to extensions disappearing or appearing on its extension points. This includes the UI reacting to views, editors, actionSets, or wizards appearing or disappearing.

OSGi Layer

The OSGi layer has been inserted in between the Boot and Runtime plugins. It can be found within the Runtime plugin. The OSGi layer is an implementation of the OSGi specification, level 2.0. Only the core functionality have been implemented so far, that is, bundle management and services. Most of the other services such as user management or configuration management are missing. The goal was to experiment with running Eclipse on top of OSGi. Through a give-and-take approach for both Eclipse and OSGi, the experiment was successful and really convinced us of the great opportunity to drive OSGi forward while allowing Eclipse to benefit from an open standard. Here is a quick list of the functionality and characteristics of the OSGi layer:

  • Clean architecture, separating between the classloader framework and the underlying support platform (on-disk management of bundles)
  • Fully builds within Eclipse (no external build)
  • Self-hosting aware (dev mode)
  • It includes full bundle and service support.
  • Bundles have a global unique identity, their name and version. The name follows Java package convention, prefixed by their provider name. Follows the Eclipse versioning model
  • Full Eclipse fragment support
  • Lazzy class loader creation
  • Two-phase approach to installs and updates, with an incremental algorithm for resolving bundles
  • Backgrounded install for bundles

The bundle concept is following the OSGi specification. Bundles import and export versioned Java packages. The versioning model has been changed for imported/exported Java packages, moved to Eclipse versioning model. Bundles also can register services.

It has been extended with Eclipse concept of fragments. A fragment acts as a slave bundle that extends a master bundle. So, a fragment is a bundle that declares a master bundle. A fragment is resolved only if its master is resolved and its imports are satisfied. When resolved, a fragment contributes all its classes, resources, and services to its master bundle.

The OSGi specification has been left mostly untouched but for a few added methods here and there (on Bundle and BundleContext). The methods are mostly to add a global identity to a bundle, which a unique name and a version. Also, improved support to hide class loaders, that is, we added the ability to load a class and get a ResourceBundle to the already existing ability to get a resource.

We need to revisit the activation model and introduce declarative services (as per the OSGi specification 3.0). Eclipse promotes automated activation while OSGi adopted an explicit activation. We are working on an automated activation approach across layer, on class loading, service lookup, and extension creation.

One aspect has been profoundly changed: the administration of the platform. This impacted only the PackageAdmin package. We have two goals there. One is to introduce a notion of bundle assembly, along with some encapsulation. The other is to approach installs/updates as a two-phase process. The idea here is that the framework is able to virtualize updates/installs, allowing full introspection on the future state of the framework. The update manager is therefore given a change to evaluate the effects of changes and to either commit or abort them. The two-phace approach and the notion of assembly shall allow to deal with complex configuration with minimal pertubations to a running system.

There is no concept of assembly of bundles yet in the prototype. In other words, there is no ability to control sharing of bundles or visibility of services. Following OSGi specification, there is still only one shared global space for exported Java packages as well as one shared global space for services. We are finishing the specification of a mechanism based on scopes.

The two-phase install process is finished and represents a major departure from the OSGi specification. Certainly not from the point of view of a bundle developer, the programming model remains untouched. But it does change how an update manager bundle would interact with the framework.

The overall process follows a repetitive cycle of updates and installs, followed by a refresh operation. Each time the refresh operation is called, the framework can provide an accurate view of the future. The update manager may then either commit the changes, abort them, or start a new batch of updates, installs, and removals. The refresh operation allows to batch changes, making it less costly to compute an accurate future state. However, the algorithm to resolve bundles is incremental and efficient. We believe the implementation can be further optimized.

Eclipse Registry

The Eclipse Registry is fully functional. The notions of "require" and "runtime" in the plugin manifest are gone. The registry totally relies on the OSGi layer for resolving plugins, all pre-requisites being expressed as imports/exports of Java packages. The Eclipse registry listen to administrative events from the OSGi layer. When a bundle is resolved, the Eclipse registry checks to see if this bundle is a plugin or a fragment (presence of a resource named plugin.xml or fragment.xml). If there is, the plugin or fragment is dynamicall added to the registry, that is, its extensions and extension points are added.

The registry dynamically matches extensions and extension points, providing the corresponding events to plugins, notifying them about extensions appearing or disappearing. Events about extensions are notification sent to the plugin object which has declared their matching extension point. Similarily, events about extension points presence are sent to the plugin objects declaring extensions for those extension points. The functionality is complete but the notification mechanism in place may need some optimizations, grouping events for the same plugin—like deltas for the resource plugin.

One major decision was to decide to keep the current Eclipse restriction on extension point names, prefixed by the plugin name in which they are declared. We decided not to. The name space for extension points is therefore separated from the name space for plugins. This has been one of the core decision from the start—following the well-pattern of independence between API and implementation. Eclipse promotes such a pattern at a programming level, that is, it promotes separating a plugin API from the implementation. However, from an application integrator point of view, Eclipse promotes pre-requisites between plugins, not on plugin APIs. Hence, Eclipse does not allow one plugin to be API compatible with another plugin. We decided to adopt the OSGi philosophy for extension points, providing a generic mechanism that could be constrained through permissions. Although the permission details are not worked out yet, the idea would be to add permissions to define extension points like we have for registering services, thereby allowing an application integrator to prevent uncontrolled replacement of plugins by other compatible ones.

Fundamentally, this is to recognize that the plugin-level dependencies are a question of configuration for integrator and administrator, not for developers. From a developer point of view, plugins only need to express their dependencies in terms of programming concepts: Java packages, services, extension points. The overall RCP then provides the right mechanisms for integrator or administrator to control the overall configuration, in particular, which plugins are used by which applications. The key issue here is allowing controlled replacement.

Another major design decision was about virtualizing the Eclipse registry. At an OSGi layer, the install/update process is a two-phase process, allowing to fully introspect the future status of the platform before committing to changes. We believe that the Eclipse registry is part of that process, that is, some update policies may want to introspect the future state of the Eclipse registry as well before deciding on the fate of the changes. For instance, a policy may require certain extension points to be present for an application to be meaningfull.

Another decision was to allow for dynamic creation of extensions and extension points. With services, a component can usually declare or revoke services dynamically. However, a plugin cannot dynamically declare or revoke extensions or extension points. With a static registry, the rationale is obvious. But with a dynamic registry, this seems to be adding much power to the environment without adding complexity in the platform design or implementation.

Workbench

Above the Eclipse Registry, we have modified the UI plugins providing a dynanic Workbench, which reacts to extensions appearing or disappearing. We actually only had to modify two plugins:

  • org.eclipse.ui.workbench
  • org.eclipse.ui.views
All extension points in the UI plugin are now dynamic. The approach taken was simple but effective: considering partial shutdown. The Workbench already had the ability to save its state when Eclipse shutdowns, in order to be able to recreate the full UI upon restart (perspectives, views, actionSets, and so forth). We have fragmented the process to work at an extension level. So plugins can be updated seamlessly from a Workbench point of view. For instance, enough information is saved about the impacted perspectives, views, action sets so that they can be automatically recreated once the update is done.

Programming Model Impacts

Evolving from a tool platform towards a Rich Client Platform has impacts on the programming model of Eclipse. While maintaining backward compatibility as much as possible is important, a sound foundation to move forward is paramount. So far, we have identified the following areas of impacts:

  • Robustness and the usage of threads or class loaders
  • Services
  • Plugin resource access, metadata, and preferences
  • Extension lifecycle
  • Security

Robustness is more of a concern for a Rich Client Platform where applications are dynamically installed, updated, or removed. Stronger robustness seems to suggest to hide access to class loaders and threads. Direct access to either class loaders or threads from a bundle code could interfere with the ability for the OSGi framework to manage bundles in a robust maner. Furthermore, OSGi makes no guarantee that a bundle is supported by a single classloader.

Of course, the functionality is needed and should be encapsulated by the OSGi framework. In particular, the Bundle object needs to support full access to class and resource loading. These are minor extensions to OSGi. Also, the BundleContext needs to support finding the bundle of an object. The bundle of an object is defined as the bundle which loaded the object's class. A few plugins require this functionality to reach the IPluginDescriptor object. This further suggests to have a link from an OSGi bundle to the plugin object, which knows its plugin descriptor.

Multi-threading is a delicate issue, because threads are roots of persistence for the garbage collector as well as hard to manage properly. Interactions between threads and libraries are always delicate. For instance, typical examples are SWT or RMI. When considering user authentification, it may interact with certain libraries or the hosting environment. A typical example is the use of JDBC. The idea is to hide threads but to provide adequate support for batching operations as well as a concept similar to thread-local storage. A strict control on threads enable the platform to actually be able to kill bundles. Also, it allows for pooling threads, avoiding trashing the system—managing authentication issues properly.

We are still working on the details. But this support needs to be integrated with the current IPlatformRunnable, providing a centralized handling and logging of exceptions. Also, it needs to be integrated with the IWorkbenchRunnable support that is proposed for backgrounding processing in Eclipse 3.0.

The next issue is the availability of services. Services are not in competition with extension points and extensions, on the contrary, they are very complementary programming patterns. It will be interesting to see how each will be used.

The next issues relate to plugin resource access, metadata, and preferences. The presence of OSGi has major impacts in these area. First, bundle contents is encapsulated, no more direct file-based access to a plugin contents. A bundle contents can only be accessed through platform URLs and a special API, probably based on visitors. Second, metadata can no longer be supported through the meta-area of Eclipse. OSGi provides private bundle data area, which should be leveraged. Same for preferences, OSGi provides services for user and preference management.

The next important issue is certainly the necessary changes in the plugin registry API. The plugin registry API is not secure today and allows access to the internals of the registry. Fortunately, we believe that very few plugins actually depend on this kind of access. We are expecting the core API (IPluginRegistry, IPluginDescriptor, and the like) to be changed minimally.

A corollary issue is the lifecyle of extensions. Indeed, plugins which provide extension points have to react to extensions dynamically appearing or disappearing. For plugins which provide extensions, a strict approach to shutdown and cleanup is necessary. Indeed, when a plugin is updated or removed, it is shutdown by the platform. Before it is shutdown, all its extensions are revoked on their extension points. Then, the plugin has the responsability to do a thorough cleanup, reclaiming any leaked reference on one of its objects.

For instance, a plugin providing view extensions to the Workbench. Today, a lot of care has to be given to ensure proper SWT disposal of widgets upon closing a view. Tomorrow, any extra leaked reference, such as SWT toolbars or menu items, have to be thoroughfully reclaimed in the shutdown procedure. Otherwise, proper reclaimation of the bundle class loaders will not happen, wasting primary resources but also endangering the overall robustness of the Rich Client Platform.

Summary

  • From an object to its bundle (on BundleContext)
  • The bundle activator is the plugin object
  • Resource access (already in OSGi, on Bundle)
  • Class loading (on Bundle)
  • Creation of ResourceBundle (on Bundle)
  • Access API to bundle contents (on Bundle)
  • Secure Plugin Registry API
  • Extension lifecycle events