Version 6.3
Copyright © 2009 , 2010 , 2011 , 2012 Lars Vogel
20.04.2012
| Revision History | ||
|---|---|---|
| Revision 0.1 | 14.02.2009 | Lars Vogel |
| created | ||
| Revision 0.2 - 6.3 | 16.02.2009 - 20.04.2012 | 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
Eclipse 4 introduces a new set of technologies which increase the flexibility of Eclipse plug-in development. The next simultaneous release of Eclipse named Juno in June 2012 will be based on Eclipse 4.2.
Eclipse 3.8 will be released in parallel to Eclipse 4.2 but the Eclipse 3.x series will be discontinued after the Eclipse 3.8 release, e.g. there will not be a Eclipse 3.9 release. Eclipse 3.8 will receive bug fixes for a year via service releases.
Eclipse 4 has the goal to solve some of the pain points of Eclipse 3.x development. The major enhancements in Eclipse 4.x compared to Eclipse 3.x are:
The Eclipse application is described via a defined structure called the application model.
This application model is available and can be modified at development and runtime.
Eclipse 4 supports dependency injection.
Eclipse widgets can be styled via CSS like 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 to run Eclipse 3.x plug-ins unmodified.
Eclipse 4 primarily contains enhancements for Eclipse based development. The user of the Eclipse IDE, e.g. a web developer or a Swing developer, will only indirectly benefit because tool development of Eclipse becomes easier. This allows the Eclipse developers to create better tools for the Eclipse users.
"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 e4 project includes several technology evaluations. Some of these evaluations have have been ported back to the core Eclipse framework. All functionalities in this description are part of the official Eclipse 4 release, except of the "Eclipse e4 tooling" project.
The subproject "Eclipse e4 tooling" provides tools to develop Eclipse 4 applications. They are very useful, but have not been added to the Eclipse core because they are not as mature as the other components.
Projects like XWT, TM or OpenSocial Gadgets, which are also part of the Eclipse e4 project, are not included in the standard Eclipse 4.2 core platform and are not described in this document.
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.
Eclipse 4.2 already runs the complete Eclipse IDE. Therefore it is unlikely that dramatic changes will occur in the future.
It is therefore relatively safe to start using the API now, but nevertheless you must be prepared that you might have to do adjustments to your application.
An Eclipse application consists of individual software components. The Eclipse IDE can be viewed as a special Eclipse application with the focus to support software development.
The components of the Eclipse IDE are primarily the following.

OSGi is a specification which describes a modularity approach for Java application. Equinox is one implementation of OSGi and is used by the Eclipse platform. The Equinox runtime provides the necessary framework to run a modular Eclipse application.
SWT is the standard UI component library used by Eclipse and JFace provides some convenient API on top of SWT. The workbench provides the framework for your application. The workbench is responsible for displaying all other UI components.
On top of these base components, the Eclipse IDE adds components which are important for an IDE application, for example the Java Development Tools (JDT) or version control support (EGit).
Eclipse 4 has a different programming model then Eclipse 3.x. Therefore the "3.x Compatibility Layer" components maps the 3.x API to the 4.0 API. This allows to run Eclipse 3.x based components unmodified on Eclipse 4.
Eclipse based applications which are not primary used as software development tools are called Eclipse RCP applications. An Eclipse 4 RCP application typically use the base components of the Eclipse platform and add additional application specific components.

