 | Level: Introductory David Gallardo (david@gallardo.org), Software consultant
01 Dec 2002 In this article, David Gallardo shows you how to create Eclipse plug-ins using the Plug-in Development Environment's code generation wizard. You'll learn how to run and debug the plug-in in the run-time workbench and install the completed plug-in in Eclipse. David also examines issues relating to packaging plug-ins -- including maintaining version information, upgrading functionality in the form of plug-in fragments, and combining plug-ins to create complete features.
A plug-in-based architecture
The Eclipse Platform, a development framework donated to the open source community
by IBM, is notable not because of the sum of money IBM is said to have spent
developing it -- $40 million -- but rather because of what they have to show for
the expenditure: a mature, well-designed, and extensible architecture. What is valuable about Eclipse is that it provides an open source platform for creating an extensible integrated
development environment. This platform allows anyone to build tools that
integrate seamlessly with the environment and other tools.
The key to the seamless integration of tools with Eclipse is the plug-in. With the exception of a small run-time kernel, everything in Eclipse is a plug-in. This
means that a plug-in you develop integrates with Eclipse in exactly the same
way as other plug-ins; in this respect, all features are created equal.
Some plug-ins are more equal than others, however. The Workbench and the Workspace
are two indispensable plug-ins of the Eclipse Platform -- they provide the extension
points used by most of the plug-ins, as shown in Figure 1. A plug-in requires an
extension point to plug into in order to function.
Figure 1. The Eclipse Workbench and Workspace: essential plug-in support
The Workbench component contains extension points that, for example, allow your
plug-in to extend the Eclipse user interface with menu selections and toolbar
buttons, to request notification of different types of events, and to create
new views. The Workspace component contains extension points that allow you to
interact with resources, including projects and files.
The Workbench and the Workspace are not the only Eclipse components that can be
extended by other plug-ins, of course. In addition, there is a Debug component
that will let your plug-in launch a program, interact with the running program,
and handle errors -- everything necessary to build a debugger. While necessary
for certain types of applications, the Debug component is not needed by most
applications.
There is also a Team component that allows Eclipse resources to interact with version
control systems (VCS), but unless you are building an Eclipse client for a VCS,
the Team component, like the Debug component, will not have its functionality
extended or enhanced.
Finally, there is a Help component available to allow you to provide online
documentation and context-sensitive help for your application. There is no
denying that help documentation is an essential part of a professional
application, but it is not essential to a plug-in's functionality.
The extension points that each of the above components provide are documented in
the Eclipse Platform Help, in the reference section of the Platform Plug-in
Developer guide. A quick glance, particularly at the Workbench section of the
API reference is initially daunting. Rather than diving into the details of the
many available extension points, we'll just dip our feet in by taking a look at a
simple plug-in and its components.
A gentle introduction to plug-ins
The
easiest way to create a plug-in is to use the Plug-in Development Environment
(PDE). The PDE, along with the Java Development Tooling (JDT) IDE, comes as a
standard extension to Eclipse. The PDE provides wizards to help create
plug-ins, including the "Hello, world" example we will examine here.
From the Eclipse menu, select File=>New=>Other (or press Ctrl-N) and then select the Plug-in Development wizard on the left side of the Select dialog. On the right side of the Select dialog, choose Plug-in Project. Press Next. On the next screen, enter a project name; I used com.example.hello. Press Next again. On the next screen, notice that the plug-in ID corresponds to the project name. Using the project name as the plug-in ID minimizes the chances that this plug-in will conflict with the name of another plug-in. Press Next once again. The next screen gives you the choice of either manually creating the initial plug-in code or running a code generation wizard. Leave the code generation wizard default, select "Hello, World", and press Next, as shown in Figure 2.
Figure 2. Selecting the "Hello, World" code generation wizard
The next
screen requests additional information. Notice the information on this screen:
it includes the plug-in name, version number, provider name, and class name.
These are important pieces of information about our plug-in, as we will see
later. You can accept the defaults provided by the wizard. Press Next. On the next screen, accept the defaults for
package name, class name, and message text. Leave the checkbox marked "Add
the action set to the resource perspective" checked. Press Finish.
If you are
notified that the wizard needs to enable certain other plug-ins in order to
complete, press OK.
After a
while, the wizard will complete and you will have a new project named com.example.hello in your workspace, as shown in Figure 3.
Figure 3. The PDE Perspective: Welcome to Hello Plug-in
On the
left of the workbench, in the Package Explorer, is an overview of some of the
things the wizard created. Most of the items are not very interesting: there
are a number of .jar files included in the project classpath (these include the Eclipse classes required by the plug-in and the Java run-time), an icons folder containing a graphic for a toolbar button, and a build.properties file containing variables used by an automated build script.
The most
interesting things here are the src folder, which contains the source code for our plug-in and the plugin.xml file -- the plug-in's manifest file. We will take a look at plugin.xml first.
The plug-in manifest file
The plug-in manifest file, plugin.xml, contains descriptive information that will be used by Eclipse to integrate the plug-in into the framework. By default, plugin.xml is opened in the manifest editor area when the plug-in is first created. Tabs at the bottom of the editor allow you to select different sets of information about the plug-in. The Welcome tab displays the message "Welcome to Hello Plug-In", and briefly discusses
the templates used and tips on using Eclipse to implement the plug-in.
Selecting the "Source" tab will let you see the complete source of
the plugin.xml file.
Let's take a look at the different parts of the plug-in manifest file. First, is general
information about the plug-in, including its name, version number, the name of
the class file that implements it, and the .jar file name.
Listing 1. Plug-in manifest file -- general information
<?xmlversion="1.0" encoding="UTF-8"?>
<plugin
id="com.example.hello"
name="Hello Plug-in"
version="1.0.0"
provider-name="EXAMPLE"
class="com.example.hello.HelloPlugin">
<runtime>
<library name="hello.jar"/>
</runtime>
|
Next, the plug-ins required by our plug-in are listed:
Listing 2. Plug-in manifest file -- required plug-ins
<requires>
<import plugin="org.eclipse.core.resources"/>
<import plugin="org.eclipse.ui"/>
</requires>
|
The first
plug-in listed, org.eclipse.core.resources, is the workspace plug-in, but it is not actually needed by our plug-in. The second plug-in, org.eclipse.ui, is the workbench. We need the workbench plug-in because we will be extending two of its extension points as indicated by the extension tags that follow.
The first extension tag has the point attribute org.eclipse.ui.actionSets. An action set is a group of contributions that a plug-in adds to the workbench user interface -- that is, menus, menu items, and toolbars. An action set groups contributions so that a user can more
easily manage them. For example, our Hello plug-in's menu and toolbar items
will appear in the Resource Perspective because of the choice we made when we
ran the code-generation wizard. The user can change this using the Window=>Customize
Perspective menu option to remove "Sample Action Set" from the
items to be displayed in the Resource Perspective.
Figure 4. Customizing the Resource Perspective
The action set contains two tags: a menu tag that describes where and how our item should appear in the workbench menu, and an action tag that describes what it should do -- in particular, the action tag identifies the class that performs the action. Note that this class is different than the plug-in class listed above.
Listing 3. Action set
<extension
point="org.eclipse.ui.actionSets">
<actionSet
label="Sample Action Set"
visible="true"
id="com.example.hello.actionSet">
<menu
label="Sample &Menu"
id="sampleMenu">
<separator
name="sampleGroup">
</separator>
</menu>
<action
label="&Sample Action"
icon="icons/sample.gif"
class="com.example.hello.actions.SampleAction"
tooltip="Hello, Eclipse world"
menubarPath="sampleMenu/sampleGroup"
toolbarPath="sampleGroup"
id="com.example.hello.actions.SampleAction">
</action>
</actionSet>
</extension>
|
The purpose of many of the menu and action attributes is fairly obvious -- for
example, providing the tooltip text and identifying the graphic for the toolbar
item. Also notice the menubarPath in the action tag: This attribute identifies
which menu item defined in the menu tag invokes the action defined in the
action tag. For more detailed information about this and other workbench
extension points, refer to the Platform Plug-in Developer Guide, particularly
the "Plugging into the workbench" chapter (the guide is available from the
help menu in Eclipse).
The second extension tag was generated as a result of
our electing to have our plug-in added to the Resource Perspective. This tag
causes our plug-in to be added to the Resource Perspective when Eclipse first
starts and loads our plug-in:
Listing 4. Extension tag
<extension
point="org.eclipse.ui.perspectiveExtensions">
<perspectiveExtension
targetID="org.eclipse.ui.resourcePerspective">
<actionSet
id="com.example.hello.actionSet">
</actionSet>
</perspectiveExtension>
</extension>
</plugin>
|
If this last extension had been omitted, the user would need
to add the plug-in to the Resource (or other) Perspective using Window=>Customize
Perspective.
The plug-in source code
The code generation wizard generated two Java source files, which you can see by opening
the src folder in the PDE package explorer. The first, HelloPlugin.java is the plug-in class, and extends the AbstractUIPlugin abstract class. HelloPlugin is responsible for managing the lifecycle of the plug-in and, in a more extended application, would be responsible for maintaining such things as dialog box settings and user preferences. HelloPlugin doesn't do much:
Listing 5. HelloPlugin
packagecom.example.hello.actions;
import org.eclipse.ui.plugin.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.resources.*;
import java.util.*;
/**
* The main plugin class to be used in the desktop.
*/
public class HelloPlugin extends AbstractUIPlugin {
//The shared instance.
private static HelloPlugin plugin;
//Resource bundle.
private ResourceBundle resourceBundle;
/**
* The constructor.
*/
public HelloPlugin(IPluginDescriptor descriptor) {
super(descriptor);
plugin = this;
try {
resourceBundle= ResourceBundle.getBundle(
"com.example.hello.HelloPluginResources");
} catch (MissingResourceException x) {
resourceBundle = null;
}
}
/**
* Returns the shared instance.
*/
public static HelloPlugin getDefault() {
return plugin;
}
/**
* Returns the workspace instance.
*/
public static IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
/**
* Returns the string from the plugin's resource bundle,
* or 'key' if not found.
*/
public static String getResourceString(String key) {
ResourceBundle bundle= HelloPlugin.getDefault().getResourceBundle();
try {
return bundle.getString(key);
} catch (MissingResourceException e) {
return key;
}
}
/**
* Returns the plugin's resource bundle,
*/
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
}
|
The second source file, SampleAction.java, contains the class that performs the action specified in the action set in the manifest file. SampleAction implements the IWorkbenchWindowActionDelegate interface, which allows Eclipse to use a proxy for our plug-in so that Eclipse does not need to load the plug-in until absolutely necessary (this optimization works to minimize memory and performance problems when plug-ins are loaded). The IWorkbenchWindowActionDelegate interface methods allow our plug-in to interact with the proxy:
Listing 6. IWorkbenchWindowActionDelegate interface methods
package com.example.hello.actions;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.jface.dialogs.MessageDialog;
/**
* Our sample action implements workbench action delegate.
* The action proxy will be created by the workbench and
* shown in the UI. When the user tries to use the action,
* this delegate will be created and execution will be
* delegated to it.
* @see IWorkbenchWindowActionDelegate
*/
public class SampleAction implements IWorkbenchWindowActionDelegate {
private IWorkbenchWindow window;
/**
* The constructor.
*/
public SampleAction() {
}
/**
* The action has been activated. The argument of the
* method represents the 'real' action sitting
* in the workbench UI.
* @see IWorkbenchWindowActionDelegate#run
*/
public void run(IAction action) {
MessageDialog.openInformation(
window.getShell(),
"Hello Plug-in",
"Hello, Eclipse world");
}
/**
* Selection in the workbench has been changed. We
* can change the state of the 'real' action here
* if we want, but this can only happen after
* the delegate has been created.
* @see IWorkbenchWindowActionDelegate#selectionChanged
*/
public void selectionChanged(IAction action, ISelection selection) {
}
/**
* We can use this method to dispose of any system
* resources we previously allocated.
* @see IWorkbenchWindowActionDelegate#dispose
*/
public void dispose() {
}
/**
* We will cache window object in order to
* be able to provide parent shell for the message dialog.
* @see IWorkbenchWindowActionDelegate#init
*/
public void init(IWorkbenchWindow window) {
this.window = window;
}
}
|
 |
