by Lars Vogel

Follow me on twitter

Lars Vogel on Google+

Extending Eclipse - Plug-in Development Tutorial

Lars Vogel

Version 2.0

04.12.2011

Revision History
Revision 0.1 01.04.2008 Lars
Vogel
Created
Revision 0.2 - 2.0 14.04.2009 - 04.12.2011 Lars
Vogel
bugfixes and enhancements

Eclipse Plug-ins Tutorial

This article describes the creation and deployment of Eclipse plug-ins. The article is based on Eclipse 3.7 (Eclipse Indigo) and Java 1.6.


Table of Contents

1. Eclipse Plugins
2. Prerequisites
3. Hello World Plug-in
4. Contribute to existing UI elements
4.1. Overview
4.2. Contribute to package explorer
4.3. Restrict the extension - Visible When
5. Resources and Marker
5.1. Overview
5.2. Create markers
5.3. More on markers
6. Adapters
6.1. Overview
6.2. Example
7. Deploying a plugin
8. Tutorial: Deploying a plug-in
8.1. Export plug-in and put into dropin folder
8.2. Create a p2 update site
9. Thank you
10. Questions and Discussion
11. Links and Literature
11.1. Source Code
11.2. Eclipse Resources
11.3. vogella Resources

1. Eclipse Plugins

The smallest software component in Eclipse are plug-ins. The Eclipse IDE allows the developer to extend the IDE functionality via plug-ins. For example you can create new menu entreis or new editors via plug-ins. This tutorial gives several examples how to do this.

Eclipse is build upon the OSGi framework. The OSGi framework provides a dynamic modular architecture which is used for running the Eclipse IDE.

2.  Prerequisites

This tutorial assumes that you are already familiar with using the Eclipse IDE and have experience in developing Java.

3. Hello World Plug-in

We will create a plug-in which contributes a menu entry to the standard Eclipse menu.

Create a new plug-in project de.vogella.plugin.first via FileNewProjectPlug-in Development Plug-in Project.

Select the "Hello, World Command!" template and press Finish. This should automatically open the "Plug-in Development perspective".

Select the file MANIFEST.MF, right click it, select Run-AsEclipse Application

A new workbench starts with a new menu entry. If you select this menu entry a message box will be displayed.

4.  Contribute to existing UI elements

4.1. Overview

In this example we will add a new context menu entry to the Package explorer view. The context menu is displayed if the user select a file in the package explorer via a right mouse click. We will offer the option to create a HTML page for a Java source file.

To contribute to an existing menu or toolbar you need to know the corresponding ID. This ID can be found via the "Menu Spy". See Eclipse Source Code Guide for details.

4.2. Contribute to package explorer

Create a new plug-in project de.vogella.plugin.htmlconverter. Do not use a template. Select the tab "Dependencies" of the file plugin.xml. Add the dependencies to org.eclipse.jdt.core and org.eclipse.core.resources.

The following uses Eclipse Commands. See Eclipse Commands Tutorial to learn how to work with commands.

Add a command with the ID de.vogella.plugin.htmlconverter.convert and the default handler de.vogella.plugin.htmlconverter.handler.Convert to your plug-in.

Add this command to the menu via the extension point org.eclipse.ui.menus and use as the "locationURI" popup:org.eclipse.jdt.ui.PackageExplorer. Set the label to "Create HTML" for this contribution.

The resulting file plugin.xml should look like the following.

				
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="popup:org.eclipse.jdt.ui.PackageExplorer">
         <command
               commandId="de.vogella.plugin.htmlconverter.convert"
               label="Create HTML"
               style="push">
         </command>
      </menuContribution>
   </extension>
   <extension
         point="org.eclipse.ui.commands">
      <command
            defaultHandler="de.vogella.plugin.htmlconverter.handler.Convert"
            id="de.vogella.plugin.htmlconverter.convert"
            name="Convert">
      </command>
   </extension>

</plugin>

			

Eclipse allows to save additional information for each file. You can use the IResource interface and the setPersistentProperty() and getPersistentProperty() methods. With these functions you can save Strings on files. We use these functions to save a directory for Java source files which already were exported via HTML.

Create the de.vogella.plugin.htmlconverter.handler.Convert class.

				
package de.vogella.plugin.htmlconverter.handler;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.ui.handlers.HandlerUtil;