Equinox allows to define dynamic software components, i.e. OSGi services, which can also be part of an Eclipse based application.
An Eclipse application consists out of several Eclipse components. A software component in Eclipse is called "Plug-in". A software component in OSGi is called "bundle". Both terms can be used interchangeably.
This description uses the terms "Eclipse based applications", "Eclipse application", "Eclipse 4 application" and "Eclipse RCP application" interchangeably for referring to an application which is based on the Eclipse 4 framework.
If a certain concept refers to Eclipse 3.x, then it is explicitly stated.
An Eclipse plug-in has the following main configuration files.
MANIFEST.MF - contains the OSGi configuration information.
plugin.xml - Contains information an Eclipse specific extension mechanisms
An Eclipse plug-in defines its API via the MANIFEST.MF file, e.g. the Java packages which can be used by other plug-ins and its dependencies, e.g. the packages or plug-ins which are required by the plug-in.
The plugin.xml file allows to define extension points and extensions. Extension-points define interfaces for other plug-ins to contribute functionality (code and non-code). Extensions contribute functionality to these interfaces. (code and non-code).
In Eclipse 4 the usage of extension points and extensions is very limited. They are mostly used to define pointers to other Eclipse 4 configuration files.
The Eclipse e4 project create regular milestone and release candidate builds. Integration builds of the current source are triggered weekly.
Download the Eclipse M7 Build of Eclipse 4.2 for your operating system using the following link.
http://download.eclipse.org/eclipse/downloads/
The download is a zip file, which is a compressed archive of multiple files. Most operating systems can extract zip files in their file browser. For example if you are using Windows7 as operating system, right mouse click on the file in the explorer and select "Extract all...". If in doubt how to unzip, search via Google for "How to unzip a file on ...", replacing "..." with your operating system.
Do not extract Eclipse to a directory with a path which contains spaces; this might lead to problems in the usage of Eclipse.
After you extracted the zip file, double-click the file "Eclipse.exe" (Windows) or "eclipse" (Linux) (or the launcher icon specific to your platform) to start Eclipse.
Select an empty directory as the workspace. The workspace contains all your project files. To avoid any collision with existing work, we want to use a new one.
The Eclipse SDK download does not include the Eclipse e4 tooling, which makes creating Eclipse 4 applications easier. These tools provide wizards to create Eclipse 4 artifacts and the specialized model editor for the application model.
The correct update side for the Eclipse tooling fitting to the Eclipse 4.2 release from above is the following.
http://download.eclipse.org/e4/downloads/drops/S-0.12M7-201205032200/repository/
From this update side, install only the "E4 CSS Spy" and the "Eclipse e4 Tools".

The milestones builds (M-build) and release candidates (RC-builds) should be relatively stable. Sometimes you want to test a recent fix; for this you can download an integration build. An integration build is typically created once per week while a milestone build is created approx. every 4-6 weeks.
The latest Integration Build of Eclipse 4.2 can also be found on the Eclipse Download Site under the "Stream Integration Builds" label.
If you install the latest integration build, you should use the corresponding update site for the e4 tooling, which is Eclipse e4 tools integration update site .
The Eclipse 4 API has not yet been released. Per default Eclipse will create warnings in your coding if you use provisional API.
You can turn of these warnings for your workspace via → → → → and setting the "Discouraged Access" to ignore.

Alternatively you can turn these warnings of on a per project basis, via right-click on the project → and afterwards the same path as the global settings. You might have to activate the "Enable project specific settings" checkbox.
The Eclipse 4 tooling project provides a project generation wizard which allows you to create a working Eclipse 4 based RCP application.
Select → → → → .
Create a
project called
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.
The visual part of an Eclipse application consists of Perspectives, Parts (Views and Editors), Menus etc. An Eclipse application also includes non-visual components, e.g. Handlers, Commands and Keybindings.
Eclipse 4 uses an abstract description; called the application model; to describe the structure of an application. This application model contains the visual elements as well as some non-visual elements of the Eclipse 4 application.
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
labels, text fields and button it consists of.
The content
of the
Part
is still defined by your source code.
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.

The application model is extensible. The basis of this
model is
typically defined
as a
static file. The default name for this file
is
Application.e4xmi.
You can change the default via the
org.eclipse.core.runtime.products
extension point to specify the model file via the
applicationXMI
parameter.
The XMI file is read at application startup and the initial application model is constructed from this file.
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 like labels, tooltips and icon URI's. 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 objects created based on the application model are called model objects.
URI's follow two patterns. One for identifying resources and another one for identifying classes.
Table 1. URI pattern
| Pattern | Description |
|---|---|
|
bundleclass://Bundle-SymbolicName/package.classname Example: bundleclass://com.example.e4.playground3/com.example.e4.playground3.parts.MySavePart
|
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,
and the fully qualified
classname.
|
|
platform:/plugin/Bundle-SymbolicName/path/filename.extension Example: platform:/plugin/com.exmaple.e4.playground3/icons/save_edit.gif |
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.
|
The Eclipse tooling project provides an 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
→ .

