by Lars Vogel

Follow me on twitter

Lars Vogel on Google+

Eclipse 4 RCP - Tutorial

Building Eclipse RCP applications based on Eclipse 4

Lars Vogel

Version 5.6

03.11.2011

Revision History
Revision 0.1 14.02.2009 Lars
Vogel
created
Revision 0.2 - 5.6 16.02.2009 - 03.11.2011 Lars
Vogel
bug fixes and enhancements

Eclipse e4

This tutorial gives an overview about the Eclipse 4 application platform.

This tutorial describes the creation of Eclipse 4 based applications, e.g. Eclipse RCP applications. It describes the modeled application concept and the new programming model which is based on annotations and dependency injection.


Table of Contents

1. Eclipse 4
1.1. What is Eclipse 4?
1.2. What is the Eclipse e4 project?
2. Eclipse Extension points
2.1. What are Extension Points?
2.2. Usage in Eclipse 4.x
3. Tutorial: Install Eclipse 4.2 for RCP development
3.1. Step: Download and Install Eclipse
3.2. Step: Install the Eclipse 4 tooling
3.3. Provisional API
4. Tutorial: Eclipse 4 application using the wizard
4.1. Eclipse tooling
4.2. Create project
4.3. Launch
5. Steps to create Eclipse 4 applications
5.1. Are Eclipse 4 applications still plug-ins?
5.2. Converting a plug-in into an Eclipse 4 application
5.3. Framework dependencies
6. Eclipse 4 application model
6.1. What is the application model?
6.2. Where is the application model defined?
6.3. How is the model connected to my Java classes?
6.4. URI in the Model
6.5. Application model editor
6.6. Model Add-ons
6.7. Model access at runtime
6.8. Application model and Dependency Injection
7. Tutorial: Create an Eclipse plug-in
7.1. Create an Eclipse plug-in
7.2. Investigate project
8. Tutorial: From Plug-in to Eclipse 4 application
8.1. Enter plug-in dependencies
8.2. Create Product configuration
8.3. Create Application model
8.4. Link application model to your product
8.5. Enter Product dependencies
8.6. Validate registered model Add-ons
8.7. Start Application
9. Tutorial: Modeling a User Interface
9.1. Adding model element
9.2. Create model objects
10. Dependency Injections and Annotations
10.1. What is Dependency Injection?
10.2. Define dependencies in Eclipse
10.3. What can get injected?
10.4. How does dependency injection work in Eclipse 4?
11. Tutorial: Using dependency injection
11.1. Getting a Composite
11.2. Validation
12. Behavior Annotations
12.1. API definition via inheritance
12.2. API definition via annotations
12.3. Lifecycle Hooks
13. Tutorial: Define Part Lifecycle
13.1. Using @PostConstruct and @PreDestroy
13.2. Validate
14. Commands, Handlers, Menus, Toolbars and Popups
14.1. Overview
14.2. Menus and Toolbar
14.3. View Menus
14.4. Scope of handlers
14.5. Core expressions
14.6. Naming schema for command and handler ID
15. Tutorial: Defining and using Commands and Handlers
15.1. Defining Commands
15.2. Defining Handler classes
15.3. Defining Handlers in your model
15.4. Adding a Menu
15.5. Adding a Toolbar
15.6. Closing the application
16. Scope of injection
16.1. What can be injected?
16.2. How are objects searched?
16.3. What are the relevant classes and interfaces
16.4. Who creates the context for model elements?
17. Model elements and dependency injection
17.1. Available Model elements
17.2. Examples for model API
18. Extending the context and using it with own Java objects
18.1. Accessing the context
18.2. Putting objects in the context
18.3. Using dependency injection for own objects
19. Closing words
20. Thank you
21. Questions and Discussion
22. Links and Literature
22.1. Source Code

1. Eclipse 4

1.1. What is Eclipse 4?

Eclipse 4 introduces a new set of technologies which make the process of Eclipse plug-in development faster and more efficient. The next release of Eclipse 4 will be the Eclipse 4.2 release in June 2012. The Eclipse 3.x series will be stopped after the Eclipse 3.8 release. Eclipse 3.8 will be the last 3.x release and will be released parallel to Eclipse 4.2.

Eclipse 4 has the target to solve some of the problems Eclipse 3.x had. The major enhancements in Eclipse 4.x compared to Eclipse 3.x are:

  • The Eclipse application is available as a dynamic model at development and runtime.

  • Eclipse 4 supports dependency injection.

  • Eclipse widgets can be styled via external CSS files, similar to webpages.

  • The application model is decoupled from its presentation, e.g. different user interface toolkits, e.g. SWT or JavaFX, can be used to render the model.

Eclipse 4 provides a compatibility layer which allows that Eclipse 3.x plug-ins work unmodified on the new runtime.

The user of the Eclipse IDE, e.g a web developer or a Swing developer, will only indirectly benefit from Eclipse 4 because tool development of Eclipse becomes easier. Therefore the tooling of Eclipse 4 will become better over time.

1.2. What is the Eclipse e4 project?

"Eclipse e4" is the name of the project which created the Eclipse 4 product. Originally the term "e4" was used for the project as well as for the product. Today it is only the name of the project.

The Eclipse e4 project included also several evaluations which have not been ported to the core Eclipse framework. All functionality described in this description is part of the Eclipse 4 release except the "Eclipse e4 tooling".

The subproject "Eclipse e4 tooling" provides tools to develop Eclipse 4 applications. These tools are very useful for developing Eclipse 4 based applications.

Projects like XWT, TM or OpenSocial Gadgets which are also part of the Eclipse e4 project are not included in the Eclipse 4 platform and not described in this document.

2. Eclipse Extension points

2.1. What are Extension Points?

On top of OSGi the Eclipse framework provides also extension-points. Extension-points define interfaces for other plug-ins to contribute functionality (code and non-code ).

They are defined in the "plugin.xml" file, which must be in the root directory of your plug-in project. This file is an XML file which provides a user interface for editing this file.

