Posts Tagged ‘Plugin’

Going plugin (from an OSGi bundle)

Friday, March 12th, 2010

The Eclipse plugin creation wizard allows to create OSGi bundles or Eclipse plugins.

The most notable difference is that the PDE plugin editor does not show the extension tab.

I recently wanted to use an plugin extension in a project which I initially created based on OSGi; therefore I wanted to enable the “Extension” and the “Extension Point” tab in the PDE editor.

To do this remove the line “pluginProject.extensions.false” from the file .settings/org.eclipse.pde.core.prefs. Re-open the “MANIFEST.MF” and the Extensions tab will show.

Many thanks to Neil Bartlett for sharing this tip via twitter.

 

Poll – Default launch configuration for Eclipse plugin / RCP development

Friday, November 20th, 2009

Eclipse shows errors during a launch via the log views in both the host and the target system and on the file system. In addition the developer can specify the flag “-consoleLog” in the launch configuration so see potential error messages in the console view.

Bug 284704 had been opened asking if the “-consoleLog” flag could be included by default in a new launch configuration.

What do you think? If you are a plugin or RCP developer please participate in the following survey:

Link to Survey

——————————
Please note that this is my first attempt using SurveyMonkey, I hope this works well. I believe the survey will close after the first 100 answers. If this number has not reached I’m planning to close the survey next week 27. Nov. 2009.

 

API for reading Eclipse plugin dependencies

Monday, October 19th, 2009

The Eclipse platform provides an API to allows that you can access in information of the MANIFEST.MF. For example you could read the dependencies of your plugin.

For this example create a plugin “de.vogella.pde.dependencies”. See Eclipse Plugin development for examples on how to develop plugins. Use the “Hello, World Command” template.

Define dependendies to the following plugins:
– org.eclipse.ui
– org.eclipse.core.runtime

Change the command to the following.


package de.vogella.pde.dependencies.handlers;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.osgi.util.ManifestElement;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;

public class PrintDependencies extends AbstractHandler {
	public Object execute(ExecutionEvent event) throws ExecutionException {
		String requireBundle = (String)Platform.getBundle("de.vogella.pde.dependencies").getHeaders().get(
				Constants.REQUIRE_BUNDLE);
				try {
					ManifestElement[] elements = ManifestElement.parseHeader(
					Constants.BUNDLE_CLASSPATH, requireBundle);
					for (ManifestElement manifestElement : elements) {
						System.out.println( manifestElement.getValue());
					}
				} catch (BundleException e) {
					e.printStackTrace();
				}
		return null;
	}
}

If you now run your new plugin it and select your command it will print out the dependencies of your plugin.

 

Eclipse Papercut #6 – Modifying Mylyn Context

Monday, October 5th, 2009

In this episode of Eclipse Papercuts I will demonstrate how to modify the Mylyn tasks context. Many thanks to David Green for providing sample code to access the Mylyn context.

Mylyn makes certain assumptions how the developer works. If you start a new task the Mylyn context is empty and fills up based on the selected files.

Which is not always the way I work. Frequently I know that for my task a whole package (or project) is relevant. I would like to include all classes in this package / project in my Mylyn task.

Ok, lets see how we can solve this papercut. I describe how to add Java classes from a package to an active task.

Create an command which extends the package explorer with a new popup commands as described here Extend the package explorer.

Create the command handler with the following coding:


package de.vogella.mylyn.tasksmodify.handlers;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.mylyn.context.core.ContextCore;
import org.eclipse.mylyn.context.core.IInteractionContext;
import org.eclipse.mylyn.internal.context.core.ContextCorePlugin;
import org.eclipse.mylyn.monitor.core.InteractionEvent;
import org.eclipse.mylyn.monitor.core.InteractionEvent.Kind;
import org.eclipse.ui.handlers.HandlerUtil;

public class SampleHandler extends AbstractHandler {
	public Object execute(ExecutionEvent event) throws ExecutionException {

		IStructuredSelection selection = (IStructuredSelection) HandlerUtil
				.getActiveMenuSelection(event);
		if (selection ==null){
			return null;
		}

		Object firstElement = selection.getFirstElement();

		if (firstElement instanceof IPackageFragment) {
			IPackageFragment mypackage = (IPackageFragment) firstElement;
			try {
				if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE){
					 ICompilationUnit[] compilationUnits = mypackage.getCompilationUnits();
					 for (ICompilationUnit iCompilationUnit : compilationUnits) {
						 IInteractionContext activeContext = ContextCore.getContextManager()
							.getActiveContext();
						 ContextCorePlugin.getContextManager().processInteractionEvent(iCompilationUnit,
									Kind.PROPAGATION, InteractionEvent.ID_UNKNOWN, activeContext);
					}
				}
			} catch (JavaModelException e) {
				e.printStackTrace();
			}
		}