The model editor has also several preference settings which can be reached via → → . The following screenshot shows the preference page.

The application model is also available at runtime. The application can access the model and change it via a defined API.
Add the
org.eclipse.e4.tools.emf.liveeditor
plug-in and its dependencies to your launch configuration to make the
model editor available in 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 itself.
You can change your application model directly at runtime by using the model editor. Most changes are directly applied, e.g. if you change the orientation of a perspective your user interface will update itself automatically.
In the life model editor, you can select the
Part
element, right
click on it and
select
Show Control
to get the
Part
highlighted.
The possible structure of the application model is defined by an Eclipse EMF meta-model.
Eclipse EMF is a popular general purpose
modeling
framework.
Eclipse
EMF
uses
an
.ecore
file to define the
structure.
The meta-model of the Eclipse application model
is
stored in the
org.eclipse.e4.ui.model.workbench
plug-in in
model
folder. The base model definition can be found in
the
UIElements.ecore
file. Based on this meta-model Eclipse EMF is
used to generate the
model classes.
If you want to investigate this model, you could install the EMF tooling via the Eclipse update manager and import the defining plug-in into your workspace. To import a plug-in from your current Target Platform (default is the Eclipse IDE) into your workspace, use the Plug-ins View, right click on a plug-in and select → .
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.
Every model elements allow to define an ID. This ID is used by the Eclipse framework to identify this model element. Make sure you always maintain an ID for every model elements and ensure that these ID's are unique.
Therefore make sure that all your model elements have an ID assigned to them.
The following suggest best practises for naming convensions, which are also used in this description.
Table 2. Naming conventions
| Object | Description |
|---|---|
| Project Names | The plug-in project name is the same as the top-level package name. |
| Packages |
For plug-in containing lots of user interface components
use
sub-packages based on the primary purpose
of the components. For
example
the
com.example
package
may have the
com.example.parts
and
com.example.handler
sub-package.
|
| Class names for model elements |
Use the primary purpose of the model element as a suffix in the
class
name. For example a class which represents a Part which
displays
Todo
objects, might be called
TodoOverviewPart.
|
| ID's |
The ID's of your application model and your plugin.xml file are API, therefore define clear rules for naming ID's in plugin.xml. ID's should always start with the top-level package. If appropriate use the sub-package of the implementing class also. The remainder of the ID should be descriptive for the purpose of the component. For example: "com.example.parts.todolist". ID should be only lower cases (some Eclipse projects also use camelCase for the last part of the ID).
|
In the following tutorial we will create a standard Eclipse Plug-in called "com.example.e4.rcp.todo".
In Eclipse select →

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

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

Press the Finish button; we will not use a template.
An Eclipse feature project contains features . A features has a name, version number, a software license and contains a list of plug-ins and other features which can be understood as a logical unit.
A feature is described via a feature.xmlfile in the Eclipse
feature
project.
Features are used for the Eclipse update manager, the build process and optionally for the definition of Eclipse products. Features can also be used as the basis for a launch configuration.
Eclipse provides several predefined features, e.g.
org.eclipse.rcp
for Eclipse 3.x based RCP applications or
org.eclipse.e4.rcp
for Eclipse 4.x based RCP applications.
You can create a new feature project via the following menu path. → → → → .
If you open the "feature.xml" you can change the feature properties via a special editor.

The tab "Plug-ins" allows you to change the included plug-ins in the feature.