Existing extensions (contributions) are collected during the start of an Eclipse application. The information in the extension points is converted into so-called descriptors and stored in registries.

The Eclipse IDE provides an editors for the "plugin.xml" file (via the so called Plug-in Development Environment).

2.2. Usage in Eclipse 4.x

In Eclipse 4 the usage of extension points is very limited. They are mostly used to define the settings for the application and to find components which contribute to the application model.

The org.eclipse.core.runtime.products extension point is used to define the Eclipse application.

org.eclipse.e4.workbench.model is used to define contributions to the Eclipse application model.

3. Tutorial: Install Eclipse 4.2 for RCP development

3.1. Step: Download and Install Eclipse

The Eclipse e4 projects creates regulary a Milestone build of Eclipse 4.2. Weekly (usually Tuesday night) an integration build is triggered.

The following assumes that you have Java installed in at least version 1.6.

Download the latest M-Build (4.2Mx) of Eclipse 4.2 from Eclipse Download Site for your platform. The download is a zip file.

Unzip the zip file onto your local directly. Do not use a path with spaces; this might lead to problems in the usage of Eclipse.

Double-click the Eclipse.exe (or the launcher icon specific to your platform) to start Eclipse.

Select an empty directory as the workspace. The workspace will contain all your project files and to avoid any collision with existing work we want to use a new one.

3.2. Step: Install the Eclipse 4 tooling

The Eclipse SDK download does not include the Eclipse e4 tooling, which makes working with Eclipse e4 easier. These tools provides wizards to create Eclipse 4 artifacts and the specialized model editor for the application model.

Please use the included e4 update site to install the e4 tooling via the Eclipse update manager.

Sometimes the included e4 tooling update site does not work, in this case use the following update site:

http://download.eclipse.org/e4/updates/0.12-I-builds/

If your Eclipse download reports incompatible versions and refuses to install the tooling you should try to download a newer version of Eclipse. In this case try the latest Integration Build.

The latest Integration Build of Eclipse 4.2 can also be found on the Eclipse Download Site under the "Stream Integration Builds" label.

3.3. Provisional API

Currently the Application Programming Interface (API) for Eclipse 4 is still marked as provisional, i.e. this means that the API might be changed in the future.

As Eclipse 4.2 now is able to run the Eclipse IDE, it is unlikely in the opinion of the author of this text, that dramatic changes will occur in the future.

Therefore it is relatively save to start using the API. But you must be prepared that you might do adjustments to your application.

Per default Eclipse will create warnings in your coding if you use provisional API. You can turn of these warnings via WindowPreferencesJavaCompilerErrors/Warnings and setting the "Discouraged Access" to ignore.

Turning of the Eclipse warnings

4. Tutorial: Eclipse 4 application using the wizard

4.1. Eclipse tooling

The Eclipse 4 tooling provides a project generation wizard. This wizard allows you to create an Eclipse 4 based RCP application.

4.2. Create project

Select FileNewOtherse4e4 Application Project .

Create the project de.vogella.e4.rcp.wizard using the default settings. This should be similar to the following screenshots.

This wizard created all necessary files to start your application. The central file for starting your application is the .product file, created in your project folder.

4.3. Launch

Open your "de.vogella.e4.rcp.wizard.product" product configuration file. Switch to the "Overview" tab and launch your product. This should start the generated Eclipse application.

5. Steps to create Eclipse 4 applications

5.1. Are Eclipse 4 applications still plug-ins?

Eclipse 4 based applications are standard Eclipse plug-ins with some additional file and configuration switches.

5.2. Converting a plug-in into an Eclipse 4 application

To convert an Eclipse plug-in into an Eclipse 4 RCP application you have to:

  • Create a product configuration which uses the predefined E4Application application for the org.eclipse.e4.ui.workbench.swt. package.

  • Maintain the dependencies regarding the necessary Eclipse 4 plug-ins.

  • Create a file which describes the Application model. This file is typically called Application.e4xmi.

  • In the plugin.xml file the application points to the Application model description file, via the property applicationXMI. The path to the file follows the "plug-in id"/filename" pattern, e.g. "com.example.e4.rcp/Application.e4xmi"."

5.3. Framework dependencies

Eclipse 4 applications require certain components of the Eclipse platform to run. The following plug-ins must be listed as dependency in the MANIFEST.MF file.

  • org.eclipse.core.runtime

  • org.eclipse.e4.ui.workbench

  • org.eclipse.e4.ui.workbench.swt

  • org.eclipse.e4.ui.workbench.renderers.swt

  • org.eclipse.e4.ui.css.swt.theme

  • org.eclipse.e4.core.services

  • org.eclipse.e4.core.di

  • org.eclipse.e4.core.contexts

  • org.eclipse.e4.ui.services

  • javax.inject

  • javax.annotation

  • org.eclipse.equinox.ds

  • org.eclipse.equinox.event

  • org.eclipse.swt

Most Eclipse 4 applications use the SWT toolkit, therefore the SWT plug-in is also included in the list.

If you enter all dependencies the resulting MANIFEST.MF should look similar to the following, except that your version might also include version numbers.

				
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Todo
Bundle-SymbolicName: de.vogella.e4.todo
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Require-Bundle: org.eclipse.core.runtime,
 org.eclipse.e4.ui.workbench,
 org.eclipse.e4.ui.workbench.swt,
 org.eclipse.e4.ui.workbench.renderers.swt,
 org.eclipse.e4.ui.css.swt.theme,
 org.eclipse.e4.core.services,
 org.eclipse.e4.ui.services,
 javax.inject,
 javax.annotation,
 org.eclipse.equinox.ds,
 org.eclipse.equinox.event,
 org.eclipse.swt,
 org.eclipse.e4.core.di,
 org.eclipse.e4.core.contexts

			

6. Eclipse 4 application model

6.1. What is the application model?

The visual part of an Eclipse application consists of Perspectives, Parts (Views, Editors), Menus etc. An Eclipse application also includes non-visual components, e.g. Handlers, Commands and Keybindings.