		return null;
	}
}

Launch your plugin. Create a Mylyn task and select a package in the package explorer. Select your commands and all files of this package will be added to the task.

Further reading: If you want to access other Java Elements, e.g. Project and add them to the Mylyn task this tutorial might help you: Eclipse JDT.

Please note that ContextCorePlugin is supposed to be internal API but I did not find another way of accessing the Mylyn tasks.

 

Eclipse PDE templates – Your action is my command

Wednesday, September 23rd, 2009

The Eclipse PDE templates are fantastic to help people to learn the platform and to get oven the first initial resistence to start with Eclipse RCP or Eclipse Plugin development.

Templates indicates to their consumers that they represent best development practices. This puts a certain burden on the quality to the templates. Unfortunately the PDE RCP templates in Eclipse 3.5 were all based on actions which I believe are superseded by Eclipse Commands.

I have seen in the past lots of questions regarding actions in the Eclipse RCP and PDE newsgroups. I believe that at least some of these questions are based on the fact that the PDE templates still promote actions.

I’m therefore happy to see the changes of Bug 265231 applied for the “RCP with a view” template for the upcoming Eclipse 3.6. Special thanks for this to Chris Aniszczyk.

It also looks good for the mail example. It seems that work is happening in Bug 253105

Actions are (a little bit more) dead. Long live the command! ;-)

 

Eclipse Papercut #5 – Getting external libraries as bundles

Monday, September 21st, 2009

In this episode of Eclipse Papercuts I explain how you get bundles for popolar Java libraries for your Eclipse plugin development.

I believe it has advantages to work with plugin projects instead of pure Java projects even if the plan is not to create Eclipse plugins / RCP applications.

The core strength of OSGi for this scenario is in my opinion the encapsalation and protection of your inner classes. With OSGi bundles you decide which packages of your project are exported and therefore visible to other projects (via the tab Runtime in the editor for the file plugin.xml).

This leaves only one problem: If you are using externally libraries you have to convert them into bundles / plugins.

I would be nicer to consume pre-packages bundles. As I created a bug iText should be OSGi and tweeted about it Chris Aniszczyk pointed me to Eclipse Orbit.

Eclipse Orbit provides lots of standard libraries already pre-packaged as bundles / plugins.

Lets see how you could get the iText version from Orbit. Check the Orbit FAQ to find out more.

You need to connect via cvs to the Eclipse cvs repository. CVS URL is :pserver:anonymous@dev.eclipse.org/cvsroot/tools

Navigate to “org.eclipse.orbit”. Select “com.lowagie.text” and check it out.

orbit10

Orbit keeps the different version of the library as cvs branches. Select your project and select Replace With -> Another Branch or Version…
orbit20

orbit30

After selecting the branch and pressing ok the system will download the library and you can start using the library.

In addition to Orbit you can also use the Springsource bundle repository. On this website you can search for bundles and download then directly. You can then import them as plugin projects into your workspace.

 

Create your first Eclipse e4 application

Wednesday, August 12th, 2009

Update This description has been updated in the following tutorial: Eclipse e4.

Eclipse released on the 29 July 2009 the tech preview version 0.9 of Eclipse e4, which can be downloaded here.

I wasn’t able to find a description how to create an new application based on E4. Starting from the CVS example is possible but I wanted to start from scratch. After several failed attempts to create an E4 application I believe I have found a way to create an E4 application. I assume others will have similar problems so I wanted to share my experience.

To follow this description you need to have knowledge how to develop Eclipse Plugins in Eclipse 3.5 or earlier. Check out this Eclipse Plugin Development Tutorial.

So lets get started with e4.

Download e4. Extract it and start it is similar to older Eclipse versions.

Currently there is no wizard which creates a working scaffold of an E4 application. We will therefore use the exsting plugin templates.

Create a new Plugin project “de.vogella.e4.first”. Do not select “Generate an activator”, nor “This plug-in will make contributions to the UI” nor “Would you like to create a rich client application”. Do not select a template. Press finish.