public class Convert extends AbstractHandler {
	private QualifiedName path = new QualifiedName("html", "path");

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {

		IStructuredSelection selection = (IStructuredSelection) HandlerUtil
				.getActiveMenuSelection(event);

		String directory = "";
		Object firstElement = selection.getFirstElement();
		if (firstElement instanceof ICompilationUnit) {
			ICompilationUnit cu = (ICompilationUnit) firstElement;
			IResource res = cu.getResource();
			boolean newDirectory = true;
			directory = getPersistentProperty(res, path);

			if (directory != null && directory.length() > 0) {
				newDirectory = !(MessageDialog.openQuestion(
						HandlerUtil.getActiveShell(event), "Question",
						"Use the previous output directory?"));
			}
			if (newDirectory) {
				DirectoryDialog fileDialog = new DirectoryDialog(
						HandlerUtil.getActiveShell(event));
				directory = fileDialog.open();

			}
			if (directory != null && directory.length() > 0) {
				analyze(cu);
				setPersistentProperty(res, path, directory);
				write(directory, cu);
			}

		} else {
			MessageDialog.openInformation(HandlerUtil.getActiveShell(event),
					"Information", "Please select a Java source file");
		}
		return null;
	}

	protected String getPersistentProperty(IResource res, QualifiedName qn) {
		try {
			return res.getPersistentProperty(qn);
		} catch (CoreException e) {
			return "";
		}
	}

	// TODO: Include this in the HTML output

