Power Java programming—free!

Build an open source IDE with jEdit

1 2 3 Page 2
Page 2 of 3

Other plug-ins also contribute to an XP approach. Since XP teams practice collective code ownership, you need a consistent coding standard to minimize the learning curve when looking at other team members' code. The JavaStyle plug-in can be used to format Java source files according to a single coding standard. Another XP concept is simple, self-documenting code. The JDocPlugin can be used to create HTML documentation from the Java code.

So, how might you develop with this jEdit IDE using an XP approach? Here's a prototypical scenario:

  1. Create a CVS working directory using Gruntspud to perform a CVS checkout command.
  2. Create a project for this working directory using the ProjectViewer plug-in. Import the files from the CVS working directory into the project.
  3. Modify source files to add new functionality and write JUnit tests to unit test the new feature(s).
  4. Write Javadoc comments for new application classes or methods or new JUnit tests. Generate Javadoc with the JDocPlugin and view it using the InfoViewer plug-in.
  5. Run a build for the project using the AntFarm plug-in.
  6. Run unit tests with the JUnit plug-in.
  7. If the tests fail, fix the code and repeat Steps 5 and 6.
  8. Perform a CVS update to ensure your code is in sync with the repository.
  9. Run the build and unit tests again.
  10. If all tests pass, use Gruntspud to perform a CVS commit to send your changes to the CVS repository.

jEdit extensibility: How to build a jEdit plug-in

But, what if you need features jEdit doesn't support? In my case, I wanted integrated, graphical Javadoc generation, so I developed the Javadoc plug-in. The plug-in architecture simplified this task because it provides a simple mechanism for extending jEdit to support new development requirements. You implement the jEdit Plugin API the same way for any jEdit plug-in, regardless of the application. GruntSpud, AntFarm, JUnit, Project Viewer, and the Javadoc plug-in all implement the same jEdit Plugin API. So, a step-by-step review of the Javadoc plug-in will show you how to build a jEdit plug-in. Two components play an important role in this extensibility: BeanShell and the jEdit Plugin API. BeanShell joins the plug-in to the jEdit host, and the Plugin API is the interface between jEdit and the plug-in.

BeanShell

BeanShell is an open source project developed by Pat Niemeyer as an example in his book, Learning Java. It is a small Java source interpreter written in Java that executes standard Java syntax as well as some scripting statements. It represents the glue that binds plug-ins to jEdit. The action.xml file forms the primary interface between the jEdit host and a plug-in application. The action tags contained in this file are short BeanShell scripts that execute plug-in methods. jEdit executes these BeanShell scripts when the corresponding plug-in menu items are selected.

The jEdit Plugin API

The jEdit Plugin API is a simple one, consisting of a plug-in core class (one with a name ending in Plugin) that implements four public methods of the abstract EditPlugin class: start(), stop(), createMenuItems(), and createOptionPanes(). jEdit calls these four methods at specific times, thereby creating the interface between itself and the plug-in. The start(), createMenuItems(), and createOptionPanes() methods are called when jEdit starts. The stop() method is called when jEdit exits. To implement its functionality, the plug-in core class overrides these methods with its application-specific code; otherwise, jEdit executes the empty methods in the EditPlugin class. Although the plug-in core class is not required syntactically to override any of these methods, it needs to override the createMenuItems() method to display a menu within the Plugins menu and the createOptionPanes() method to display a menu in the Global Options dialog box.

Additionally, the plug-in needs to define resources that jEdit uses to build the plug-in's user interface components. At a minimum, the plug-in needs two resources, an action file and a properties file:

  • actions.xml: this file contains a BeanShell script that executes plug-in core class methods
  • <plugin>.props: this file contains name and value properties that define the plug-in menu items and other information

If the plug-in is dockable (one that can be minimized to the top, bottom, or sides of the jEdit user interface), then the plug-in also needs to provide a dockables.xml file.

This section described jEdit Plugin API's parts; the following example shows how the parts fit together.

jEdit plug-in example: The Javadoc plug-in