e410

This will open the Plugin Perspective, switch here to the Package Explorer to see your new project.

Create the package “de.vogella.e4.first”. The result should look like the following.

e412

Select your MANIFEST.MF and add the following dependencies to your plugin.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: First
Bundle-SymbolicName: de.vogella.e4.first;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime,
 org.eclipse.e4.ui.workbench;bundle-version="0.9.0",
 org.eclipse.e4.ui.workbench.renderers.swt;bundle-version="0.9.0",
 org.eclipse.e4.ui.workbench.renderers.swt.contributions;bundle-version="0.9.0",
 org.eclipse.e4.ui.workbench.swt;bundle-version="0.9.0",
 org.eclipse.e4.ui.services;bundle-version="0.9.0",
 org.eclipse.e4.core.services;bundle-version="0.9.0"

You need (some of) these plugins for the usage of E4 features.

Add the following extension points. I noticed that for some of the features you have to modify the plugin.xml directly as the UI does not support them. But you have to create the plugin.xml via the MANIFEST.MF file; as I created it directly as a new file I received a strange system behavior.


<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.e4.workbench.parts">
          <part
            class="de.vogella.e4.first.views.View1"
            label="My first E4 View"
            parentId="org.eclipse.e4.ui.tags.navigation">
      </part>
   </extension>
   <extension
         id="product"
         point="org.eclipse.core.runtime.products">
      <product
            application="org.eclipse.e4.ui.workbench.swt.application"
            name="vogella">
             <property
               name="appName"
               value="vogella">
         </property>
         <property
               name="applicationXMI"
               value="de.vogella.e4.first/Application.xmi">
         </property>
      </product>

   </extension>

</plugin>

“org.eclipse.e4.workbench.parts” is a new extension point by which you can define your view parts, formally known as views and editors.

The extension point “org.eclipse.core.runtime.products” has a new parameter “applicationXMI”. This is a parameter to the model of your UI. We came to this later. You also do not define your own application; we use “org.eclipse.e4.ui.workbench.swt.application”.

Create a product configuration called “vogella.product”. This is similar to Eclipse 3.5; see here for a description: Eclipse Product Configuration.

e420

Make sure you select “org.eclipse.e4.ui.workbench.swt.application”.

e430

Add as dependency to your product the plugin “org.eclipse.e4.ui.workbench”. Add also the plugin “de.vogella.e4.first”.
Press “add required plugins”.

Create the following two classes:


package de.vogella.e4.first.handlers;

import org.eclipse.e4.workbench.ui.IWorkbench;

public class ExitHandler {
	public void execute(IWorkbench workbench) {
		workbench.close();
	}
}

and

package de.vogella.e4.first.views;

import org.eclipse.e4.core.services.context.IEclipseContext;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.services.IDisposable;

public class View1 implements IDisposable {

	public View1(Composite parent, final IEclipseContext outputContext) {
		Label label = new Label(parent, SWT.NONE);
		label.setText("E4 is new");
		GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
		gridData.horizontalIndent = 20;
		label.setLayoutData(gridData);
		Text text = new Text(parent, SWT.NONE);
		text.setText("and different");
		GridLayoutFactory.fillDefaults().generateLayout(parent);
	}

	public void dispose() {

	}
}

You need a model for your application. In the parameter “applicationXMI” we earlier defined that this model will be “de.vogella.e4.first/Application.xmi”. Create the file Application.xmi with the following content.


<?xml version="1.0" encoding="ASCII"?>
<application:MApplication xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2008/Application">
  <windows name="Main" x="100" y="100" width="800" height="600">
    <menu>
      <items xsi:type="application:MMenuItem" name="File">
        <menu>
          <items xsi:type="application:MMenuItem" id="" name="Exit" command="//@command.0"/>
        </menu>
      </items>
    </menu>
    <children policy="VerticalComposite">
      <children xsi:type="application:MSashForm" policy="HorizontalSash">
        <children xsi:type="application:MStack">
          <children xsi:type="application:MContributedPart" iconURI="" name="My View" tooltip="My first View" URI="platform:/plugin/de.vogella.e4.first/de.vogella.e4.first.views.View1"/>
        </children>
        <weights>30</weights>
        <weights>70</weights>
      </children>
    </children>
    <handlers id="" URI="platform:/plugin/de.vogella.e4.first/de.vogella.e4.first.handlers.ExitHandler" persistedState="" command="//@command.0"/>
  </windows>
  <command id="application.exit" name="Exit"/>