A Perspective is a visual container. Parts are the separate Windows within your application. Parts can be placed on top of each other if they are contained in a Stack. A SashContainer (Sash) allows to divide two elements either horizontally or vertically.

Eclipse 4 uses a model to describe an application. This application model contains the visual parts as well as some non-visual parts. Each model element has attributes which describe its current state, e.g. the size and the position for a Window. Model elements might be in a hierarchical order, for example Parts might be grouped below a Perspective.

The application model defines the structure of the application; it does not describe the content of the individual user interface components.

For example the application model describes which Parts are available. But it does not describe the content of the Part, e.g. the SWT Labels, Buttons etc. The content of the Parts is still defined via coding.

If the application model would be a house, it would describe the available rooms (Parts) and their arrangement (Perspectives, Stacks, Sashes) but not the furniture of the rooms. This is illustrated by the following image.

Limits of the modeled workbench

6.2. Where is the application model defined?

The workbench model is extensible. The basis of this model is typically defined as a static file. This file is typically called Application.e4xmi ; we assume this name for this tutorial.

The Eclipse application uses the org.eclipse.core.runtime.products extension point to specify the model file via the applicationXMI parameter.

The XMI file is read at start time of the application and the initial application model is constructed from this file.

6.3. How is the model connected to my Java classes?

Application model elements can contain references to Java classes via an URI.

The URI describes the location of the Java class The first part of this URI is the plug-in, the second one the package and the last one the class.

For example a model description for a part (View or Editor) contains attributes as for example label, tooltips, icon URI's, etc. It also contains a class URI which points to a Java class for this element. If the model elements get activated this class will get instantiated.

The following will call the objects created based on the application model "model objects".

6.4. URI in the Model

URI's follow two patterns. One for identifying resources and another one for identifying classes.

Table 1. URI patter

Pattern Description
bundleclass://Bundle-SymbolicName/package.classname Used to identify Java classes. It consists of the following parts: "bundleclass://" is a fixed schema, Bundle-SymbolicName as defined in the MANIFEST.MF file, package for the package of the Java class and classname is the name of the Java class. For example: bundleclass://com.example.e4.playground3/com.example.e4.playground3.parts.MySavePart
platform:/plugin/Bundle-SymbolicName/path/filename.extension Identifier for a resource in the plug-in. "platform:/plugin/" is a fixed schema, followed by the Bundle-SymbolicName of the MANIFEST>MF file, followed by the path to the file and the filename, Example: platform:/plugin/com.exmaple.e4.playground3/icons/save_edit.gif

6.5. Application model editor

The Eclipse tooling project provides a specialized model editor which makes it easier to work on an application model.

