The following is tip #3 from "Developing Eclipse plug-ins for Lotus Notes and Domino -- 7 tips in 7 minutes," excerpted from Chapter 3 of the book Eclipse: Building Commercial Quality Plug-ins, published by Addison-Wesley Publishing.
As stated earlier, there are two files -- MANIFEST.MF and plugin.xml -- per plug-in defining various high-level aspects so that the plug-in does not have to load until you need its functionality. The format and content for these files can be found in the Eclipse help facility accessed by Help -> Help Contents; look under Platform Plug-in Developer Guide -> Reference -> Other Reference Information -> OSGi Bundle Manifest and Plug-in Manifest.
Note: What is OSGi?
Eclipse originally used a home-grown runtime model/mechanism that was designed and implemented specifically for Eclipse. This was good because it was highly optimized and tailored to Eclipse, but less than optimal because there are many complicated issues, and having a unique runtime mechanism prevented reusing the work done in other areas (e.g., OSGi, Avalon, JMX, etc.). As of Eclipse 3.0, a new runtime layer was introduced based upon technology from the OSGi Alliance (www.osgi.org) that has a strong specification, a good component model, supports dynamic behaviour, and is reasonably similar to the original Eclipse runtime. With each new release of Eclipse, the Eclipse runtime API and implementation (e.g. "plug-ins") continues to align itself more and more closely with the OSGi runtime model (e.g. "bundles").
Within each bundle manifest, there are entries for name, identifier, version, plug-in class, and provider.
Bundle-Name: Favorites Plug-in Bundle-SymbolicName: com.qualityeclipse.favorites; singleton:=true Bundle-Version: 1.0.0 Bundle-Activator: com.qualityeclipse.favorites.FavoritesPlugin Bundle-Vendor: Quality Eclipse
Strings in the plug-in manifest, such as the plug-in name, can be moved into a separate plugin.properties file. This process facilitates internationalization.
The plug-in identifier ( Bundle-SymbolicName) is designed to uniquely identify the plug-in and is typically constructed using Java package naming conventions (e.g., com.<companyName>.<productName>, or in our case, com.quality-eclipse.favorites). If several plug-ins are all part of the same product, then each plug-in name can have four or even five parts to it as in com.quality-eclipse.favorites.core and com.qualityeclipse.favorites.ui.
Every plug-in specifies its version ( Bundle-Version) using three numbers separated by periods. The first number indicates the major version number, the second indicates the minor version number, and the third indicates the service level, as in 1.0.0. You can specify an optional qualifier that can include alphanumeric characters as in 1.0.0.beta_1 or 188.8.131.526-03-20 (no whitespace). Eclipse does not use or interpret this optional qualifier in any way, so the product builder can use it to encode the build type, build date, or other useful information.
Tip: For an outline of the current use of version numbers and a proposed guideline for using plug-in version numbering to better indicate levels of compatibility, see eclipse.org/equinox/documents/plugin-versioning.html.
Plug-in name and provider
Both the name and the provider are human-readable text, so they can be anything and are not required to be unique. To see the names, versions, and providers of the currently installed plug-ins, select Help -> About Eclipse SDK to open the About dialog.
Figure 3: The About Eclipse SDK dialog
The About Eclipse SDK dialog, showing information about the Eclipse platform.
Figure 4: The About Eclipse SDK Plug-ins dialog
The About Eclipse SDK Plug-ins dialog, showing all the installed plug-ins with the Favorites plug-in highlighted at the bottom.
Plug-in class declaration
Optionally, every plug-in can specify a plug-in class ( Bundle-Activator) as the Favorites plug-in does).
The Bundle-ClassPath declaration in the MANIFEST.MF file is a comma separated list describing which libraries (*.jar files) contain the plug-in code. The Export-Package declaration is a comma-separated list indicating which packages within those libraries are accessible to other plug-ins.
Bundle-ClassPath: favorites.jar Export-Package: com.qualityeclipse. favorites.views
Tip: When delivering your plug-in as a single JAR, the Bundle-ClassPath declaration should be empty so that Eclipse looks for classes in the plug-in JAR and not in a JAR inside your plug-in.
The plug-in loader instantiates a separate class loader for each loaded plug-in, and uses the Require-Bundle declaration of the manifest to determine which other plug-ins—thus which classes—will be visible to that plug-in during execution.
Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime
If a plug-in has been successfully compiled and built but, during execution, throws a NoClassDefFoundError , it may indicate that the plug-in project's Java classpath is out of sync with the Require-Bundle declaration in the MANIFEST.MF file. It is important to keep the classpath and the Require-Bundle declaration in sync.
When the plug-in loader is about to load a plug-in, it scans the Require-Bundle declaration of a dependent plug-in and locates all the required plug-ins. If a required plug-in is not available, then the plug-in loader throws an exception, generating an entry in the log file (Logging) and does not load the dependent plug-in. When a plug-in gathers the list of plug-ins that extend an extension point it defines, it will not see any disabled plug-ins. In this circumstance, no exception or log entry will be generated for the disabled plug-ins.
If a plug-in can successfully execute without a required plug-in, then that required plug-in can be marked as optional in the plug-in manifest. To do so, open the plug-in manifest editor and then switch to the Dependencies tab. Select the required plug-in, click the Properties button and then check the Optional checkbox in the Properties dialog (See Figure 5.).
Figure 5: The required plug-in properties dialog.
Making this change in the plug-in manifest editor appends ;resolution:=optional to the required plug-in in the Require-Bundle declaration so that it now looks something like this:
Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime; resolution:=optional
If your plug-in requires not just any version of another plug-in, you can specify an exact version or a range of versions using the required plug-in properties dialog (The required plug-in properties dialog.). The following are some examples:
- [3.0.0.test,3.0.0.test] - requires a specific version
- [3.0.0,3.0.1) - requires version 3.0.0.x
- [3.0.0,3.1.0)—requires version 3.0.x
- [3.0.0,3.2.0)—requires version 3.0.x or 3.1.x
- Α.0.0,4.0.0)—requires version 3.x
- [3.0.0—requires version 3.0.0 or greater
The general syntax for a range is:
[floor , ceiling )
where floor is the minimum version and ceiling is the maximum version. The first character can be [ or ( and the last character may be ] or ) where these characters indicate the following:
- [ = floor is included in the range
- ( = floor is not included in the range
- ] = ceiling is included in the range
- ) = ceiling is not included in the range
You can specify a floor or minimum version with no extra characters indicating that your plug-in needs any version greater than or equal to the specified version. Entering one of the preceding in the required plug-in properties dialog (The required plug-in properties dialog.) modifies the Require-Bundle declaration so that it now looks something like this:
Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime;bundle-version="[3.0.0,3.1.0)"
Finally, check the Reexport this dependency checkbox (The required plug-in properties dialog.) to specify that the dependent plug-in classes are made visible (are (re)exported) to users of this plug-in. By default, dependent classes are not exported (i.e., they are not made visible).
Import-Package is similar to Require-Bundle except that Import-Package specifies names of packages that are required for execution rather than names of bundles. Using Import-Package can be thought of as specifying the service required whereas using Require-Bundle is like specifying the service provider. Import-Package makes it easier to swap out one bundle for another that provides the same service, but harder to know who is providing that service.
Extensions and extension points
A plug-in declares extension points so that other plug-ins can extend the functionality of the original plug-in in a controlled manner. This mechanism provides a layer of separation so that the original plug-in does not need to know about the existence of the extending plug-ins at the time you build the original plug-in. Plug-ins declare extension points as part of their plug-in manifest, as in the views extension point declared in the org.eclipse.ui plug-in:
<extension-point id="views" name="%ExtPoint.views" schema="schema/views.exsd"/>
You can find documentation for this extension point in the Eclipse help (select Help -> Help Contents, then in the Help dialog, select Platform Plug-in Developer Guide -> Reference -> Extension Points Reference -> Workbench -> org.eclipse.ui.views). It indicates that any plug-in using this extension point must provide the name of a class that implements the interface org. eclipse.ui.IViewPart.
Other plug-ins declare extensions to the original plug-in's functionality similar to the Favorites plug-in's view extensions. In this case, the Favorites plug-in declares a new category of views with the name Quality Eclipse and the class,
as a new type of view as follows: <extension point="org.eclipse.ui.views"> <category name="Quality Eclipse" id="com.qualityeclipse.favorites"> </category> <view name="Favorites" icon="icons/sample.gif" category="com.qualityeclipse.favorites" class= "com.qualityeclipse.favorites.views.FavoritesView" id= "com.qualityeclipse.favorites.views.FavoritesView"> </view> </extension>
Each type of extension point may require different attributes to define the extension. Typically, ID attributes take a form similar to the plug-in identifier. The category ID provides a way for the Favorites view to uniquely identify the category that contains it. The name attribute of both the category and view is human-readable text, while the icon attribute specifies a relative path from the plug-in directory to the image file associated with the view.
This approach allows Eclipse to load information about the extensions declared in various plug-ins without loading the plug-ins themselves, thus reducing the amount of time and memory required for an operation. For example, selecting the Windows -> Show View -> Other… menu opens a dialog showing all the views provided by all the plug-ins known to Eclipse. Because each type of view is declared in its plug-in's manifest, the Eclipse runtime can present a list of views to the user without actually loading each plug-in that contains the view.
Developing Eclipse plug-ins for Lotus Notes and Domino
Tip 1: The Eclipse plug-in structure for Lotus Notes and DOmino
Tip 2: The Eclipse plug-in directory for Lotus Notes and Domino
Tip 3: The Eclipse plug-in manifest for Lotus Notes and Domino
Tip 4: The Eclipse plug-in class for Lotus Notes and Domino
Tip 5: The Eclipse plug-in model for Lotus Notes and Domino
Tip 6: Eclipse logging for Lotus Notes and Domino
Tip 7: Eclipse plug-in types for Lotus Notes and Domino
This chapter is excerpted from Eclipse: Building Commercial-Quality Plug-ins, 2nd Edition, by Eric Clayberg and Dan Rubel, published by Addison-Wesley Professional in March 2006. Copyright 2006 Pearson Education Inc. ISBN: 032142672X. Reprinted with permissions, all rights reserved. Click here to see a complete Table of Contents for this book. Click here for the chapter download.
This was first published in April 2007