</application:MApplication>

This is the EMF model which defines your UI. Eclipse should display this model in a EMF editor so that you can investigate it. In this model you find your view and command definition. The content can be viewed via the properities view.

e450

Now start your application from your vogella.product. Starting it directly from the plugin.xml will not work (easily).

If you receive the error “org.eclipse.core.runtime.AssertionFailedException: null argument:-applicationXMI argument missing” check you plugin.xml. E4 created in several cases twice the products entry.

You should be rewarded ;-) with this user interface:

e460

With this first application I hope you can started using the E4 advanced features, e.g. CSS styling, etc.

My final thoughts: Eclipse e4 has already amazing capabilities for a tech review release. The new modeled UI removes the need for a lot of boilerplate code.

Try it out!

 

TweetHub – Eclipse ECF Twitter client

Monday, August 10th, 2009

Eclipse ECF is a framework for supporting the development of distributed Eclipse-based tools and applications.

With the Galileo release Eclipse ECF provides also a nice Twitter client TweetHub. TweetHub is an Eclipse RCP application for communicating with Twitter.

It took me a while to gather the right information to make TwitterHub work. So I thought it might be helpful to blog about it so that this might be easier for others.

First you need to install the ECF SDK via the update manager from http://download.eclipse.org/rt/ecf/3.0/3.5/repo.

To install TwitterHub you need to download the code from cvs. The cvs connection string is: :pserver:anonymous@ecf1.osuosl.org:/ecf

To learn how to use cvs see Eclipse cvs access.

Check-out the following plugins from the cvs location:

org.eclipse.ecf.provider.twitter.ui.hub.product
org.eclipse.ecf.provider.twitter.ui.hub
org.eclipse.ecf.provider.twitter

TweetHub08

This should be sufficient. You should now be able to run the product.

TweetHub10

So now you can use TwitterHub to follow me on Twitter. ;-)

I would like to thank Marcelo Mayworm who helped on in the eclipse.technology.ecf newsgroup.

Additional links:
ECL New and Noteworthy
TweetHub wiki .

 

Deprecate certain extension points to guide developers?

Wednesday, July 29th, 2009

Given the discussion about E4 and the evolution of Eclipse I’m wondering if it would make sense to flag certain Eclipse extension points as deprecated and add a warning to the PDE tooling if someone uses these extension points. This would help developes to do “the right thing”.

This question came to me while watching The Myth of the Genius Programmer. Björn quoted from this presentation in this post Criticism is not evil . In this video it was explained that tools matter in the sense that they guide new developer in a certain direction.

For example I believe that actions could be marked as deprecated. I see still a lot of questions which relates to actions in the newsgroup and I believe that commands are superior to actions. I know that the description indicates that “org.eclipse.ui.menus” can be used but perhaps more guidance would help?

Any opinions on this?

Update I submitted Bug 285034 for the enhancement in PDE / UI for the warning.

 

Eclipse Papercut #3 – Plugin to find unused methods

Wednesday, July 15th, 2009

In this episode of Eclipse Papercuts we will look at how we can analyse our own code to find “dead” code in your projects. We will write a plug-in to find methods which are not called (within the workspace).

methodCalls

Of course if you are a framework developer all your exported public methods are API and you can hardly change it. But in a lot of cases the development team has all code in one workspace. In this case it should be easy to identify dead code easily. Currently you have to select each method and select “Open Call Hierachy”.

This calls of course for a simpler solution, lets solve a papercut.

Create a Plug-in Project “de.vogella.jdt.codeanalysis” .

Define the following model class which will store the results of the calucation.


package de.vogella.jdt.infoview.model;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IMethod;

public class MethodInformation {
private final String methodName;
private final int numberOfCalls;
private final ICompilationUnit cu;
private final IMethod method;

public MethodInformation(String methodName, int numberOfCalls,
ICompilationUnit cu, IMethod method) {
this.methodName = methodName;
this.numberOfCalls = numberOfCalls;
this.cu = cu;
this.method = method;
}

/**
* @return the method
*/
public String getMethodName() {
return methodName;
}

/**
* @return the numberOfCalls
*/
public int getNumberOfCalls() {
return numberOfCalls;
}

/**
* @return the cu
*/
public ICompilationUnit getResource() {
return cu;
}

/**
* @return the method
*/
public IMethod getMethod() {
return method;
}

}

