Summary
This is a draft document.
This document details the steps required to adopt the new mechanisms found in the Eclipse 3.0 runtime. In most cases, plug-in developers do not need to follow these steps as the 3.0 runtime supports the 2.1-style API. However, the new runtime offers significant new experimental function. It is this function which is detailed here.
By Jeff McAffer, IBM OTI Labs
January 27, 2004
Preamble
In this document the terms deprecated and obsolete are used to mean that the code is not part of the Eclipse runtime story going forward. For Eclipse 3.0 this code is still a full-fledged member of the API and is fully supported.
The new runtime is 99% binary compatible with the original Eclipse runtime. That is, with the exception of the cases listed above, most existing plug-ins will continue to run unchanged.
Having said that, there are costs associated with the compatibilty layer and the full power of the new runtime is not available to legacy plug-ins. Plug-in developers interested in additional performance and function should consider adopting the new APIs and removing their dependence on the compatibility layer. Compatibility code shows up in three places:
- org.eclipse.core.boot - entire plug-in are legacy
- org.eclipse.core.runtime.compatibility - entire plug-in are legacy
- org.eclipse.core.runtime - various classes and methods are legacy
The text below gives more detail on the which classes and methods are present for compatibility purposes as well as guidance on how to update your plug-in should you choose to.
Plug-ins and bundles
The Eclipse runtime has been refactored into two parts; classloading and prerequisite management, and extension/extension-point management. This split allows for natural/seamless adoption of the OSGi framework specification for classloading and prerequisite management. This in turn enables a range of new capabilities in the runtime from dynamic plug-in install/update/uninstall to security and increased configurability.
While we continue to talk about plug-ins, in the new runtime a plug-in is really a bundle plus some extensions and extension-points. The term bundle is defined by the OSGi framework specification and refers to a collection of types and resources and associated inter-bundle prerequisite information. The extension registry (and related types) is the new form of the plug-in registry (and related types) and details only extension and extension-point information. By-in-large the extension registry API is the same as the relevant plug-in registry API (for more information see Registries).
In the Eclipse 2.x runtime, the plug-in object has a number of roles and responsibilities:
- Lifecycle - The Plugin class implements method such as startup() and shutdown(). The runtime uses these methods to signal the plug-in that someone is interested in the function it provides. In response, plug-ins typically do a combination of:
- Registration - Hook various event mechanisms (e.g., register listeners) and otherwise make their presence known in the system (e.g., start needed threads).
- Initialization - Initialize or prime their data structures and load models so they are ready for use.
- Plug-in global data/function - While never explicitly put forth for this role, in common practice plug-in classes have become a place to hang data and function which is effectively global to the plug-in itself. In some cases this data/function is API in others it is internal. For example, the UI plug-in exposes as API methods such as getDialogSettings() and getWorkbench().
- Context - The standard Plugin class provides access to various runtime-provided function such as preferences and logging.
In the Eclipse 3.0 runtime picture, these roles and responsibilities are factored into distinct objects.
-
Bundle
- Bundles are the OSGi unit of modularity. There is one classloader per bundle and Eclipse-like inter-bundle class loading dependency graphs can be constructed. Bundles have lifecycle for start and stop and the OSGi framework broadcasts bundle related events (e.g., install, resolve, start, stop, uninstall, ...) to interested parties. Unlike the Eclipse Plugin class, the OSGi Bundle class is not extensible. That is, developers do not have the opportunity to define their own bundle class.
-
BundleActivator
- BundleActivator is an interface defined by the OSGi framework. Each bundle can define a bundle activator class much like a plug-in can define its Plugin class. This class is instantiated by the framework and used to implement the start() and stop() lifecycle processing. There is a major difference however in the nature of this lifecycle processing. In Eclipse it is common (though not recommended) to have the Plugin classes do both initialization and registration. In OSGi activators must only do registration. Doing large amounts of initialization (or any other work) in BundleActivator.start() threatens the liveness of the system.
-
BundleContext
- BundleContexts are the OSGi mechanism for exposing general system function to individual bundles. Each bundle has a unique and private instance of BundleContext which they can use to access system function (e.g., getBundles() to discover all bundles in the system).
-
Plugin
- The new Plugin is very much like the original Eclipse Plugin class with the following exceptions: Plugin objects are no longer a) required or b) managed by the runtime and various methods have been deprecated (see below). As such, Plugin continues to provide context access. It is essentially a convenience mechanism providing a host of useful function and mechanisms but is no longer absolutely required. Much of the function provided there is also available on the Platform class in the runtime.
Plugin also implements BundleActivator. This recognizes the convenience of having one central object representing the lifecycle and semantic of a plug-in. Note that this does not however sanction the eager initialization of data structures that is common in plug-ins today. We cannot stress enough that plug-ins can be activated because a somewhat peripheral class was referenced during verification of a class in some other plug-in. That is, just because your plug-in has been activated does not necessarily mean that its function is needed. Note also that you are free to define a different BundleActivator class or not have a bundle activator at all.
The steps required to port a 2.x Plugin class to Eclipse 3.0 depends on what the class is doing. As outlined above, most startup lifecycle work falls into one of the following categories:
-
Initialization
- Datastructure and model initialization is quite often done in Plugin.startup(). The natural/obvious mapping would be to do this work in a BundleActivator.start(), that is to leave the function on Plugin. This is strongly discouraged. As with 2.x plug-ins, 3.0 plug-ins/bundles may be started for many different reasons in many different circumstances.
An actual example from Eclipse 2.0 days illuminates this case. There was a plug-in which initialized a large model requiring the loading of some 11MB of code and many megabytes of data. There were quite common usecases where this plug-in was activated to discover if the project icon presented in the navigator should be decorated with a particular markup. This test did not require any of the initialization done in startup() but yet all users, in all usecases had to pay the memory and time penalty for this eager initialization.
The alternative approach is to do such initialization in a classic lazy style. For example, rather than having models initialized when the plug-in/bundle is activated, do it when they are actually needed (e.g., in a centralized model accessor method). For many usecases this will amount to nearly the same point in time but for other scenarios this approach will defer initialization (perhaps indefinitely). We recommend taking time while porting 2.1 plug-ins to reconsider the initialization strategy used.
-
Registration
- Plug-in startup is a convenient time to register listeners, services etc. and start background processing threads (e.g., listening on a socket). Plugin.start() may a reasonable place to do this work. It may also make sense to defer until some other trigger (e.g., the use of a particular function or data element).
-
Plug-in global data
- Your Plugin class can continue to play this role. The main issue is that Plugin objects are no longer globally accessible via a system-managed list. In Eclipse 2.x you could discover any plug-in's Plugin ojbect via the plug-in registry. This is no longer possible. In most circumstances this type of access is not required. Plugins accessed via the registry are more typically used as generic Plugins rather than calling domain-specific methods.
Registries and the plug-in model
In the new runtime there is a separation between the information and structures needed to execute a plug-in and that related to a plug-in's extensions and extension points. The former is defined and managed by the OSGi framework specification. The latter are Eclipse-specific concepts and are added by they Eclipse runtime code. Accordingly, the original plug-in registy and related objects have been split into OSGi bundles and the Eclipse extension registry.
The parts of IPluginRegistry dealing with execution specification (e.g., IPluginDescriptor, ILibrary, IPrequisite) have been deprecated and the remaining parts related to extensions and extension point have been moved to IExtensionRegistry. Further, the so-called model objects related to the plug-in registry as a whole are now deprecated. These types were presented and instantiated by the runtime primarily to support tooling such as PDE. Unfortunately, it was frequently the case that the level of information needed exceeded the runtime's capabilities or interests (e.g., remembering line numbers for plugin.xml elements) and in the end, the potential consumers of the runtime's information had to maintain their own structures anyway.
In the new runtime we have re-evaluated the facilities provided by the runtime and now provide only those which are either essential for runtime execution or are extraordinarily difficult for others to do. As mentioned above, the plug-in registry model objects have been deprecated as has the plug-in parsing API. The new extensions registry maintains the essential extension-related information. A new state (see org.eclipse.osgi.service.resolver.State and friends) structure represents and allows the manipulation of the essential execution-related information.
Legacy code
org.eclipse.core.boot.BootLoader (class)
BootLoader has been completely deprecated and merged with org.eclipse.core.runtime.Platform since it no longer made sense to have a split between boot and runtime. Note that in fact, the org.eclipse.core.boot plug-in has been broken up and all its code moved to either the new runtime or the compatibility layer.
org.eclipse.core.boot.IPlatformConfiguration (class)
IPlatformConfiguration has always been a type defined by and for the Ecliipse Install/Update component. With the reorganization of the runtime we are able to repatriate this type to its rightful home. This class remains largely unchanged and has been repackaged as org.eclipse.update.configurator.IPlatformConfiguration. The compatibility layer retains a deprecated copy of the original class.
org.eclipse.core.boot.IPlatformRunnable (class)
This class has been deprecated in favour of the identical class org.eclipse.core.runtime.IPlatformRunnable. The was the last remaining use of "boot" in the API and was confusing for people.
org.eclipse.core.runtime.IExtension
org.eclipse.core.runtime.IExtensionPoint (methods)
- getDeclaringPlugin()
- This method (on both classes) gives an upward link to the plug-in which declares the extension or extension-point (respectively). The new registry model separates the execution aspects of plug-ins from the extension/extension-point aspects and no longer contains IPluginDescriptors. Users of this API should consider the new method getParentIdentifier() found on both IExtension and IExtensionPoint. The returned value can be used directly or as a key in the compatibility IPluginRegistry or the OSGi framework's API for bundle discovery (e.g., BundleContext.getBundles(String) <XXX point to the Platofrm method>).
org.eclipse.core.runtime.ILibrary (class)
In the original runtime, ILibrary is a representation of execution related attributes. In the new runtime these are now handled by OSGi. While it is possible to maintain some of the API for legacy plug-ins, it is not possible to do so for OSGi-based plug-ins/bundles. Users of ILibrary should consider using Bundle.getHeader(Constants.BUNDLE_CLASSPATH) and processing the results using the ManifestElement helper class.
org.eclipse.core.runtime.IPrerequisite (class)
In the original runtime, IPrerequisite is a representation of execution related attributes. In the new runtime these are now handled by OSGi. While it is possible to maintain some of the API for legacy plug-ins, it is not possible to do so for OSGi-based plug-ins/bundles. Users of IPrerequiste should consider using Bundle.getHeader(Constants.IMPORT_PACKAGE) or Bundle.getHeader(Constants.REQUIRE_BUNDLE) and processing the results using the ManifestElement helper class.
org.eclipse.core.runtime.Platform (methods)
- getPlugin(String)
- In the new runtime, Plugin objects are no longer managed by the runtime and so cannot be accessed via this method. Use <XXX tentative> Platform.getBundle(String) instead. Note however that this returns only a generic Bundle object. Those wishing to use domain-specific function on a particular Plugin object must arrange for access with the plug-in in question. This is typically done via a singleton pattern (e.g., ResourcesPlugin.getDefault()).
- getPluginRegistry()
- The plug-in registry object has been deprecated. If you are looking for the registry of extensions and extension points use Platform.getExtensionRegistry(). If you are looking to find the static and generic representation of a plug-in, consider using <XXX tentative> Platform.getBundle(String).
org.eclipse.core.runtime.Plugin (methods)
- Plugin(IPluginDescriptor)
- The Plugin object is no longer created or managed by the runtime and IPluginDescriptor is deprecated. Plugin class implementors may choose to use their Plugin as a bundle activator in which case they must implement (allow for) the default constructor. Users wishing to have a Plugin class but not use it as the bundle activator need to implement the appropriate constructor which at a minimum takes the BundleContext to be associated with the plug-in.
- getPluginDescriptor()
- IPluginDescriptor is now deprecated. Users of this method are looking for
- extension/extension point information: go directly to org.eclipse.core.runtime.IExtensionRegistry
- manifest information: get the bundle for the plug-in (getBundle()) and access its manifest headers as required.
- getPluginPreferences()
- <xxx the preference mechanism is still in play>
- savePluginPreferences()
- <xxx the preference mechanism is still in play>
- initializeDefaultPluginPreferences()
- <xxx the preference mechanism is still in play>
- shutdown() and startup()
- These methods have been replaced with the OSGi standard start() and stop() methods. Note that the new lifecycle methods are only automatically called if the defining Plugin class is registered as the bundle activator in a bundle manifest (MANIFEST.MF) file. See the header Bundle-Activator.
- OSGi (and Eclipse) coding practices strongly recommend against doing or triggering significant work in the start() methods. Doing excessive work here can damage startup time as well as overall responsiveness.
org.eclipse.core.runtime.IPluginDescriptor (class)
Plug-in descriptors contain methods for a number of different purposes. These are outlined below as well as the steps for updating their uses.
- extension-related (e.g., getExtensions())
- Update such cases to use the IExtensionRegistry directly.
- execution-related (e.g., find() and getPluginClassLoader())
- Use the related methods found on org.eclipse.core.runtime.Platform
- accessors (e.g., getLabel())
- Get the bundle associated with the descriptor and access the appropriate manifest header fields.
org.eclipse.core.runtime.IPluginRegistry (class)
The contents of the plug-in registry, like the runtime, has been split into two parts, the execution-related and the extension-related. As such, the unified notion of a plug-in registry does not apply. Uses of the IPluginRegistry to discover extensions and extension-points are directly supported by nearly identical API on IExtensionRegistry. Uses of IPluginRegistry to discover IPluginDescriptors should be changed to use the appropriate OSGi structures. See the discussion related to IPluginDescriptor for more details.
org.eclipse.core.runtime.model (package)
All types in this package are now deprecated. See the discussion on registries for more information.
Updating plugin/fragment files
The new runtime is based on an implementation of the OSGi framework specification. The OSGi specification mandates the use of MANIFEST.MF files to define the execution of a plug-in. This conflicts with the Eclipse notion of plugin.xml as far as <runtime> and <requires> elements are concerned. The easiest way to update your plugin.xml or fragment.xml is to use the PDE Migration Tool (PDE Tools->Convert to OSGi bundle).
In certain situations the conversion tool is unable to correctly determine all of the packages provided by a plug-in. In particular, if a plug-in declares a library entry for say foo.jar but does not contain foo.jar, the converter is unable to generate the appropriate provides-package entries in the output manifest (this is done by analyzing the supplied jar which, in this case, is not present). Plug-in or fragments which are fully self-contained are converted correctly.
This tool extracts the execution-specific information from your plugin.xml and puts into the OSGi mandated META-INF/MANIFEST.MF file. All extension-related information is left in the plugin.xml. The manifest is a standard Java Jar file manifest. It contains specifications for the execution elements of our plug-in (e.g., classpath, prerequisites, ...). A table of frequent mapping is included below while the full OSGi specification has enumerates all pre-defined manifest headers.
plugin.xml tag/attribute | manifest.mf header |
<plugin id=> | Bundle-GlobalName |
<plugin version=> | Bundle-Version |
<plugin name=> | Bundle-Name |
<plugin provider=> | Bundle-Vendor |
<plugin class=> | Bundle-Activator |
<requires>, <import> | Require-Bundle |
<runtime>, <library> | Bundle-ClassPath |
The extension/extension-point related information continues to be detailed in the plugin.xml file however the following aspects of the plugin.xml DTD are being deprecated.
- all attributes on the <plugin> tag
- <runtime> and its <library> subelement
- <requires> and its <import> subelement
This leaves the plugin.xml containing only the <plugin>, <extension> and <extension-point> tags
Note also that the form of this content is not specific to a plug-ins vs. fragments. As a result, the fragment.xml file is being deprecated and renamed to plugin.xml with the outlined DTD changes. In most cases fragments do not supply extensions or extension-points so the bulk of the change required is done while moving to the MANIFEST.MF file and the fragment.xml file can be deleted.
The plugin.properties file continues to supply translations for the extension/extension-point information in plugin.xml and also supplies translations for various keys in the MANIFEST.MF.
The build.properties file remains unchanged.
from: http://dev.eclipse.org/viewcvs/index.cgi/platform-core-home/runtime/adoption.html?rev=1.5