The "feature.xml" file is a simple text file. For example the "feature.xml" file might look like the following in a text editor.
<?xml version="1.0" encoding="UTF-8"?> <feature id="de.vogella.featuretest.feature" label="Feature" version="1.0.0.qualifier"> <description url="http://www.example.com/description"> [Enter Feature Description here.] </description> <copyright url="http://www.example.com/copyright"> [Enter Copyright Description here.] </copyright> <license url="http://www.example.com/license"> [Enter License Description here.] </license> <plugin id="de.vogella.featuretest.testplugin" download-size="0" install-size="0" version="0.0.0" unpack="false"/> </feature>
In this chapter we convert the Eclipse plug-in into an Eclipse 4 application.
We will now create a "todo.product" product configuration file which
uses the
E4Application.
Right click on your project and select →


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, the
defining
plug-in is your plug-in and use the name
product
as ID.
We must use the
E4Application
class.

Create the
com.example.e4.rcp.todo.feature
feature project.
Include the
com.example.e4.rcp.todo
plug-in into that feature.
Change your product configuration file to use features. To do this open your product configuration file and select the Feature option on the Overview tab of the product editor.

Select the
Dependencies
tab
and add the
org.eclipse.e4.rcp
and the
com.example.e4.rcp.todo.feature
features
as dependency via the
button.

Press the
button. This will add the
org.eclipse.emf.common
and
org.eclipse.emf.ecore
features to
the
dependencies.
Select → → → → → to open a wizard. Use the project as container and the file name suggested by the wizard.

This will create the
Application.e4xmi
file and open this file
with the application model editor.
Add one
Window
to your application model to have a visual component.
Select the
Windows
node
and press the
+
Button (the
Add...
button)
for
a
TrimmedWindow.

Enter an ID, the position and size of the window and a label as giving in the screenshot below.

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

Validate that your application starts. It should be an empty application, which can be moved and closed.
We want in later chapters to use functionality from specific other plug-ins which we add here.
Open your
plugin.xml
file and select the
Dependency
tab.
Use the
Add
button to
add the following plug-ins as
dependency.
org.eclipse.swt
javax.inject
org.eclipse.e4.core.di
org.eclipse.e4.ui.workbench
This chapter gives an overview of the purpose of the model elements created by the model editor. It will cover the most important model elements.
Eclipse applications consist out of one or more
Windows.
Typically an application has only one
Window
but you are not not limited to that, e.g. if you want to support
multiple displays for two connected monitors.

Parts
are user interface components which allow to navigate and modify
data.
Parts
are typically divided into
Views
and
Editors.

The distinction into
Views
and
Editors
is primarily not based on technical differences, but on a different
concept of using and arranging these
Parts.
A
View
is
typically
used to work on a set of data, which might be hierarchical
structured. If data
is
changed via the
View,
this change is typically directly applied to the
underlying data
structure. A
View
sometimes allows us to open
an
Editor
for a selected set of the data.
An example for a
View
is the Java Package Explorer, which allow you browse the files of
Eclipse Projects. If you choose to change data in the Package
Explorer, e.g. if you rename a file, the file name is directly
changed
on the filesystem.
Editors
are
typically used to modify a single data element, e.g. a file or a
data object. To apply the
changes done in an
editor to the
data
structure, the user has to explicitly save the editor content.
Editors
were traditionally placed in a certain area, called the "editor
area".
Until Eclipse 4 this was a hard limitation, it was not
possible to move
an
Editor
out of this area; Eclipse 4 allows to place
Editors
at any position in a
Perspective.
For example the Java Editor is used to modify Java source files. Changes to the source file are applied, once the user selects the "Save" command.
A
Perspective
is a visual container for a set of
Parts. The Eclipse IDE uses
Perspectives
to arrange
Parts
for different development tasks.
You can change the layout and content within a
Perspective
by opening or closing
Parts
and by re-arranging them.
As of Eclipse 4.x Perspectives are optional elements for Eclipse
applications.
Parts
can be directly assigned to a
Window
or a
Perspective. If you want to group and arrange
Parts
you can use
PartStacks
and
PartSashContainers.
PartStacks
contain a stack of
Parts
of which only one is visible at the same time and can be selected via
tabs. A
PartSashContainer
displays all its children at the same time
horizontally or vertically.
The following shows a simple Eclipse application layout using two
PartSashContainers
and a few
PartStacks.