Define a Eclipse command “de.vogella.jdt.codeanalysis.calculateUsage” with the default handler “de.vogella.jdt.codeanalysis.handler.CalculateUsage”.

Create these two helper classes with will search through a given Java project. The usage of the JDT functionality is explained in Eclipse JDT.


package de.vogella.jdt.codeanalysis.analysis;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;

import de.vogella.jdt.codeanalysis.model.MethodInformation;

public class CodeAnalysis {

	public static List<MethodInformation> calculate(IJavaProject project) {
		List<MethodInformation> list = new ArrayList<MethodInformation>();
			try {
				if (project.isOpen()) {

					IPackageFragment[] packages = project
							.getPackageFragments();
					// parse(JavaCore.create(project));
					for (IPackageFragment mypackage : packages) {
						if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
							for (ICompilationUnit unit : mypackage
									.getCompilationUnits()) {
								IType[] types = unit.getTypes();
								for (int i = 0; i < types.length; i++) {
									IType type = types[i];
									IMethod[] methods = type.getMethods();
									for (int j = 0; j < methods.length; j++) {
										IMethod method = methods[j];
										if (!method.isMainMethod()) {
											int number = performIMethodSearch(method);

											if (number == 0) {
												MethodInformation metric = new MethodInformation(
														method.getElementName(),
														number, unit, method);
												list.add(metric);
											}

										}

									}

								}

							}
						}

					}
				}
			} catch (CoreException e) {
				e.printStackTrace();
			}
		return list;
	}

	private static int performIMethodSearch(IMethod method)
			throws CoreException {
		SearchPattern pattern = SearchPattern.createPattern(method,
				IJavaSearchConstants.REFERENCES);
		IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
		MySearchRequestor requestor = new MySearchRequestor();
		SearchEngine searchEngine = new SearchEngine();
		searchEngine.search(pattern, new SearchParticipant[] { SearchEngine
				.getDefaultSearchParticipant() }, scope, requestor, null);
		return requestor.getNumberOfCalls();

	}
}

package de.vogella.jdt.codeanalysis.analysis;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.search.MethodReferenceMatch;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchRequestor;

public class MySearchRequestor extends SearchRequestor {

	private int numberOfCalls = 0;

	@Override
	public void acceptSearchMatch(SearchMatch match) throws CoreException {
		if (match instanceof MethodReferenceMatch) {
//			MethodReferenceMatch methodMatch = (MethodReferenceMatch) match;
//			Object element = methodMatch.getElement();
			numberOfCalls++;
		}
	}

	/**
	 * @return the numberOfCall
	 */
	public int getNumberOfCalls() {
		return numberOfCalls;
	}

}

We create a little View with a Table (and its content and label provider)


package de.vogella.jdt.codeanalysis.views;

import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.part.ViewPart;

import de.vogella.jdt.codeanalysis.model.MethodInformation;

public class ResultView extends ViewPart {
	public static final String ID = "de.vogella.jdt.codeanalysis.ResultView";
	private TableViewer viewer;

	public void setInput(List<MethodInformation> list) {
		viewer.setInput(list);
	}

	@Override
	public void createPartControl(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
		buildTableColumns(viewer);
		viewer.setLabelProvider(new AnalysisLabelProvider());
		viewer.setContentProvider(new AnalysisContentProvider());

		viewer.getTable().addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				Object data = e.item.getData();
				if (!(data instanceof MethodInformation))
					return;
				MethodInformation info = (MethodInformation) data;
				IMethod method = info.getMethod();
				ICompilationUnit cu = info.getResource();
				if (cu == null)
					return;
				try {
					IEditorPart part = JavaUI.openInEditor(cu);
					JavaUI.revealInEditor(part, (IJavaElement) method);
				} catch (CoreException ex) {
					// error handling
				}
			}
		});
	}

	@Override
	public void setFocus() {
	}

	private void buildTableColumns(TableViewer viewer) {
		String[] titles = { "File", "Method", "Number of Calls" };
		int[] bounds = { 100, 100, 100 };

		for (int i = 0; i < titles.length; i++) {
			TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
			column.getColumn().setText(titles[i]);
			column.getColumn().setWidth(bounds[i]);
			column.getColumn().setResizable(true);
			column.getColumn().setMoveable(true);
		}
		Table table = viewer.getTable();
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
	}

	public class AnalysisLabelProvider extends LabelProvider implements
			ITableLabelProvider {

		@Override
		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}

		@Override
		public String getColumnText(Object element, int columnIndex) {
			MethodInformation metric = (MethodInformation) element;
			switch (columnIndex) {
			case 0:
				return metric.getResource().getElementName();
			case 1:
				return metric.getMethodName();
			default:
				return String.valueOf(metric.getNumberOfCalls());
			}

		}
	}

	public class AnalysisContentProvider implements IStructuredContentProvider {

		@Override
		public Object[] getElements(Object inputElement) {
			List<MethodInformation> list = (List<MethodInformation>) inputElement;
			return list.toArray();
		}

		@Override
		public void dispose() {
		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		}

	}

}