The best way to explain a programming interface is by illustrating it with an example, so I'll review the Javadoc plug-in for jEdit, which displays option dialogs to collect javadoc runtime arguments and runs the javadoc command within jEdit. It is a simple plug-in that performs the following five tasks:

  1. Implements the jEdit Plugin API for communication between jEdit and the plug-in
  2. Creates option dialogs that collect the javadoc runtime arguments
  3. Invokes the Runtime.exec() method to run the javadoc command
  4. Displays javadoc output using the Console plug-in
  5. Persists the values of the javadoc command-line arguments in a file

To keep the example simple, I concentrate on the code that implements the jEdit Plugin API.

Explore The Javadoc plug-in

We begin our exploration of the Javadoc plug-in by looking at the plug-in core class, JDocPlugin.java. This class name is set by convention—when jEdit loads the plug-in, it looks for a core class with a name ending in Plugin.class.

Class JDocPlugin.java implements all four of the methods in the jEdit Plugin API as well as some other methods I discuss later. jEdit executes this class's methods at specific points in its execution.

The start() method

When jEdit starts, it executes JDocPlugin's start() method. This method performs two initialization tasks. First, it initializes name and value properties for the javadoc command-line arguments. Second, it calls the Shell class's registerShell() method to make the Console plug-in aware of the Javadoc plug-in's shell, the JDocShell class. This class executes the javadoc command using the Console plug-in's exposed methods.

The stop() method

When jEdit exits, it calls the JDocPlugin class's stop() method. This method performs two tasks: it calls the Shell class's unregisterShell() method to release the resources. Second, it calls a helper method in the JDocPlugin class to persist the properties for the javadoc command-line arguments to storage.

The createOptionPanes() method

jEdit calls the createOptionPanes() method when it creates the Global Options dialog box. The method is just a few lines of code, but the jEdit classes do a lot of work. The OptionGroup class displays multiple option panes shown as one branch in the option dialog box. The addOptionPane() method adds the option pane to the option group. Each of the separate option panes is implemented as a separate class that extends the jEdit AbstractOptionPane class. Despite the name, AbstractOptionPane is not an abstract class and implements much of the option pane's functionality. The option pane classes need to only implement a constructor, and the _init() and _save() methods. The following code in the createOptionPanes() method creates multiple option panes in the Global Options dialog for the Javadoc plug-in.

   public void createOptionPanes(OptionsDialog od) {
      OptionGroup jdocGroup = new OptionGroup("jdoc");
      jdocGroup.addOptionPane(new JDocGeneralOptionPane());
      jdocGroup.addOptionPane(new JDocVisibilityOptionPane());
      jdocGroup.addOptionPane(new JDocPathOptionPane());
      jdocGroup.addOptionPane(new JDocDirectoryOptionPane());
      jdocGroup.addOptionPane(new JDocFlagOptionPane());
      jdocGroup.addOptionPane(new JDocFormatOptionPane());
      od.addOptionGroup(jdocGroup);
   }

These option panes provide a GUI for entering the javadoc command-line arguments. Similar arguments group into separate option panes. Alternatively, a plug-in could add a single option pane to the option dialog box with the OptionsDialog()addOptionPane() method. Figure 5 shows the option pane for the path options.

Figure 5. Global Options dialog box

The createMenuItems() method

To allow users to select plug-in actions, jEdit plug-ins display a submenu within the jEdit plug-in menu. The createMenuItems() method with one argument and one line of code in its body is the most important interface between jEdit and the Javadoc plug-in. It allows jEdit to build a menu for the external plug-in component and link the menu items to dynamically executed code. The relevant code in JDocPlugin.java is as follows:

   public final static String MENU = "jdoc-menu";
   ...
   public void createMenuItems(Vector menuItems) {
       menuItems.addElement(GUIUtilities.loadMenu(MENU));
   }