On the top of this layout there is a horizontal
PartSashContainer
which contains another
PartSashContainer
and some
Part Stacks. The hierachy is depicted in the following graphic.

In this chapter you extend the user interface of your Eclipse 4 application.
You will add a Perspective to the Window. This Perspective will contain a PartSashContainer. This container will divide its children horizontally.
The PartSashContainer will contain a Stack and another PartSashContainer. This second PartSashContainer will contain two Stacks and divide them vertically.
Each stack will get one Part assigned to it.
After these changes, your user interface should look like the following:

Open the
Application.e4xmi
file. Go to your Window
and
select
the
Controls
node. Add a
PerspectiveStack. Press the
Add
button to create
a
Perspective
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 perspective and add a PartSashContainer. Change its Orientation attribute to Horizontal.

In the drop-down list of the PartSashContainer select PartStack and press the Add button to add a stack.
Re-select the parent PartSashContainer and add another PartSashContainer. Now add two Stacks to the second PartSashContainer.

Add a
Part
to each Stack. For each ID use the prefix
com.example.e4.rcp.ui.parts
and the suffix from the following table.
Table 3. Label and ID from the Parts
| ID Suffix | Label |
|---|---|
| *.todooverview | To-Dos |
| *.tododetails | Details |
| *.playground | Playground |
The following screenshots shows the data of one Part.

The model editor support re You can reassignment of elements via drag-and drop.
Start your product and validate that the user interface looks as planned. Reassign your Parts to other Stacks, if required.
Please note that you have not yet created a Java class for our application.
In the following you will create Java objects and connect them to the application model.
Create the
com.example.e4.rcp.todo.ui.parts
package.
Create three Java classes called TodoOverviewPart TodoDetailsPart and PlaygroundPart in this package. These classes do not extend another class, nor do they implement any interface.
Open the
Application.e4xmi
file and connect the class with the
correct model object. You can do
this via
the
Class URI
property
of
the
Part
model element.