Finally we can create the handler:


package de.vogella.jdt.codeanalysis.handler;

import java.util.List;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.handlers.HandlerUtil;

import de.vogella.jdt.codeanalysis.analysis.CodeAnalysis;
import de.vogella.jdt.codeanalysis.model.MethodInformation;
import de.vogella.jdt.codeanalysis.views.ResultView;

public class CalculateUsage extends AbstractHandler {

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

		IStructuredSelection selection = (IStructuredSelection) HandlerUtil
				.getActiveMenuSelection(event);
		if (selection == null || selection.getFirstElement() == null) {
			// Nothing selected, do nothing
			MessageDialog.openInformation(HandlerUtil.getActiveShell(event),
					"Information", "Please select a project");
			return null;
		}
		final Object firstElement = selection.getFirstElement();
		if (!(firstElement instanceof IJavaProject)) {
			return null;
		}

		final IJavaProject project = (IJavaProject) firstElement;

		try {
			if (!project.isOpen()
					|| !(project.getProject()
							.hasNature("org.eclipse.jdt.core.javanature"))) {
				MessageDialog.openInformation(
						HandlerUtil.getActiveShell(event), "Information",
						"Only works for open Java Projects");
				return null;
			}
		} catch (CoreException e1) {
			return null;
		}

		Job job = new Job("Calculate Usage of methods") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				final List<MethodInformation> calculate = CodeAnalysis
						.calculate(project);
				// Open view in the UI thread
				Display.getDefault().asyncExec(new Runnable() {
					public void run() {
						try {
							final ResultView findView = (ResultView) HandlerUtil
									.getActiveWorkbenchWindow(event)
									.getActivePage().showView(ResultView.ID);
							findView.setInput(calculate);
						} catch (PartInitException e) {
							e.printStackTrace();
						}
					}

				});
				return Status.OK_STATUS;
			}

		};
		job.setUser(true);
		job.schedule();

		return null;
	}
}

As a last step add your command to the menu of the package explorer. This is also described Eclipse Plugin Development you results in the following plugin.xml


<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
         point="org.eclipse.ui.views">
      <view
            class="de.vogella.jdt.codeanalysis.views.ResultView"
            id="de.vogella.jdt.codeanalysis.ResultView"
            name="Analysis Result"
            restorable="true">
      </view>
   </extension>

   <extension
         point="org.eclipse.ui.commands">
      <command
            defaultHandler="de.vogella.jdt.codeanalysis.handler.CalculateUsage"
            id="de.vogella.jdt.codeanalysis.calculateUsage"
            name="Calculate method usage">
      </command>
   </extension>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            locationURI="popup:org.eclipse.jdt.ui.PackageExplorer">
         <command
               commandId="de.vogella.jdt.codeanalysis.calculateUsage"
               label="Calculate method usage"
               style="push">
         </command>
      </menuContribution>
   </extension>

</plugin>

If you now export your plugin into your Eclipse IDE you will have a new menu entry which allows you to start the usage calculation of your methods. Once finished your View should be opened / updated and the methods displayed which are not called. By double-clicking on them you can jump to the related method.

Note: project.isOpen() returns false, if you select an open project only with the right mouse click. If you click the project with the left mouse you should be fine.

Of course you can easily think of possible extensions to this approach:

  1. Calculate the usage of all methods and show then in the table
  2. Make is work for several projects
  3. Display in the table if a method has private, protected, default or public access
  4. Introduce filter
  5. Create marker in the editor for the identified methods. See Eclipse Plugin Development – Resource Markers

And here is the project for download.

de.vogella.jdt.codeanalysis.source_1.0.0.200907151800

Last but not least if would be nice if the Eclipse API Tools could help us with finding “dead” code. If have therefore opened Bug 283574.