If you have created a plug-in project in Eclipse before, you are familiar with the established plug-in project templates, which provide a convenient starting place for new projects. The existing plug-in templates can save a lot of time, but they are not omnipotent.
A challenge to using them is finding the template that satisfies the users' requirements. But templates offer only a certain number of functions, and users' requirements are diverse and almost impossible to foresee perfectly for those who created the templates. Customizing templates is a smart way to give users the plug-ins they need without writing them from scratch.
In this article, learn:
- How to customize plug-in project template in Eclipse.
- Advanced characteristics of templates, such as multisection implementation and control, UI component customization, and validation.
- Tools to organize a project directory structure automatically.
This article is written for Java™ technology developers familiar with Eclipse and interested in building plug-ins. It assumes a basic understanding of plug-ins and Eclipse-based development tools in general. To build the example plug-ins, you need a computer with an Eclipse installation (V3.4 or later) and a current Java Runtime Environment (JRE).
The work here is based on the developerWorks article "Building templates with the Eclipse Plug-in Development Environment." If you are new to plug-in templates, we suggest you start with that article, which introduces how to create a template. Because that article is introductory, the template it presents lacks the features we offer here, which include the following.
- Multisection implementation and control
- Generally, a section of a plug-in template is defined as cohesive functional module that contains highly interdependent files established or generated based on users' input. Files under a section will either be replicated into a destination project altogether or not at all. A user can define a section as required or optional. Files under the required section must be included into a plug-in project, while those under the optional section should be copied upon choice. This is useful when a plug-in template offers a function's super-set, but a certain project only needs a subset.
- UI component customization
- Eclipse provides several default UI components for a plug-in project template. These basic UI components offer limited functions. To improve usability and functionality, we sometimes need to customize complex components.
- Input validation function
- It increases data validation control.
- Organize the directory structure of plug-in project automatically
- Resources in plug-in project can be organized into a specific directory using a template. It can save manual effort.
These extended features make a plug-in template more scalable, usable, and efficient. In the following sections, we present a sample template that uses all these features.
Sample case study: In-depth discussion on a plug-in template
Assume a group of plug-in projects are needed. They are used to construct various Eclipse perspectives, like a Java perspective and a Web perspective. One project is for one perspective development. Each perspective can have several views. Every view has relevant resources, such as image and auto-generated Java source files, need to be copied into its project. The number of views in a perspective and the name of each view are determined by the individual perspective.
Customizing a plug-in template is a good way to generate these destination projects.
To start, create a new plug-in project (File > New > Project > Plug-in Project). Be sure to select the This plug-in will make contribution to the UI checkbox. This is because destination projects in this sample are for perspective development, which will use the UI. Once the new project is created, a template wizard extension extending org.eclipse.pde.ui.plugin.Content should also be added into plugin.xml.
New feature A: Multisection implementation and control
When we look at the above case closely, we discover an issue in customizing the template. Since the number of views for each perspective is alterable, the relevant resources are unable to be generated and copied into its destination project until the number is given.
To address this issue, we consider two solutions. A common method is to create one template for each perspective category where all perspectives of identical view number are assembled. The alternative method is more efficient and advanced. A single template is created for all perspective categories. The linkage between views and perspective is managed by section control.
Add extensions for the perspective and view sections
In this sample, we separate all resources into two sections. We use the perspective section to manage perspective resources and use the view section to manage view resources. If a user wants a perspective with no views, none of the view resources will be replicated into the corresponding project. Likewise, if a user wants perspective with nine views, nine views will be registered into their perspectives, and view sources will be iteratively generated and copied into its destination project.
To generate these two sections, we need to add extensions in the Extensions tab of the Plug-in Manifest Editor.
Figure 1. Extensions tab — Perspective section
Figure 2. Extensions tab — View section
Figure 3 shows the template project structure. Five new files (SampleWizard.java, PerspectiveSection.java, ViewSection.java, $perspectiveClassName$.java, and $viewClassName$.java) are created in this sample. They constitute the main part of the project.
Figure 3. Template project structure
PerspectiveSection and ViewSection are subclasses of OptionTemplateSection, which is used to represent a section of a template wizard. They have three main functions: to create a UI for the template, to hold variables inputted from the UI, and to update the plug-in model. Table 1 shows the methods description of the section class.
Table 1. Section class methods description
| Method name | Function description |
|---|---|
| initializeFields | Initialize options on the wizard page by using input parameters. Some options may depend on the user's selection in the previous steps of the wizard. |
| addPages | Add template-related pages to the wizard. |
| getStringOption | Get the option name. |
| getSectionId | Return the section ID. |
| updateModel | Add the required entries into plug-in model. |
$perspectiveClassName$.java and $viewClassName$.java are template files that will be auto-translated into Java source files of the destination project. The template files are very simple in this sample. We just create a list for each view, then add these views into the perspective.
Next is to include section control into the wizard behavior. The SampleWizard class is a subclass of NewPluginTemplateWizard, which is used as a wizard template for the plug-in. We can allocate the specified section to the destination plug-in project via the SampleWizard class. The performFinish method inherits from the super-class. It can be used to perform special finish processing in a wizard, including looping through template sections and executing them sequentially to generate files for destination project. Listing 1 shows how sections are registered into a wizard, and the main actions in the performFinish method.
Listing 1. SampleWizard.java
//register all related sections in wizard
public ITemplateSection[] createTemplateSections() {
return new ITemplateSection[] {
new PerspectiveSection(),
new ViewSection()
};
}
public boolean performFinish(final IProject project, IPluginModelBase model,
IProgressMonitor monitor) {
...
ITemplateSection[] sections = super.getTemplateSections();
//monitor finish action in this wizard
monitor.beginTask("perform finish", sections.length);
...
//get sections
for (int i = 0; i <sections.length; i++) {
if (sections[i].getClass().equals(PerspectiveSection.class)) {
perspectiveSection = (PerspectiveSection) sections[i];
} else if (sections[i].getClass().equals(ViewSection.class)) {
viewSection = (ViewSection) sections[i];
}
}
...
//set variables to sections and manage sections
...
viewSection.setViewClassName(values[j]);
viewSection.setSourcePath(sourceFolderName);
viewSection.execute(project, model, new SubProgressMonitor(monitor, 1));
perspectiveSection.setSourcePath(sourceFolderName);
perspectiveSection.setViewNames(viewNames);
perspectiveSection.execute(project, model, new SubProgressMonitor(monitor, 1));
}
|
New feature B: UI component customization
As mentioned, a perspective can have as many views the user desires, and the name of each view can be set by the user. To collect all views in a perspective, we design an input panel, shown below. It has a View Class Name field and a View List field. The user can input the view class name and add it into the view list by clicking the Add button. Likewise, the user can also remove a view using the Remove button.
Figure 4. Customized template option
To create this, ViewOption class, which extends TemplateOption, is added into the template project (see Figure 3). We use it to set UI components and store users' inputs. Listing 2 shows how to customize a UI component with a view list, plus two buttons.
Listing 2. ViewOption.java
//add UI components in this panel
public void createControl(Composite parent, int span) {
...
//create View List
listLabel = new Label(parent, SWT.LEFT);
listLabel.setText("View List:");
listViewerField = new ListViewer(parent);
listField = (List) listViewerField.getControl();
GridData listGridData = new GridData(GridData.FILL_HORIZONTAL);
listGridData.heightHint = 100;
listField.setLayoutData(listGridData);
...
//create add button
addButton = new Button(parent, SWT.PUSH);
addButton.setText("Add");
...
addButton.setLayoutData(addBtnData);
addButton.addSelectionListener(...);
//create remove button
removeButton = new Button(parent, SWT.PUSH);
...
removeButton.addSelectionListener(...);
}
|
New feature C: Input-validation function
The input-validation function refers to a process of validating all users' inputs before using them. The input-validation function is absolutely critical to application security. In our sample, we define a validation rule: For all views in a perspective, view class name must be unique. If this rule is violated, an error message will be displayed on the top of the panel.
Figure 5. Validate customized template option
The input-validation function can be implemented by calling the validateOptions method in the corresponding section class. This method inherits from the super-class, and we can overwrite it to perform our own validation function. Listing 3 shows the validateOptions method in our sample.
Listing 3.
validateOptions method in ViewSection.java
public void validateOptions(TemplateOption source) {
this.getPage(0).setErrorMessage(null);
ViewOption viewOption = (ViewOption) source;
Text textField = viewOption.getTextField();
List listField = viewOption.getListField();
String[] items = listField.getItems();
if (items != null && items.length > 0) {
//validation rule check
for (int i = 0; i < items.length; i++) {
if (items[i].equals(textField.getText())) {
this.getPage(0).setErrorMessage("Class name '"
+ textField.getText()
+ "' already exists in View List.");
break;
}
}
}
}
|
New feature D: Organize the directory structure of a plug-in project automatically
One of our goals is to let the template organize directory structure for destination plug-in projects automatically. We implement this with three steps:
- Store the directory structure of the destination project using variables.
- Write an Ant script, which will be used to create target directory structure and assign resources into right directories.
- Add
IResourceChangeListenerto monitor the workspace of the template. Trigger the Ant script execution once section files' generation is completed.
- To simplify, we assume all Java files are copied into one package, which use the same name as the project name. For instance, if a project is named
com.ibm.template, all Java files will be in the packagecom.ibm.template.This discussion is beyond the scope of this article. See "Building templates with the Eclipse Plug-in Development Environment" for details. - Listing 4 shows the Ant script we use in this sample. It has three
targets. The firsttargetcreates a directory structure based on the source path and the package path. The second one copies all Java files to the correct directory. The last one removes this script file from the new plug-in project. - Add
IResourceChangeListenerintoperformFinishmethod ofSampleWizardclass. Listing 5 shows the implementation of this listener.
Listing 4. CreatePackage.xml
<?xml version="1.0"?>
<project name="template project" default="clean" basedir=".">
<property name="package" value=".\$sourcePath$\$packagePath$"></property>
<target name="create">
<mkdir dir="$dollarMark${package}"/>
</target>
<target name="move" depends="create">
<move todir="$dollarMark${package}">
<fileset dir=".">
<include name="*.java"/>
</fileset>
</move>
</target>
<target name="clean" depends="move">
<delete dir=".">
<include name="CreatePackage.xml"/>
</delete>
</target>
</project>
|
Listing 5. SampleWizard.java — Listener
public boolean performFinish(final IProject project, IPluginModelBase model,
IProgressMonitor monitor) {
...
//get workspace
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
//get Ant file
String antFilePath = "CreatePackage.xml";
final IFile file = project.getFile(antFilePath);
//add Listener to monitor resource changing
IResourceChangeListener listener = new IResourceChangeListener() {
public void resourceChanged(IResourceChangeEvent event) {
try {
if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
IResourceDelta rootDelta = event.getDelta();
IPath filePath = file.getFullPath();
IResourceDelta targetDelta = rootDelta.findMember(filePath);
if (targetDelta != null) {
URI uri = file.getLocationURI();
File antFile = new File(uri);
//run Ant script
Project project = new Project();
project.fireBuildStarted();
project.init();
ProjectHelper helper = ProjectHelper.getProjectHelper();
helper.parse(project, antFile);
project.executeTarget(project.getDefaultTarget());
project.fireBuildFinished(null);
workspace.removeResourceChangeListener(this);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
workspace.addResourceChangeListener(listener);
...
}
|
Once we create a new plug-in project, we need to refresh the project. Right-click the project and select the Refresh menu item. That's because our Ant script is executed after the project generation. We need to refresh the project in the Eclipse IDE manually. Listing 6 is a plug-in project generated through the sample template discussed in "Sample case study: In-depth discussion on a plug-in template."
Figure 6. New project structure
You need to export this new project to the [eclipse_home]\plugins directory, then restart Eclipse with the -clean parameter. After Eclipse starts, check to see that our perspective has been added into the perspective list (see in Figure 7). Select myplugin perspective, then click OK. This perspective will open.
Figure 7. Perspective list
Through this article, you should have further understanding of Eclipse plug-in template. You learned how to create a customized input component, how to control the generation of template files, and how to use one template to generate plug-in projects with different directory structures. By taking advantage of these template features, you will find it is easier to create a plug-in project.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample plug-in template | os-eclipse-plugin-templates.zip | 33KB | HTTP |
Information about download methods
Learn
-
Learn more about the basics of template creation in "Building templates with the Eclipse Plug-in Development Environment."
-
Learn more about the Plug-in Development Environment (PDE).
-
Learn more about template use in "Building Eclipse plug-ins using templates."
-
Check out the "Recommended Eclipse reading list."
-
Browse all the Eclipse content on developerWorks.
-
New to Eclipse? Read the developerWorks article "Get started with Eclipse Platform" to learn its origin and architecture, and how to extend Eclipse with plug-ins.
-
Expand your Eclipse skills by checking out IBM developerWorks' Eclipse project resources.
-
To listen to interesting interviews and discussions for software developers, check out check out developerWorks podcasts.
-
Stay current with developerWorks' Technical events and webcasts.
-
Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
-
Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
Get products and technologies
-
Check out the latest Eclipse technology downloads at IBM alphaWorks.
-
Download Eclipse Platform and other projects from the Eclipse Foundation.
-
Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
Discuss
-
The Eclipse Platform newsgroups should be your first stop to discuss questions regarding Eclipse. (Selecting this will launch your default Usenet news reader application and open eclipse.platform.)
-
The Eclipse newsgroups has many resources for people interested in using and extending Eclipse.
-
Participate in developerWorks blogs and get involved in the developerWorks community.