The following table gives and overview, which elements should be connected.
Table 4. Connection Java class with Model Element
| Class | Part ID suffix |
|---|---|
| TodoOverviewPart | *.todooverview |
| TodoDetailsPart | *.tododetail |
| PlaygroundPart | *.playground |
The Eclipse 4 model editor allow to seach for existing class via the "Find..." button. The initial list is empty, start typing the class name to see results.
Run your application. It should start, but you should see no difference in your user interface.
To validate that the model objects are created by the Eclipse
runtime, 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.
The general concept behind 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 on another class if it uses this class as a variable. For example a class which accesses a logger service has a dependency on 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)
a setter (setter injection)
a field (field injection)
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 330
(JSR330). 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 5. 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. The specific behavior depends where @Optional is used:
|
| @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 allows to use dependency injection for Java objects, OSGi services and Preferences.
The Eclipse 4 runtime creates objects for the Java classes referred by the application model. During this instantiation the Eclipse runtime scans the class definition for annotations.
Based on these annotations the Eclipse framework performs the injection. First the constructor injection is performed and afterwards the field and constructor injections.
Constructors are called, before the fields are injected. Accessing an injected field in the constructor will result in an error.
The Eclipse framework also tracks the injected values and if they change, it can 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.
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 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.
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 6. Eclipse lifecycle annotations for Parts
| 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. |
| @Focus | Indicates that this method should be called, once the Part gets the focus. |
| @Persist | Eclipse calls this method if a save request is triggered. Can for example be used to save the data of a part. |
| @PersistState | Eclipse calls this method if before the model object is disposed, so that the object can save its state. |
Table 7. Other Eclipse behavior annotations
| Annotation | Description |
|---|---|
| @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 |
| @GroupUpdates |
Indicates that updates for this @Inject should be batched.
If you
change such objects in the
IEclipseContext
the update will be
triggered by the
processWaiting()
method on
IEclipseContext.
|
| @EventTopic and @UIEventTopic | Allows to subscribe to events send by the Event Admin service. |
All these annotations will also trigger dependency injections.
Therefore you do not need to add the
@Inject
annotation, if you use these annotations.
The
@PostConstruct,
@PreDestroy
annotations are included in the
javax.inject
package.
The
org.eclipse.e4.core.di.annotations
package contains the
@Execute,
@CanExecute
annotations.
@Persists,
@PersistState
and
@Focus
are part of the
org.eclipse.e4.ui.di
package.
Typically some functionality should be triggered if an application is stared or stopped. Eclipse 4 provides the possibility to register a class to predefined events of this lifecycle. For example you can use these lifecycle hooks to create a login screen before the actual application is started.
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 8. Life Cycle Annotations
| Annotation | Description |
|---|---|
| @PostContextCreate | Is called after the Application’s IEclipseContext is created, can be used to add objects, services, etc. 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. |
For example lets assume you have registered a lifecycle class in your
plugin.xml
file.
<?xml version="1.0" encoding="UTF-8"?> <plugin> <extension id="product" point="org.eclipse.core.runtime.products"> <product name="testing" application="org.eclipse.e4.ui.workbench.swt.E4Application"> <property name="appName" value="testing"> </property> <property name="applicationXMI" value="testing/Application.e4xmi"> </property> <property name="applicationCSS" value="platform:/plugin/testing/css/default.css"> </property> <property name="lifeCycleURI" value="bundleclass://testing/testing.LifeCycleManager"> </property> </product> </extension> </plugin>
The following coding will display a shell.
package testing; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.ui.workbench.UIEvents; import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Shell; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; public class LifeCycleManager { @PostContextCreate void postContextCreate(final IEventBroker eventBroker) { final Shell shell = new Shell(SWT.TOOL | SWT.NO_TRIM); // Will close the shell once a part gets focus // Should be easier see bug // https://bugs.eclipse.org/bugs/show_bug.cgi?id=376821 eventBroker.subscribe(UIEvents.UILifeCycle.ACTIVATE, new EventHandler() { @Override public void handleEvent(Event event) { shell.close(); shell.dispose(); System.out.println("Closed"); eventBroker.unsubscribe(this); } }); shell.open(); } }
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.ui.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("Layout: " + parent.getLayout().getClass()); } else { System.out.println("No Composite available."); } } }
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.
The Eclipse application model can contain commands and handlers.
A command in Eclipse is a declarative description of an abstract action which can be performed, for example save, edit or copy. A command is independent from its 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.
In the handler class you can determine the command ID if the command was triggered via the user interface. Determining the ID is not possible, if it was triggered via the command service (limitation). The following code snippet shows how to get the command ID.
@Execute public void execute(MHandledItem item) { MCommand command = item.getCommand(); // Prints out the commmand ID System.out.println(command.getElementId()); }
If you know Eclipse 3.x you are probably searching for the predefined commands which you can re-use. The Eclipse 4 platform tries to be as lean as possible.
Eclipse 4 does not include standard commands anymore. You have to define all your commands.
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. Using a Handler gives you more flexibility, for example you can have different Handlers for different scopes (Applications or Views) and you can define Keybindings for your Handlers.
Toolbars in the application are represented in the application model via the trimbar model element. A trimbar can be defined for Windows. Via its attribute you define if the trimbar should be placed on the top, left, right or bottom corner of the Window.
The related command is assigned to the menu and toolbar entry. Menus and toolbars support separators. Menus can have submenus.
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>
To add such a View menu entry, select the entry Menu under our Part, select ViewMenu and press the Add button. Eclipse 4.2M7 or earlier releases required that you add this tag manually in the source code.

You can also define a popup menu for SWT controls. For this you
define a "Popup Menu" for your
Part
in the application model.
You can then assign it via the
EMenuService
class to a SWT control. The following coding shows an example.
package testing.parts; import javax.annotation.PostConstruct; import org.eclipse.e4.ui.workbench.swt.modeling.EMenuService; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; public class Detail { @PostConstruct public void createUi(Composite parent, EMenuService service) { final Text text = new Text(parent, SWT.BORDER); text.setText("Hello"); service.registerContextMenu(text, "popuptest"); } }
Each command can have only one valid handler for a given scope. The application model allows to define a handler for the application, specific for a Window and for a Part.
If more than 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 handler defined for the application will be called.
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.
A good convention is to start IDs with the top level package name of your project and to use only lower cases.
The ID's of commands and handler should reflect their
relationship.
For example if you implement a
command with the
com.example.contacts.commands.show
ID, you should use
com.example.contacts.handler.show
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.handler.show.details".
In 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 9. 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 |
You will now define commands and handlers for your application.
Open
the
Application.e4xmi
file and select
Commands. We will
define our
handlers for the whole application. Alternatively
you
could also
define them specific for
Parts.

Via you can create new commands. The name and the ID are the important fields. Create the following commands.
Table 10. 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.test | For testing |
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() { System.out.println("Called"); } @CanExecute public boolean canExecute() { return true; } }
Using this templates for all classes, implement the following classes.
SaveHandler
ExitHandler
NewTodoHandler
RemoveTodoHandler
TestHandler
Select the entry "Handlers" in your application model and create the handlers from the following table for your commands. For the definition of handlers the ID, the command and the class is relevant information.
Table 11. Handlers
| Handler ID | Command - Class |
|---|---|
| org.eclipse.ui.file.save.handler | Save - SaveHandler |
| org.eclipse.ui.file.exit.handler | Exit - ExitHandler |
| com.example.e4.rcp.todo.new.handler | New Todo - NewTodoHandler |
| com.example.e4.rcp.todo.remove.handler | Remove Todo - RemoveTodoHandler |
| com.example.e4.rcp.todo.test.handler | For testing - TestHandler |
The application model editor shows both the name and the ID of
the
command. The class URI follows the
bundleclass://
schema, the table only define the class name to make the table more
readable.

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.