Running and debugging the plug-in
When developing a plug-in for Eclipse, it would be awkward to have to stop Eclipse and
then re-start it with the new plug-in in order to test and debug. Eclipse's
PDE, thankfully, provides a self-hosted development environment that lets you
run a plug-in without installation in a separate instance of the workbench.
To run the
Hello plug-in, select Run=>Run As=>Run-time Workbench to start
another instance of the Workbench with our plug-in's menu selection and toolbar
added as shown in Figure 5.
Figure 5. The Hello plug-in running in the run-time workbench
We can activate the plug-in by clicking on the toolbar
button or from the "Sample Menu" menu. Either method will bring up a
box titled "Hello Plug-in" with the contents "Hello, Eclipse
world" and an OK button to dismiss it.
We can debug a plug-in in a similar way, by selecting Run=>Debug
As=>Run-time Workbench. This time we can step through the source code,
examine variables, etc., in the original workbench while the plug-in runs in
the second workbench instance.
Once our plug-in is tested and ready for release, we will need to
package it appropriately for installation in Eclipse.
Packaging the plug-in
Eclipse determines what plug-ins to load by looking in its plugins directory at startup. To install a plug-in, we need to create a subdirectory in the plugins directory and copy our program files and manifest files there. It's not necessary, but it is recommended that
the directory name indicate the plug-in's ID, followed by an underscore and the
version number. Suppose that Eclipse is installed in C:\eclipse; we might make a directory:
C:\eclipse\plugins\com.example.hello_1.0.0.
As is standard with Java applications, our program files need to be archived into a .jar file -- our plug-in manifest file, you may remember contained this entry:
<runtime>
<library name="hello.jar"/>
</runtime>
|
To create
the hello.jar file, we can export our plug-in
files by highlighting the project name, and selecting File=>Export
from the Eclipse menu. Select JAR file as the destination, press Next, and then browse to the directory we created for it. Next, we need to copy the plugin.xml file to this directory too. You can use the File=>Export menu selection as well (but remember to choose File System as the destination).
This is
all that is required to install the plug-in, but you will need to stop and
restart Eclipse for the new plug-in to be recognized. You can find information
about the installed plug-ins, including version number, by selecting "About
Eclipse Platform" from the help menu. One of the buttons on the screen
that appears will be Plug-in Details; scroll down the list to find the Hello
plug-in and its version number.
Updating the plug-in version
The purpose of including the version number in the directory name is to allow
multiple versions of a plug-in to co-exist on the same machine (only one is
loaded at a time). We can see how this works by creating an updated version of
the Hello plug-in: for example, change the version number in the plugin.xml file to "1.0.1", and change the text in SampleAction.java to "New and improved Hello, Eclipse world".
Select Project=> Rebuild All from the Eclipse
menu. Next, export the project files as a JAR to a new plug-in directory, for
example, com.example.hello_1.0.1. Copy the revised plugin.xml file to the same directory. When you stop and restart Eclipse, only the updated plug-in will be loaded.
Plug-in fragments and features
Eclipse is
composed of plug-ins, but there are two other levels of components that are
important to consider when developing plug-ins for Eclipse -- plug-in fragments and features.
A plug-in fragment,
as the name suggests, forms a part of a full-fledged plug-in -- the target
plug-in. The functionality provided by the fragment is merged with that of the
target plug-in. A fragment can be used to localize a plug-in for different
languages, to incrementally add features to an existing plug-in without the
need for a full new release, or to provide platform-specific functionality. In
many respects a fragment is identical to a plug-in. The main difference is that
a fragment does not have a plug-in class -- the fragment's life cycle is managed
by its target plug-in. In addition, the fragment's manifest file, called fragment.xml, lists the target plug-in's ID and version number as well as the fragment's ID and version number.
A plug-in feature,
on the other hand, does not include coding at all. In Eclipse architecture terminology, a feature is the packaging of a group of related plug-ins into an integral product. For example, the JDT is a feature made up of plug-ins like a Java editor, debugger, and console. A manifest file called feature.xml describes a feature archive. Among other things, this manifest file includes references to the plug-ins and other resources that the feature comprises, information on how the feature is to be updated, copyright information, and license information.
In Eclipse a primary feature sets the look and feel of the
Eclipse Platform. The primary feature is expected to determine things like the
splash screen and other characteristics that give Eclipse its identity. Eclipse
allows only one primary feature. In this way -- by creating a set of plug-ins,
packaging them into a feature, and making this feature the primary
feature -- Eclipse can be re-branded and used to create an entirely new and
different product. As downloaded from Eclipse.org, the default primary feature
is eclipse.org.platform.
Next steps
This introduction to plug-ins necessarily
covers very little of what can be done with a plug-in. The best resource for learning
more about plug-ins is the Plug-in Developer's Guide that is available from the
help menu in Eclipse. The documentation includes a programming guide, a
reference to the Eclipse API and the plug-in extension points, a guide to the
programming examples available from Eclipse.org, and a list of frequently asked
questions. Another excellent resource is the source code for Eclipse
itself. Depending on your interests, you may wish to find examples of
how different workbench features such as views and editors are extended, or how
the SWT (the Eclipse graphics API) is used. In addition, the Resources below can help you learn more.
Resources
- Documentation, articles, and downloads of Eclipse are
available from the Eclipse Project Web site.
- Browse a complete list of plug-ins for Eclipse.
- You can also get more information about plug-ins in French.
- Learn more about Eclipse in these developerWorks articles:
- "Getting started with the Eclipse Platform", also by David Gallardo (developerWorks, November 2002)
- "Plug a Swing-based development tool into Eclipse" (developerWorks, October 2002)
- "Internationalizing your Eclipse plug-in" (developerWorks, June 2002)
- "Testing your internationalized Eclipse plug-in" (developerWorks, July 2002)
- "Working XML: Use Eclipse to build a user interface for XM" (developerWorks, October 2002)
- "Interview with Marc Erikson about the Eclipse code donation" (developerWorks, November 2001)
- "Working the Eclipse Platform" (developerWorks, November 2001)
- "Getting to know WebSphere Studio Application Developer" (developerWorks, November 2001)
- "Help for reusing your assets" (developerWorks, November 2001)
- For more details on plug-in development, see the articles on the Eclipse.org site.
- Find the resources you need in the Open source projects zone and the Java technology zone on developerWorks.
About the author  | |  | David Gallardo is an independent software consultant and author specializing in software internationalization, Java Web applications, and database development. He has been a professional software engineer for over fifteen years and has experience with many operating systems, programming languages, and network protocols. His recent experience includes leading database and internationalization development at a business-to-business e-commerce company, TradeAccess, Inc. Prior to that, he was a senior engineer in the International Product Development group at Lotus Development Corporation where he contributed to the development of a cross-platform library providing Unicode and international language support for Lotus products including Domino. You can reach David at david@gallardo.org. |
Rate this page
|  |