To open the model editor double-click on your Application.e4xmi file (or right click on it and select Open-withe4 Workbenchmodel Editor .

Open editor for the Eclipse modeled workbench

6.6. Model Add-ons

Eclipse 4 tries to keep the core framework as minimal as possible. Additional functionality to the model is provided by Add-ons to the model. These add-ons can be registered to the model and can enhance the application.

Currently the following Add-ons are useful for Eclipse applications. Their class names give a relative good indication of their provided functionality, check their Javadoc to get a short description of their purpose.

Table 2. Model Add-ons

Add-on ID Class
org.eclipse.e4.core.commands.service CommandServiceAddon
org.eclipse.e4.ui.contexts.service ContextServiceAddon
org.eclipse.e4.ui.bindings.service BindingServiceAddon
org.eclipse.e4.ui.workbench.commands.model CommandProcessingAddon
org.eclipse.e4.ui.workbench.contexts.model ContextProcessingAddon
org.eclipse.e4.ui.workbench.bindings.model BindingProcessingAddon


Use the bundleclass:// URI convention to add Add-ons to your application model.

Having these Add-ons registered allows to enhance or replace them by the Eclipse platform team or by a customer specific implementation in case the need arises.

Additional Add-ons are available, e.g. to support drag and drop of Parts in your application.

To support drag-and-drop for Parts add the DnDAddon class and the CleanupAddon class from the org.eclipse.e4.ui.workbench.addons.swt bundle as Add-ons to your “Application.e4xmi”.

Add the org.eclipse.e4.ui.workbench.addons.swt plug-in to your product to use these two plugins.

6.7. Model access at runtime

The application model is also available at runtime. The application can access the model and change it via a defined API. We will later have a look at this API.

Add the org.eclipse.e4.tools.emf.liveeditor plug-in and its dependencies to your launch configuration to add the model editor to your application.

Afterwards you can open the model editor for your running application via the ALT+Shift+F9 shortcut. This also works for the Eclipse 4 IDE.

Using the model editor you can change your application model directly at runtime. Most changes are directly applied, e.g. if you change the orientation of a perspective your user interface will update itself automatically.

You can also select the part element, right click on it and select "Show Control" to get it highlighted.

6.8. Application model and Dependency Injection

During startup the Eclipse runtime creates the application model and instantiates the referred classes in the model if required.

The life cycle of every model object is therefore controlled by the Eclipse runtime. The Eclipse runtime instantiates and destroys the model objects.

This is important for the programming model of Eclipse 4, as it supports the usage of dependency injection for the model objects.

7. Tutorial: Create an Eclipse plug-in

7.1. Create an Eclipse plug-in

In the following tutorial we will create a standard Eclipse Plug-in called "com.example.e4.rcp.todo".

In Eclipse select FileNew Project

Selection the Eclipse Plug-in Wizard

Give your plug-in the name "com.example.e4.rcp.todo".

First page of the Eclipse Plug-in Wizard specifying the project name.

Press "Next" and make the following settings. Select "No" at the question "Would you like to create a rich client application" and "This plug-in will make contributions to the UI"". Unflag the "Generated an activator, a Java class that controls the plug-ins life-cycle." option.

Second page of the Eclipse Plug-in Wizard specifying the plug-in ID, version, Name, Activator and the RCP type.

Press the "Finish" button; we will not use a template.

7.2. Investigate project

Open the project and check if Java classes were created. You should have no classes in the source folder.

Open the "MANIFEST.MF" file and switch to the tab "Extensions". Validate that the list of Extensions is currently empty.

8. Tutorial: From Plug-in to Eclipse 4 application

In the following we add the additional configuration so that your Eclipse plug-in can be used as Eclipse 4 application.

8.1. Enter plug-in dependencies

Add the required plug-ins as dependency to your plug-in configuration file. For this open the "MANIFEST.MF" file in the "META-INF" folder and select the tab "Dependencies".

The following shows a screenshot of the dependency tab.

The individual plug-ins are the following:

  • org.eclipse.core.runtime

  • org.eclipse.e4.ui.workbench

  • org.eclipse.e4.ui.workbench.swt

  • org.eclipse.e4.ui.workbench.renderers.swt

  • org.eclipse.e4.ui.css.swt.theme

  • org.eclipse.e4.core.services

  • org.eclipse.e4.core.di

  • org.eclipse.e4.core.contexts

  • org.eclipse.e4.ui.services

  • javax.inject

  • javax.annotation

  • org.eclipse.equinox.ds

  • org.eclipse.equinox.event

  • org.eclipse.swt

8.2. Create Product configuration

Create the "todo.product" product definition file which uses the E4Application. Right click on your project and select NewProduct Configuration

To define that your product uses the E4Application application, press the "New" button on the "Overview" tab of the product editor. Enter "To-do" as the name, "product" as ID. The defining plug-in is your plug-in and we must use the E4Application.

8.3. Create Application model

Create the "Application.e4xmi" application model file directly in your plug-in directory. Select FileNewOthere4 ModelNew Application Model.

This will create the "Application.e4xmi" file and open this file an the application model editor.

Add one Window to your application model to have a visual component.

Select the "Windows" node and press the "+" Button (which will be called the "Add" Button in this description) for a TrimmedWindow.

Enter a default height and width and a label as in the following screenshot.

Enter the data for the TrimmedWindow in the model editor

8.4. Link application model to your product

You will now connect the application model with your product configuration. You may have to close and re-open the editor for the "plugin.xml" file to see the existing contribution to the extension point. See Bug report for incorrect initial display of plugin.xml for details on this problem.

Open the "plugin.xml" file, select the "Extensions" tab and open the org.eclipse.core.runtime.products contribution.

Right click on the "product" entry and select New Property. Use "applicationXMI" as name and "com.example.e4.rcp.todo/Application.e4xmi" as value. This value consists out of your plug-in name and the file name of your application model file.

8.5. Enter Product dependencies

Open your product configuration file and switch to the tab "Dependencies". Press the "Add" button and add your own "com.example.e4.rcp.todo" plug-in as dependency. Afterwards press "Add Required Plug-ins".

This should add all dependencies you defined in the "MANIFEST.MF" file to your product configuration file.

8.6. Validate registered model Add-ons

In your project you will use functionality provided by model Add-ons. Fortunately the wizard for creating the "Application.e4xmi" file added these Add-ons already. For completeness here is a list of the registered Add-ons.

Table 3. Model Add-ons

Add-on ID Class
org.eclipse.e4.core.commands.service CommandServiceAddon
org.eclipse.e4.ui.contexts.service ContextServiceAddon
org.eclipse.e4.ui.bindings.service BindingServiceAddon
org.eclipse.e4.ui.workbench.commands.model CommandProcessingAddon
org.eclipse.e4.ui.workbench.contexts.model ContextProcessingAddon
org.eclipse.e4.ui.workbench.bindings.model BindingProcessingAddon


8.7. Start Application

Open the product file and select the "Overview" tab. Press the "Launch an Eclipse application" hyperlink in the "Testing Section".

Starting the product

Validate that your application starts. It should be an empty application, which can be moved and closed.

9. Tutorial: Modeling a User Interface

9.1. Adding model element

In the following you will extend the minimal Eclipse 4 application. After this change, your user interface should look like the following:

You will add Perspective to the Window. This Perspective will contain a SashPartContainer, which will contain two Stacks. Each stack will get one Part assigned to it.

Open the "Application.e4xmi" file. Go to your Window and select the "Controls" node. Add a PerspectiveStack. Press the "Add" Button to create a "Label" entry. Enter the value "To-Do" in the field label and the value "com.example.e4.rcp.todo.simple" in the field ID.

Select "Controls" below the newly created Label and add a "PartSashContainer". Change its "Orientation" attribute to "Horizontal".

Change the orientation attribute

In the drop-down list of the "PartSashContainer" select "PartStack" and press the "Add" button to add a stack. Re-select the "PartSashContainer" and add another "PartStack".

Adding a Stack to a PartSashContainer

Add a "Part" to each Stack. The Part in the first "PartStack" should get the "com.example.e4.rcp.parts.todooverview" ID and the "To-Dos" label. The second part should get the "com.example.e4.rcp.parts.tododetail" ID and the "Details" label.

Start your product and validate that the user interface looks as planned.

Please note that so far, you have not created a Java class for our application.

9.2. Create model objects

In the following you will create two Java objects (model objects) and connect them to the application model.

Create the com.example.e4.rcp.todo.parts package.

Create two Java classes called "TodoOverviewPart" and "TodoDetailsPart" in this package. These classes do not extend another class, nor do they implement any Interface, i.e. they are "plain old Java objects" (POJO's).

Connect the TodoOverviewPart class with the model element for the Part with the com.example.e4.rcp.parts.todooverview ID. You can do this via the "Class URI" property of the Part model element.

Connect the TodoDetailsPart class with the Part with the com.example.e4.rcp.parts.tododetail ID.

Run your application. It should start, but you should see no difference in your user interface.

To validate that the model objects are create a no-argument constructor, e.g. with no parameters, for one of the classes and add a System.out.println() statement. Afterwards verify that the constructor is called, once you start your application.

10. Dependency Injections and Annotations

10.1. What is Dependency Injection?

The general concept between dependency injection is called Inversion of Control. A class should not configure itself but should be configured from outside.

Dependency injection is a concept which is not limited to Java. But we will look at dependency injection from a Java point of view.

A Java class has a dependency to another class if it uses this class as a variable. For example a class which accesses a logger service has a dependency to this service.

Ideally Java classes should be as independent as possible from other Java classes. This increases the possibility to reuse these classes and to test them independently from other classes, for example for unit testing.

If the Java class directly creates an instance of another class via the new() operator, it cannot be used and tested independently from this class.

To decouple Java classes its dependencies should be fulfilled from the outside. A Java class would simply define its requirements like in the following example:

			
public class MyPart {
	
	@Inject private Logger logger;
	// DatabaseAccessClass would talk to the DB
	@Inject private DatabaseAccessClass dao;
	
	@Inject
	public void init(Composite parent) {
		logger.info("UI will start to build");
		Label label = new Label(parent, SWT.NONE);
		label.setText("Eclipse 4");
		Text text = new Text(parent, SWT.NONE);
		text.setText(dao.getNumber());
	}

}
		

Another class could read these dependencies and create an instance of the class, injecting objects into the defined dependency. This can be done via the Java reflection functionality. This class is usually called the dependency container.

This way the Java class has no hard dependencies. For example if you want to test a class which uses another object which directly uses a database, you could inject a mock object.

Mock objects are objects which act as if they are the real object but only simulate their behavior. They mock to be these objects, therefore the name.

If dependency injection is used, a Java class can be tested in isolation, which is good.

Dependency injection can happen on:

  • the constructor of the class (construction injection), defines a hard dependency

  • a setter (setter injection), defines a soft dependency

  • a field (field injection), defines a soft dependency

10.2. Define dependencies in Eclipse

Eclipse 4 supports field, constructor and method injection. It uses the standard Java @Inject and @Named annotations, which were defined in the Java Specification Request 303 (JSR303). In addition to these standard annotations, it declares the @Optional and @Preference annotations

The following table gives an overview of the dependency injection (DI) annotations.

Table 4. Annotations for Dependency Injection

Annotation Description
@javax.inject.Inject Marks a field, a constructor or a method. The Eclipse framework tries to inject the parameter.
@javax.inject.Named Defines the name of the key for the value which should be injected. By default the fully qualified class name is used as key. Several default values are defined as constants in the IServiceConstants interface.
@org.eclipse.e4.core.di.annotations.Optional Marks an injected value to be optional, so if it can’t be found no error is thrown. This also ensures that the value is unset if the injected value is set to null.
@org.eclipse.e4.core.di.extensions.Preference Eclipse can store key/values as so-called preferences. The @Preference annotation defines that the annotated value should be filled from the preference store. Eclipse can store key/values as so-called preferences.


10.3. What can get injected?

Eclipse allows to use DI for objects, OSGi services and Preferences. We will later learn where Eclipse searches for things to inject.

10.4. How does dependency injection work in Eclipse 4?

We learned that the Eclipse 4 runtime instantiates the Java classes referred by the model once this is required. During this instantiation the Eclipse runtime scans every object for annotations.

Based on the DI annotations the Eclipse framework performs the injection. Field and constructor injections are performed immediately once the class is instantiated.

Methods which are annotated with DI annotation will get there values injected once these methods are executed by the Eclipse framework.

Constructors are called before the fields are injected. Accessing a injected field in the constructor will result in an error.

The Eclipse framework also tracks the injected values and if they change, it will re-inject the new values. For example you can define that you want to get the current selection injected. If the selection changes, Eclipse will inject the new value.

11. Tutorial: Using dependency injection

11.1. Getting a Composite

In the following tutorial we extend our classes to use dependency injection.

Change the TodoOverviewPart class to the following:

				
package com.example.e4.rcp.todo.parts;

import javax.inject.Inject;

import org.eclipse.swt.widgets.Composite;

public class TodoOverviewPart {
	
	
	@Inject 
	public TodoOverviewPart(Composite parent) {
		if (parent != null) {
			// Print the layout to the console
			System.out.println("Got Composite via DI.");
			System.out.println("Composite has even a Layout: " + parent.getLayout().getClass());
		} else {
			System.out.println("No Composite available.");
		}
	}
}
			

11.2. Validation

Run your application and check in the console View of your Eclipse IDE, if the parameter Composite got injected or not. Note down the LayoutManager class which the Composite got assigned, if it is not null.

12. Behavior Annotations

12.1. API definition via inheritance

Each framework defines an application programming interface (API).

If you use a framework you need to have a convention which methods are called at which point of the execution of your program. For example if a Java class is responsible for handling a toolbar button click, the framework needs to know which method of this class it should call.

The "traditional" way of defining an API is via inheritance. This approach requires that your classes extend or implement framework classes and interfaces. This is how Eclipse 3.x defined its API.

The framework defines for example via an abstract class which methods must be implemented. In the above example the method might be called execute() and the framework knows that this method must be called once the toolbar button is clicked.

For example in Eclipse 3.x a View would extend the abstract ViewPart class. This class defines the createPartControl() method.

The Eclipse 3.x framework knows that createPartControl() is responsible for creating the user interface and calls this method once the View becomes visible.

API definition via inheritance is a simple way to define an API, but it also couples the classes tightly to the framework. For example testing the class without the framework is difficult.

12.2. API definition via annotations

Eclipse 4 does not require that classes extend framework classes. Eclipse 4 uses annotations to indicate that a certain behavior is expected from the framework.

I like to call these annotations "behavior annotations".

Behavior annotations are used to indicate that certain methods should be called at certain events. The following tables list the available behavior annotations.

Table 5. Eclipse behavior annotations

Annotation Description
@PostConstruct Eclipse calls this method once the class is constructed and the field injection has been performed.
@PreDestroy Eclipse calls this method before the class is destroyed. Can be used to clean up resources.
@Execute Marks a method in a command to be executed
@CanExecute Marks a method to be visited by the Command- Framework to check if a command is enabled
@Focus Indicates that this method should be called, once the Part gets the focus.
@Persist annotates method. If used in a Part-POJO this method will be called when the workbench issues a save-request.


All these annotations will also trigger dependency injections. Therefore you do not need to add the @Inject annotation, if you use these annotations.

The org.eclipse.e4.core.di.annotations package contains the @PostConstruct, @PreDestroy, @Execute, @CanExecute annotations.

@Persists and @Focus are part of the org.eclipse.e4.ui.di package.

12.3. Lifecycle Hooks

Eclipse 4 provides the possibility to register a class to events of the lifecycle of the application model. For example you can use these lifecycle hooks to create a login screen.

The org.eclipse.core.runtime.product extension point allows to define this lifecycle class class with a property with the lifeCycleURI key.

This property points to a class via the bundleclass:// schema.

In the lifecycle class you can use the following annotations. The annotated methods will be called by the framework depending on the life cycle of your application.

Table 6. Life Cycle Annotations

Annotation Description
@PostContextCreate Is called after the IEclipseContext is created, can be used to add objects to the context.
@ProcessAdditions Is called directly before the model is passed to the renderer, can be used to add additional elements to the model.
@ProcessRemovals Same as @ProcessAdditions but for removals.
@Presave Is called before the application model is saved. You can modify the model before it is persisted.

13. Tutorial: Define Part Lifecycle

13.1. Using @PostConstruct and @PreDestroy

In the following tutorial we use the @PostConstruct and @PreDestroy annotations.

Add the following method to your TodoOverviewPart and TodoDetailsPart class.

				
public void createControls(Composite parent) {

}
			

Annotate the method with @PostContruct.

Create an empty public void dispose() method and annotate it with @PreDestroy.

Remove all constructors from your classes.

13.2. Validate

Run your application and validate that the @PostContruct method is called. Use either debugging or a System.out.println() statement. If you are familiar with SWT, add a few controls to your user interface.

14. Commands, Handlers, Menus, Toolbars and Popups

14.1. Overview

The Eclipse application model can also contain commands, handlers and keybinding.

A command in Eclipse is a declarative description of a component and is independent from the implementation details.

The behavior of a command is defined via a handler. A handler defines a class via the contributionURI attribute of the handler. This attribute is displayed as "Class URI" in the model editor.

This class uses the @Execute annotation to define which method is called once the handler is executed. The @CanExecute annotation defines the method which evaluates if the handler is currently active.

@CanExecute is called by the framework if the SWT.SHOW event happens. This event is for example triggered if a new Part is displayed.

Also if you add items to the toolbar, a timer automatically registered by the Eclipse framework will, as of the time of this writing, execute every 400 Milliseconds. This timer will check the @CanExecute to enable or disable the related toolbar entry.

14.2. Menus and Toolbar

You can add menus and toolbars to the application model for the Window and for Parts. Menu and toolbars items contain references to commands. If a command is select the runtime will determine the relevant handlers for the command.

For simple cases you can also use the "Direct MenuItem" or a "Direct ToolItem", which allows to define a handler class directly.

A trimbars can be defined for Windows. Here you can decide if they should be placed on the top, left, right or bottom.

The related command is assigned to the menu and toolbar entry. Menus support separators and submenus.

14.3. View Menus

To show a menu for a View you have to add a tag to the corresponding entry in the "Application.e4xmi" file. This tag must be defined before the menu children are defined and looks like the following.

				
<tags>ViewMenu</tags>
			

Unfortunately this tag is currently not added by the model editor and you have to add this manually. Here is an example for such an entry.

				
<menus xmi:id="_97aYcEzrEeGWA5PIedy0eQ" elementId="viewmenutest" 
	label="viewmenutest Label">
	<tags>ViewMenu</tags>
    <children xsi:type="menu:HandledMenuItem" xmi:id="_JuWbAEzsEeGWA5PIedy0eQ" 
    	elementId="handledViewMenu" label="Test" tooltip="kk" 
    	command="_rR8PMEq3EeGHfpgriXYg9Q"/>
</menus>
			

14.4. Scope of handlers

Each command can have only one valid handler for a given scope. The application model allows to define handler for the application, specific for a Window and for a for an Part.

If more then one handler is defined for a command, Eclipse will select the handler most specific to the model element.

For example if you define a handler for the "Copy" command for your Window and if you define another "Copy" handler for your Part, the runtime will select the handlers closest to model element.

During this evaluation the @CanExecute is considered, e.g. if the "Copy" handler for a Part is not active at a given point the workbench will call the handler defined on the Window.

14.5. Core expressions

The visibility of menus, toolbars and their entries can be restricted via the core expressions. You add the corresponding attribute in the application model to the ID defined by the org.eclipse.core.expressions.definitions extension point.

This approach is similar to the definition of core expressions in Eclipse 3.x.

14.6. Naming schema for command and handler ID

A good convention is to start IDs with the top level package name and to use only lower cases. Handler IDs should use the command ID as a prefix and add the suffix "handler".

For example if you implement a command with the "com.example.contacts.show" you should use "com.example.contacts.show.handler" as ID for the handler. If you have more then one handler defined, add another suffix to it, describing its purpose, e.g. "com.example.contacts.show.handler.details".

If case you implement commonly used functions, e.g. save, copy, you should use the existing platform IDs, as some Eclipse contributions expect these IDs.

Table 7. Default IDs for commonly used commands

Command ID
Save org.eclipse.ui.file.save
Save All org.eclipse.ui.file.saveAll
Undo org.eclipse.ui.edit.undo
Redo org.eclipse.ui.edit.redo
Cut org.eclipse.ui.edit.cut
Copy org.eclipse.ui.edit.copy
Paste org.eclipse.ui.edit.paste
Delete org.eclipse.ui.edit.delete
Import org.eclipse.ui.file.import
Export org.eclipse.ui.file.export
Select All org.eclipse.ui.edit.selectAll
About org.eclipse.ui.help.aboutAction
Preferences org.eclipse.ui.window.preferences
Exit org.eclipse.ui.file.exit

15. Tutorial: Defining and using Commands and Handlers

15.1. Defining Commands

You will now define commands and handlers for your application. Open the "Application.e4xmi" file and select "Commands". We will define our handlers application-wide.

Adding commands to your application

Via "Add" you can create new commands. The name and the ID are the important fields. Create the following commands.

Table 8. Commands

ID Name
org.eclipse.ui.file.save Save
org.eclipse.ui.file.exit Exit
com.example.e4.rcp.todo.new New Todo
com.example.e4.rcp.todo.remove Remove Todo
com.example.e4.rcp.todo.showmap Show Map


15.2. Defining Handler classes

Create the com.example.e4.rcp.todo.handlers package for your handler classes.

All handler classes will implement the execute() method.

				
package com.example.e4.rcp.todo.handlers;

import org.eclipse.e4.core.di.annotations.CanExecute;
import org.eclipse.e4.core.di.annotations.Execute;

public class SaveHandler {
	@Execute
	public void execute() {
	}

	@CanExecute
	public boolean canExecute() {
		return true;
	}

}
			

Using this templates for all classes, implement the following classes.

  • ExitHandler

  • NewTodoHandler

  • RemoveHandler

  • SaveHandler

  • ShowMapHandler

15.3. Defining Handlers in your model

Select the entry "Handlers" in your application model and create the following handlers for your command. For the definition of handlers the ID, the command and the class is relevant information.

The application model editor shows both the name and the ID of the command, in the following table we just add .handler to each command ID for its handler. Therefore it should be clear which command the handler should be referring to.

The class URI follows the bundleclass:// schema, we only define the class name to make the table more readable.

Table 9. Handlers

ID Referred Class
org.eclipse.ui.file.save.handler SaveHandler
org.eclipse.ui.file.exit.handler ExitHandler
com.example.e4.rcp.todo.new.handler NewTodoHandler
com.example.e4.rcp.todo.remove.handler RemoveTodoHandler
com.example.e4.rcp.todo.showmap.handler ShowMapHandler

15.4. Adding a Menu

You will now add a Menu to your application model.

Select "Application.e4xmi". To add a menu to a Window or TrimmedWindow select the entry in the model and flag the "Main Menu" attribute.

Add two menus, one with the name "File" and the other one with the name "Edit". You only need to enter the "Label" attribute.

Creating a menu

Add a "HandledMenuItem" to the ""File" menu. This item should point to the save command.

Adding a menu item to the menu

Add a "Separator" after the save menu item and add after that an entry for the exit command.

Add all other commmands to the "Edit" menu.

15.5. Adding a Toolbar

Select the node "TrimBars" in your application model and press the add button. The "Side" attribute should be set to "Top" so that all toolbars assigned to that TrimBar appear on the top of the application.

Add a "ToolBar" to your TrimBar. Add a "Handled ToolItem" to this ToolBar, which points to the org.eclipse.ui.file.save command.

Set the label for this entry to "Save".

Adding a menu item to the menu

15.6. Closing the application

To test if your handler is working, change your ExitHandler class, so that it will close your application.

				
package de.vogella.e4.todo.handler;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.workbench.IWorkbench;

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


			

16. Scope of injection

16.1. What can be injected?

We covered how dependency injection works and which annotations can be used to define the behavior of the Java classes. But we have not yet covered what the scope of injection is, e.g. what you can inject into your model classes.

The Eclipse runtime creates a context in which the possible values for injection can be stored. This context can be modified, e.g. the application and the framework can add elements to the context.

The Eclipse context contains:

  • all objects associated with the workbench model

  • all other objects which have explicitly been added to the context

  • all Preferences - key/value pairs which typically used to configure the application

  • OSGi services - software components which can be dynamically consumed

16.2. How are objects searched?

All possible values for dependency injection can be accessed via the context.

The context contains Java objects which can be accessed via keys. Access to the context works similar to accessing a Java Map data structure.

Internally the context is not a flat structure like a Java map, it is hierarchical and can also dynamically compute values for requested keys.

A context can be local to an object and can have a parent context.

Each model element has its own context assigned to it. The main context is created by the Eclipse Framework and all context objects of the model elements are hierarchically connected to the main context object.

Model objects that implement the MContext interface have their own local context. This is for example the case for MWindow and MPart. Each context for a model element contains a reference to the Model object itself.

If for example a part requests object by a certain key from the context, Eclipse will first search for this object in the local context of the part. If it does not find the key in the local context it will search the parent context. This process continues until the main context has been reached. At this point the framework would check for fitting OSGi services in the OSGi registry.

This happens transparently for the caller of the context and is considered as an implementation detail.

16.3. What are the relevant classes and interfaces

The interface for the context object is the IEclipseContext interface.

The OSGiContextStrategy class is responsible for searching for OSGi service if the Eclipse framework does not find the requested key in the hierarchy of IEclipseContext objects.

16.4. Who creates the context for model elements?

Eclipse 4 has a flexible renderer framework. For each model element the framework determines a renderer class which is responsible for creating the Java object associated with the model element. This renderer class creates, if required, the local context for the model element and connects this local context to the context hierarchy.

For example the ContributedPartRenderer class is responsible for creating the Java objects for Parts in the model. The interface for Parts is MPart.

ContributedPartRenderer creates a Composite for every Part and injects this Composite into the local context of the Part.

17. Model elements and dependency injection

17.1. Available Model elements

We have learned about the model workbench and dependency injection. As the model is interactive you can change it at runtime, for example you can change the size of the current window, add Parts to your application or remove menu entries.

But what is the best way to access these models?

Model elements have Java classes associated with them. We will later learn how we can access these elements via dependency injection. As the model is interactive you can use these model elements to change its attributes or children.

The following is a table of important model elements based on their Java classes.

Table 10. Eclipse 4 model element

Model element Description
MApplication Describes the application object. Can be used for example to add new windows to your application
MWindow Represents a Window in your application.
MTrimWindow Represents a Window in your application. The underlying SWT shell has been created with the SWT.SHELL_TRIM attribute which means, it has a tile, a minimize, maximize and resize button.
MPerspective Object for the perspective model element.
MPart Represents the model element part, e.g. a View or a Editor.
MDirtyable Property of MPart which can be injected. If set to true, this property informs the mode that this Part contains unsaved data (is dirty). In a Handler you can query this property can trigger a save.
MPartDescriptor MPartDescriptor is a template for new Parts. You define in your application model a PartDescripter. A new Part based on this PartDescriptor can be created with the via the EPartService and its showPart() method.


17.2. Examples for model API

To create new model objects you can use the MBasicFactory.INSTANCE class. This is a factory to create new model objects via typed create*() methods. For example you can create a new Window at runtime via the following snippet.

				
// Create a new window and set its size
MWindow window = MBasicFactory.INSTANCE.createTrimmedWindow();
window.setWidth(200);
window.setHeight(300);

// Create a new part and assign it to the window
MPart part = MBasicFactory.INSTANCE.createPart();
window.getChildren().add(part);

// Add new Window to the application
application.getChildren().add(window);
			

The following snippet demonstrates how to use the MDirtyable model property in a part to flag it as a Part which should be saved by the corresponding workbench action.

				
import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.eclipse.e4.ui.di.Persist;
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;

public class MySavePart {

	@Inject
	MDirtyable dirty;

	@PostConstruct
	public void createControls(Composite parent) {
		Button button = new Button(parent, SWT.PUSH);
		button.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				dirty.setDirty(true);
			}
		});
	}

	@Persist
	public void save() {
		System.out.println("Saving data");
		// Save the data
		// ...
		// Now set the dirty flag to false
		dirty.setDirty(false);
	}

}
			