Give the "org.eclipse.ui.main.menu" ID to your main menu.
Add two menus, one with the name "File" and the other one with the name "Edit". You only need to enter the "Label" attribute.
Also set the "org.eclipse.ui.file.menu" ID for the file menu.

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

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.
Select the node "TrimBars" under your Window 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".

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(); } }
It is also possible to define Keybindings (shortcuts) for your Eclipse application. This requires two steps, first you need to enter values for the "Binding Context" node of your application model.
Afterwards you need to enter the keybindings for the relevant Binding Context in the Binding Table node of your application model.
The
BindingContext
is defined via its ID. You can use any ID you like.
BindingContext
ID's can be assigned to a Window in the application model.
This would
define which
BindingContexts
are valid for this Window. If nothing is defined in the
Window then
all shortcuts are valid.
Eclipse JFace uses predefined BindingContext identifier which
are
based on the
org.eclipse.jface.contexts.IContextIds
class. JFace
distingish between shortscuts for dialogs, windows or
both.
The following gives an overview of the supported ID and the validity of keybindings defined with reference to this Context ID.
Table 12. Default BindingContext values
| Context ID | Description |
|---|---|
| org.eclipse.ui.contexts.dialogAndWindow | Keybindings valid for Dialogs and Windows. |
| org.eclipse.ui.contexts.dialog | Keybindings valid in Dialogs. |
| org.eclipse.ui.contexts.window | Keybindings valid for Windows. |
The BindingTable node in the application model allows to define shortcuts for a specific BindingContext.
To define a shortcut you create a new node for BindingTable and define a reference for the Context ID.
In your keybinding you define the key "Sequence" and the command associate with this shortcut.