jEdit calls createMenuItems() when it builds the plug-ins menu for the Javadoc plug-in. The method's argument is a vector of the installed plug-in menus. The call to the GUIUtilities.loadMenu() method creates the top-level menu for the Javadoc plug-in, which is added to this vector. The argument passed to this method is the name of the menu property in the Javadoc plug-in properties file. Every jEdit plug-in needs a property file that contains the key and value pairs for the menu item names and the menu labels that jEdit displays. The following fragment from the JDocPlugin properties file describes a submenu with three labels:

   #
   # jdoc.props application menu properties
   #
   jdoc-menu=jdoc - jdoc-help - jdoc-options
   jdoc-menu.label=Javadoc
   jdoc.label=Execute Javadoc
   jdoc-help.label=Javadoc Help
   jdoc-options.label=Javadoc Options...

This value of the jdoc-menu property contains three property names, which are the menu item properties for this plug-in menu. The dash (-) character separates the three values in the jdoc-menu property. When the plug-in's menu is selected, the item properties look up the labels for the menu items (or submenus: if a percent sign (%) precedes the item property names, jEdit builds submenus recursively).

jEdit uses the property file's item names (jdoc, jdoc-help, jdoc-options) to link to the XML action name attributes in the JDocPlugin's actions.xml file. This file contains the top-level \ <ACTIONS\> tag and three <ACTION\> tags within it for each of the three menu items. The actions.xml file for the Javadoc plug-in that follows shows how the menu item name is used to link the menu item to its action, which is a method in the JDocPlugin class:

   <!-- javadoc plugin actions.xml file -->
   <ACTIONS>
      <ACTION NAME="jdoc">
         <CODE>
            jdoc.JDocPlugin.executeJavadoc(view, "execute");
         </CODE>
      </ACTION>
      <ACTION NAME="jdoc-help">
         <CODE>
            jdoc.JDocPlugin.executeJavadoc(view, "help");
         </CODE>
      </ACTION>
      <ACTION NAME="jdoc-options">
         <CODE>
            new jdoc.options.JDocOptionDialog(view);
         </CODE>
      </ACTION>
   </ACTIONS>

During startup, when jEdit loads the plug-in, it builds an internal data structure of actions from these \<ACTION\> tags. The action names in the actions.xml file correspond to the item names in the property, establishing the link between the menu item and the action. The \<CODE\> tag within each action contains a short BeanShell script. The view variable in each method's argument is a BeanShell variable, which contains a reference to jEdit's top-level user interface component.

Each BeanShell script within the \<CODE\> tags executes a method in the plug-in core class that performs that action's work.

In the code above, the JDocOptionDialog() method displays the same option dialog box as the Global Options menu. This tabbed dialog box allows you to set all command-line arguments for the javadoc command.

The executeJavadoc() method with the execute argument runs the javadoc command using the command-line argument settings configured in the option dialog box.

The executeJavadoc() method with the help argument runs the javadoc command with the -h command-line argument and displays the javadoc help output on the jEdit console.

Supporting classes

So far, this article has concentrated on showing how the JDocPlugin class implements the jEdit Plugin API and the plug-in resources (the actions.xml file and plug-in properties file) to illustrate how to implement a jEdit plug-in. These components are similar for any jEdit plug-in. The Javadoc plug-in also contains numerous classes that perform the actual work of the plug-in, such as setting the javadoc command-line options and executing the javadoc command. The implementation of these classes depends on the function of the particular plug-in, but these classes also use some common jEdit GUI facilities. This section introduces these classes.

Option pane display

The option pane classes provide the user interface to enter plug-in options. All option pane classes encapsulate the jEdit AbstractOptionPane class. This jEdit class's name is misleading because it is not an abstract class. It extends the Swing JPanel class, implements the jEdit OptionPane interface, and provides a default framework for option pane classes. Many classes in the jdoc.options package display the option dialog boxes for the Global Options menu and the JDocPlugin Options menu.

The JDocOptionDialog class displays the dialog box with tabbed panes for the Javadoc Options menu. Figure 6 shows the Javadoc Options dialog box.

Figure 6. Javadoc Options dialog box

The JDocCommand class manages constants for all Java commands and property keys.

1 2 3 Page 2
Page 2 of 3