For example the following ads a new part to the currently active window.

				
package testing.handlers;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
import org.eclipse.e4.ui.model.application.ui.basic.MBasicFactory;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;

public class AddPartHandler {
	@Execute
	public void execute(MWindow window) {
		MPart part = MBasicFactory.INSTANCE.createPart();
		part.setLabel("New part");
		part.setContributionURI("platform:/plugin/testing/testing.MyView");
		window.getChildren().add(part);

	}
}

			

18. Extending the context and using it with own Java objects

18.1. Accessing the context

To access an existing context you can use dependency injection, if the relevant object is managed by the Eclipse runtime, i.e. if you are using a model object.

				
package com.example.e4.rcp.todo.handlers;

import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Execute;

public class ShowMapHandler {
	@Execute
	public void execute(IEclipseContext context) {
		// Add objects to this local context of this handler
		// ...
	}

}
			

				
package com.example.e4.rcp.todo.handlers;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.equinox.app.IApplicationContext;

public class ShowMapHandler {
	@Execute
	public void execute(IApplicationContext context) {
		// Add objects to the application context 
		// This way is would be accessible for other 
		// model objects
		// ...
	}

}
			

Alternatively if your model object extends MContext you can use DI to get the model object injected and use the getContext() method to access its context. For example Parts, Windows, Applications and Perspectives extend MContext.

				
package com.example.e4.rcp.todo.parts;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.swt.widgets.Composite;