	private void analyze(ICompilationUnit cu) {
		// Cool JDT allows you to analyze the code easily
		// I don't see really a use case here but I just wanted to do this here
		// as I consider this as cool and
		// what to have a place where I can store the data
		try {

			IType type = null;
			IType[] allTypes;
			allTypes = cu.getAllTypes();
			
/** * Search the public class */
for (int t = 0; t < allTypes.length; t++) { if (Flags.isPublic((allTypes[t].getFlags()))) { type = allTypes[t]; break; } } if (type != null) { String classname = type.getFullyQualifiedName(); IMethod[] methods = type.getMethods(); } } catch (JavaModelException e) { e.printStackTrace(); } } protected void setPersistentProperty(IResource res, QualifiedName qn, String value) { try { res.setPersistentProperty(qn, value); } catch (CoreException e) { e.printStackTrace(); } } private void write(String dir, ICompilationUnit cu) { try { cu.getCorrespondingResource().getName(); String test = cu.getCorrespondingResource().getName(); // Need String[] name = test.split("\\."); System.out.println(test); System.out.println(name.length); String htmlFile = dir + "\\" + name[0] + ".html"; System.out.println(htmlFile); FileWriter output = new FileWriter(htmlFile); BufferedWriter writer = new BufferedWriter(output); writer.write("<html>"); writer.write("<head>"); writer.write("</head>"); writer.write("<body>"); writer.write("<pre>"); writer.write(cu.getSource()); writer.write("</pre>"); writer.write("</body>"); writer.write("</html>"); writer.flush(); } catch (JavaModelException e) { } catch (IOException e) { e.printStackTrace(); } } }

If you start this plugin you should be able to create HTML output from a Java source file.

4.3. Restrict the extension - Visible When

Currently our context menu is always displayed. We would like to show it only if a source file is selected. For this we will use a "visible-when" definition. To learn the details of visible-when please see Eclipse Advanced Usage of Commands .

Add the dependency "org.eclipse.core.expressions" to your plugin. Select your menu contribution. Using the right mouse add the condition to the command that it should only be visible if a file is selected which represents a "org.eclipse.jdt.core.ICompilationUnit". For this exercise you use the predefined variable "activeMenuSelection" which contains the selection in the menu and iterate over it. If the selection can get adapted to ICompilationUnit then the contribution will be visible.

This will result in the following "plugin.xml".

				
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="popup:org.eclipse.jdt.ui.PackageExplorer">
         <command
               commandId="de.vogella.plugin.htmlconverter.convert"
               label="Create HTML"
               style="push">
            <visibleWhen
                  checkEnabled="false">
               <with
                     variable="activeMenuSelection">
                  <iterate
                        ifEmpty="false"
                        operator="or">
                     <adapt
                           type="org.eclipse.jdt.core.ICompilationUnit">
                     </adapt>
                  </iterate>
               </with>
            </visibleWhen>
         </command>
      </menuContribution>
   </extension>
   <extension
         point="org.eclipse.ui.commands">
      <command
            defaultHandler="de.vogella.plugin.htmlconverter.handler.Convert"
            id="de.vogella.plugin.htmlconverter.convert"
            name="Convert">
      </command>
   </extension>

</plugin>

			

If you now start your plugin the menu entry should only be visible if at least one compilation unit has been selected.

5. Resources and Marker

5.1.  Overview

Eclipse represents Resources like Projects, Files, Folders, Packages as IResource.

Marker represent additional informations for resources, e.g. an error marker. Every marker can have attributes (key / value combination). Markers can be displayed in the standard view, e.g. the Task, Bookmark or the problems view. To be displayed in these views you have to use predefined attributes.

The following will demonstrate how to create marker for a selected resource.

5.2. Create markers

Create a plug-in project "de.vogella.plugin.markers". Add the dependency to org.eclipse.core.resources", "org.eclipse.jdt.core" and "org.eclipse.jdt.ui". Create the command "de.vogella.plugin.markers.AddMarker" with the default handler "de.vogella.plugin.markers.handler.AddMarker" and add this command to the menu.

Create the following code.

				
package de.vogella.plugin.markers.handler;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.handlers.HandlerUtil;

public class AddMarker extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		IStructuredSelection selection = (IStructuredSelection) HandlerUtil
				.getActiveSite(event).getSelectionProvider().getSelection();
		if (selection == null) {
			return null;
		}
		Object firstElement = selection.getFirstElement();
		if (firstElement instanceof IJavaProject) {
			IJavaProject type = (IJavaProject) firstElement;
			try {
				IResource resource = type.getUnderlyingResource();
				IMarker marker = resource.createMarker(IMarker.TASK);
				marker.setAttribute(IMarker.MESSAGE, "This a a task");
				marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
		return null;
	}
}

			

If you run you can create a marker in the TODO list if you select a Java project and click your menu entry.

5.3. More on markers

For more on markers check the following tutorial from IBM developerworks Using markers, annotations, and decorators in Eclipse.

6. Adapters

6.1.  Overview

Adapters help to display information about objects in view without having to adjust the existing views. In this example we will create a small view which allows to select objects and use the properties view to display them.

Adapters are used on several places for example you can use an adapter to display your data in the outline view. See Outline View Example for an example how to do this.

6.2.  Example

We will simple use an adapter to show our data in the property view. Create a new plugin project "de.vogella.plugin.adapter". Use the "Plug-in with a view" template with the following settings.

Add the dependency "org.eclipse.ui.views" in tab dependencies of plugin.xml.

Create the following data model.

				
package de.vogella.plugin.adapter.model;

public class Todo {
	private String summary;
	private String description;
	public String getSummary() {
		return summary;
	}
	public void setSummary(String summary) {
		this.summary = summary;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}

}

			

Change the code of SampleView.java to the following. After this change you should be able to run your project, open your view and see your todo items.

				
package de.vogella.plugin.adapter.views;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

import de.vogella.plugin.adapter.model.Todo;

public class SampleView extends ViewPart {
	public static final String ID = "de.vogella.plugin.adapter.views.SampleView";

	private TableViewer viewer;

	class ViewLabelProvider extends LabelProvider implements
			ITableLabelProvider {
		public String getColumnText(Object obj, int index) {
			Todo todo = (Todo) obj;
			return todo.getSummary();
		}

		public Image getColumnImage(Object obj, int index) {
			return getImage(obj);
		}

		public Image getImage(Object obj) {
			return PlatformUI.getWorkbench().getSharedImages()
					.getImage(ISharedImages.IMG_OBJ_ELEMENT);
		}
	}

	
/** * This is a callback that will allow us to create the viewer and initialize * it. */
public void createPartControl(Composite parent) { viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer.setContentProvider(new ArrayContentProvider()); viewer.setLabelProvider(new ViewLabelProvider()); getSite().setSelectionProvider(viewer); viewer.setInput(getElements()); }
/** * Passing the focus request to the viewer's control. */
public void setFocus() { viewer.getControl().setFocus(); } // Build up a simple data model private Todo[] getElements() { Todo[] todos = new Todo[2]; Todo todo = new Todo(); todo.setSummary("First Todo"); todo.setDescription("A very good description"); todos[0] = todo; todo = new Todo(); todo.setSummary("Second Todo"); todo.setDescription("Second super description"); todos[1] = todo; return todos; } }

To displays its values in the property view, add the extension point "org.eclipse.core.runtime.adapters" to your project. The data of the extension point should be like the following.

				
<extension
         point="org.eclipse.core.runtime.adapters">
      <factory
            adaptableType="de.vogella.plugin.adapter.model.Todo"
            class="de.vogella.plugin.adapter.TodoAdapterFactory">
         <adapter
               type="org.eclipse.ui.views.properties.IPropertySource">
         </adapter>
      </factory>
</extension>

			

Implement the factory and the new class "TodoPropertySource" which implements "IPropertySource".

				
package de.vogella.plugin.adapter;

import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.ui.views.properties.IPropertySource;

import de.vogella.plugin.adapter.model.Todo;

public class TodoAdapterFactory implements IAdapterFactory {

	@Override
	public Object getAdapter(Object adaptableObject, Class adapterType) {
		if (adapterType== IPropertySource.class && adaptableObject instanceof Todo){
			return new TodoPropertySource((Todo) adaptableObject);
		}
		return null;
	}

	@Override
	public Class[] getAdapterList() {
		return new Class[] { IPropertySource.class };
	}

}

			

				
package de.vogella.plugin.adapter;

import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;

import de.vogella.plugin.adapter.model.Todo;

public class TodoPropertySource implements IPropertySource {

	private final Todo todo;

	public TodoPropertySource(Todo todo) {
		this.todo = todo;
	}


	@Override
	public boolean isPropertySet(Object id) {
		return false;
	}

	@Override
	public Object getEditableValue() {
		return this;
	}

	@Override
	public IPropertyDescriptor[] getPropertyDescriptors() {

		return new IPropertyDescriptor[] {
				new TextPropertyDescriptor("summary", "Summary"),
				new TextPropertyDescriptor("description", "Description") };
	}

	@Override
	public Object getPropertyValue(Object id) {
		if (id.equals("summary")) {
			return todo.getSummary();
		}
		if (id.equals("description")) {
			return todo.getDescription();
		}
		return null;
	}

	@Override
	public void resetPropertyValue(Object id) {

	}

	@Override
	public void setPropertyValue(Object id, Object value) {
		String s = (String) value;
		if (id.equals("summary")) {
			todo.setSummary(s);
		}
		if (id.equals("description")) {
			todo.setDescription(s);
		}
	}

}

			

If you run your workbench and open your View via Windows -> Show View -> Others -> Sample Category -> Sample View and the property view you should be able to view your data.

7. Deploying a plugin

To use your plug-ins in your standard Eclipse installation you can either export it locally as plug-in and place it into your Eclipse installation or you export it as feature and use the Eclipse update manager to install it.

If you export your plug-in locally you can put it into the Eclipse "dropin" folder of your Eclipse installation. After a restart of your Eclipse your plug-in should be available and ready to be used.

If you want to install your plug-in into your running Eclipse IDE, you can also use "Install into host. Repository". In the export wizard dialog select in this case "Install into host. Repository". This will export your plugin into the selected directory (Repository) and install it directly into the running Eclipse.

If you create and export an feature you can use the Eclipse update manager directly if you point to the created "metadata" repository during the export. You can then use the Eclipse update manager to install this feature.

8. Tutorial: Deploying a plug-in

8.1. Export plug-in and put into dropin folder

Select your plugin.xml and select the tab overview. Press the hyperlink "Export Wizard".

Select the plug-in you want to export.

This will create a jar in the selected directory. Copy this jar to the "dropin" directory in your Eclipse installation directory and re-start Eclipse.

After a restart of Eclipse your plug-in should now be available in your Eclipse installation and ready to be used. For example if you contributed a new view you find it under the Windows -> Show View menu entry.

8.2. Create a p2 update site

p2 is the technical component which allows to install, remove and update plugins to your existing Eclipse IDE installation.

To create an update site you require a feature project. Create a feature project for your plugin.

The Eclipse p2 update manager shows per default only features with a category. While the user can deflag this grouping it is often easier to deploy the feature including an category.

In your feature project create file File -> New -> Other -> Plug-in development -> "Category Definition" a new category for your feature.

Press "New Category" and create a category with a name which describes your functionality. Add your feature to this category.

Export your feature via File -> Export -> "Deployable features". Deploy it to a local directory on your machine. Make sure you select on the Option tab your "category.xml". Also make sure to select "Generate metadata repository".

Try if this feature can be installed into your Eclipse IDE. See Using the Eclipse Update Manager for information on how to use the Eclipse update manager. Use the update manager and point to your local directory. Restart the IDE after installation.

After a restart of Eclipse your plug-in should now be available in your Eclipse installation and ready to be used. For example if you contributed a new view you find it under the Windows -> Show View menu entry.

9. Thank you

Please help me to support this article:

Flattr this

10. Questions and Discussion

Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.de Google Group. I have created a short list how to create good questions which might also help you.

11. Links and Literature

11.1. Source Code

Source Code of Examples

11.3. vogella Resources

Eclipse RCP Training (German) Eclipse RCP Training with Lars Vogel

Android Tutorial Introduction to Android Programming

GWT Tutorial Program in Java and compile to JavaScript and HTML

Eclipse RCP Tutorial Create native applications in Java

JUnit Tutorial Test your application

Git Tutorial Put everything you have under distributed version control system