The control keys are different for the different platforms, e.g. on the Mac vs. a Linux system. For example you can use Ctrl but this would be hardcoded. Better use the metakeys M1 - M4.
Table 13. Key Mapping
| Control Key | Mapping for Windows and Linux | Mapping for Mac |
|---|---|---|
| M1 | Ctrl | Command |
| M2 | Shift | Shift |
| M3 | Alt | Alt |
| M4 | Undefined | Ctrl |
These values are defined in the
SWTKeyLookup
class
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 application 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
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 an 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.
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.
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.
Another example is the
WBWRenderer
which is responsible for creating a Window. This class puts an
instance of
IWindowCloseHandler
and
ISaveHandler
into the context of the Window. The first is responsible for the
behavior of a Window during close, the other one for saving. For
example the default
IWindowCloseHandler
would prompt you if you want to save
Parts
as dirty. You can change this default
IWindowCloseHandler
via the MWindow model object. The following example show this.
@Execute public void execute(final Shell shell, EModelService service, MWindow window) { IWindowCloseHandler handler = new IWindowCloseHandler() { @Override public boolean close(MWindow window) { MessageDialog.openConfirm(shell, "Really close?", "You will loose data"); return true; } }; window.getContext().set(IWindowCloseHandler.class, handler); }
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. 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 14. 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.
|
| Snippets |
Snippets can be used to pre-configure model parts which you want
to create via your program. You can use
EcoreUtil.copy
to copy a Snippets and assign it then to another model element,
e.g. on a
MSash
you can a newly copied
MStack
called "copy",
via
getChildren().add(copy).
|
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 as show in 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);
For example the following adds 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); } }
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); } }
The
IApplicationContext
gives access to the command line arguments which were used to start
the Eclipse application, e.g. via the run configuration in the
"Arguments" tab or via the .ini file of your exported product.
import java.util.Map; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.equinox.app.IApplicationContext; public class GetArgumentsHandler { @Execute public void execute(IApplicationContext context) { // OSGi consumes framework arguments String[] args = (String[]) context.getArguments().get( IApplicationContext.APPLICATION_ARGS); for (Object value : args) { System.out.println(value); } } }
Eclipse 4 tries to keep the core framework as minimal as
possible.
Addons
model object can be registered globally on the application model and
can
enhance
the
application with
additional functionality.
Currently the following Add-ons are useful for Eclipse applications. Their class names give an indication of their provided functionality. Check their Javadoc to get a short description of their purpose.
Table 15. 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 |
Addons
are created before
the rendering engine
renders the model. This allows
Addons
to alter the user interface that is produced by the rendering
engine.
For example, the
min/max
Addon
changes the tab folders created for
MPartStacks
to have min/max buttons in the corner.
Addons
use the
bundleclass://
URI convention to extend your application model with add-ons.
Having these Add-ons registered allows them to be enhanced or replaced 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
you need to add the
org.eclipse.e4.ui.workbench.addons.swt
plug-in to your product configuration file. Then you can use the
DnDAddon
and the
CleanupAddon
from this bundle as
Add-ons in your application model.
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.ui.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); }
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.
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); }
It is not recommended to add new objects to an existing Eclipse Context as you may override existing objects which the intention of doing so.
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.
The IEclipseContext should also not be used to transfer data within your application. For example you should not put your model objects directly into the context to be able to access the data from other parts of your application.
For this you would either define an own OSGi services or use the EventAdmin Service to communicate within your application.
Using dependency injection for your own Java objects has two
flavors.
First you want the Eclipse dependency container to create
your own
objects and get them injected into your model objects.
Second
you want
to create objects which declare there dependencies with
@Inject
and want to create it via dependency injection.
Both approaches are described here.
If you want the Eclipse dependency injector to create your objects
for you, annotate them with
@Creatable. This way you telling the Eclipse DI container that it should create
a new instance of this object if it does not find an instance in the
context.
The Eclipse DI container will try to find a suitable constructor for this class. You can also use @Inject on the constructor to indicate that Eclipse should try to run dependency injection also for this constructor.
For example, assume that you have the following domain model.
@Creatable class Todo { @Inject public Todo(Dependent depend, YourOSGiService service) { // placeholder } } @Creatable class Dependent { public Dependent() { // placeholder } }
Assuming that you have defined the required OSGi service, you can get an instance of your Todo data model injected in a Part.
// Field Injection
@Inject Todo todo
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);
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.
Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.com Google Group. I have created a short list how to create good questions which might also help you.
http://wiki.eclipse.org/E4 Eclipse E4 - Wiki