public class TodoDetailsPart {

	@PostConstruct
	public void createControls(Composite parent, MPart part) {
		IEclipseContext context = part.getContext();
	}
}
			

If you are outside of a model object, you still can access the global context via the following:

				
public Object start() {
  // Get Bundle Information
  Bundle bundle = FrameworkUtil.getBundle(getClass());
  BundleContext bundleContext = bundle.getBundleContext();
  IEclipseContext eclipseCtx =   
      EclipseContextFactory.getServiceContext(bundleContext);

  // Fill Context with information using set(String,Object)
  // ....
  
  // Create instance of class
  ContextInjectionFactory.make(MyPart.class, eclipseCtx);
}

			

18.2. Putting objects in the context

The recommended way to add objects to the context is to use OSGi services. OSGi services are automatically available in the context.

Sometimes it might be more efficient to add objects directly to the IEclipseContext. For example you want to test your Java objects and want to supply mock (test) objects to them via dependency injection.

If you want to add new objects to an existing context, it is best practice to create a new context and set the existing context as parent of the new one via the setParent() method.

To create a new context, you can use the EclipseContextFactory.create() factory method call. Adding objects to it can be done via the set() method on IEclipseContext.

				
@Inject
public void addingContext(IEclipseContext context) {
	// We want to add objects to context

	// Create instance of class
	IEclipseContext myContext = EclipseContextFactory.create();

	// Putting in some values
	myContext.set("mykey1", "Hello1");
	myContext.set("mykey2", "Hello2");

	// Adding a parent relationship
	myContext.setParent(context);

}


			

18.3. Using dependency injection for own objects

Using dependency injection is not limited to the objects created by the Eclipse runtime. You can use @Inject in a Java class and use the dependency injection framework to create your class.

				

// Create instance of class
ContextInjectionFactory.make(MyJavaObject.class, context);

			

For this you can either use an existing context as described in the last section or a new context.

				
IEclipse context = EclipseContextFactory.create();

// Add your Java objects to the context
context.set(MyDataObject.class.getName(), data);
// Add your Java objects to the context
context.set(MoreStuff.class.getName(), moreData);




			

19. Closing words

I hope you enjoyed this introduction into the Eclipse 4 framework. Of course there is much more, check out the "Eclipse 4 development" section under my lists of Eclipse Plug-in and Eclipse RCP Tutorials section.

20. Thank you

Please help me to support this article:

Flattr this

21. 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.

22. Links and Literature

22.1. Source Code

Source Code of Examples

http://wiki.eclipse.org/E4 Eclipse E4 - Wiki

Ecipse 4 RCP Wiki

Eclipse RCP

Eclipse EMF

Dependency Injection