Back to top

vogella training Training Books

Eclipse 4 Modularity - Tutorial

Building modular Eclipse RCP applications based on Eclipse 4

Lars Vogel

Version 5.8

20.05.2012

Revision History
Revision 0.1 14.02.2009 Lars
Vogel
created
Revision 0.2 - 5.8 16.02.2009 - 20.05.2012 Lars
Vogel
bug fixes and enhancements

Eclipse Application Model contributions

This tutorial explains how to contribute to the Eclipse application model via other plug-ins.


Table of Contents

1. Prerequisites
2. Eclipse 4 Modularity
2.1. OSGi modularity
2.2. Application model and model contributions
3. Contributing model fragments and processors
3.1. Contributing to the application model
3.2. Model fragments
3.3. Model processors
3.4. Position of new model elements
3.5. Usage of IDs
3.6. Comparison with Eclipse 3.x
4. Constructing the runtime application model
4.1. Components
4.2. User Changes
4.3. Merging model elements at startup
5. Fragment extension elements
6. Tutorial: Contributing via fragments
6.1. Create Project and Java classes
6.2. Create model fragment
6.3. Register Fragment via extension
6.4. Update Feature and test
6.5. Extend example: Contributing a Part
7. Tutorial: Contributing via processors
7.1. Enter dependencies and create Java classes
7.2. Register processor via extension
8. Thank you
9. Questions and Discussion
10. Links and Literature
10.1. Source Code
10.2. Links and Literature

1. Prerequisites

The following assumes that you have already basic Eclipse RCP development experience. See the Eclipse RCP Tutorial for details. .

2. Eclipse 4 Modularity

2.1. OSGi modularity

Eclipse 4 is based on OSGi and therefore supports its modularity. Plug-ins define their external API, and consume API from other plug-ins.

The modularity provided by OSGi is completely available in Eclipse 4. Consuming OSGi services is very well supported in Eclipse 4, as OSGi services can get injected into other components via dependency injection.

2.2. Application model and model contributions

In Eclipse 4 the application is described via an application model with the Application.e4xmi default filename.

Other plug-ins can extend this base application model with contributions.

These model contributions are registered in Eclipse 4 via the org.eclipse.e4.workbench.model extension point. This extension point is defined in the org.eclipse.e4.ui.workbench plug-in.

3. Contributing model fragments and processors

3.1. Contributing to the application model

The org.eclipse.e4.workbench.model extension point allows you to define contributions to the application model.

Model contributions can be done via files (fragments) or via code (processors).

The model contributions are read during startup and the contained information is used to build the runtime application model.

3.2. Model fragments

A model fragment is a file which typically ends with the .e4xmi extension. It specifies additional model elements.

It defines which model element it extends and the new model elements which should be added to this model element. For example a fragment can define that it extends a certain menu with additional menu entries.

3.3. Model processors

A processor allows you to contribute to the model via program code. A processor allows the dynamic creation of model elements, therefore this approach has the highest flexibility.

3.4. Position of new model elements

Fragments contribute new model elements to existing containers, e.g. new menu entries to existing menus.

Fragments allow to define the position of these new model elements via the Position in List attribute. The following values are allowed:

Table 1. Position in List attribute

Value Description
first Positions the element on the beginning of the list.

index: theindex

Example

index:0

Places the new model elements at position theindex.
before: theotherelementsid Places the new model elements before the model element with the ID theotherelementsid.
after: theotherelementsid Places the new model elements after the model element with the ID theotherelementsid.

Fragments of independent plug-ins are processed in arbitrary order by the Eclipse runtime, therefore first or index might not always result in the desired outcome.

3.5. Usage of IDs

If you want to contribute to an element of the application model you must specify the ID of the element to which you are contributing.

In general it is good practice to always define IDs in your application model.

3.6. Comparison with Eclipse 3.x

The programming model of Eclipse 3.x primarily uses extension points to define contributions to the application. These extensions define new parts, new menus, etc.

This approach is no longer used in Eclipse 4 applications. All contributions are made via fragments or processors.

4. Constructing the runtime application model

4.1. Components

The application model of a running application consists of different components: the base application model and model contributions via other plug-ins. In addition to that user changes are also recorded and applied to the runtime model.

4.2. User Changes

Changes during runtime, e.g. the user moves a part, are written back to the model. While the application is running, the model objects can be changed. For example, parts are closed or opened.

Theses changes are recorded and saved independently in a workbench.xmi file in the .metadata/.plugins/org.eclipse.e4.workbench folder.

If user changes should be deleted, you can specify the clearPersistedState parameter as a launch parameter.

4.3. Merging model elements at startup

The different components of the runtime application model need to be combined.

Eclipse 4 creates the application model at first based on the base application model and applies the model contributions to it. User deltas are applied afterwards. If these deltas do not apply anymore, e.g. because the base model has changed, they will be skipped.

The deltas are applied to the model based on the IDs of the user interface component.

5. Fragment extension elements

In fragments you contribute to an existing model element which is defined via its ID. You also have to specify the Featurename to which you want to contribute. A Featurename is a direct link to the structure of the application model.

The following table lists some Featurename values and their purposes.

Table 2. Contribution, Featurename and Element id

You want to contribute to Featurename Element id
Command to the application commands ID of your application
Handler to the application handlers ID of your application
New MenuItem / HandledMenuItem to existing menu children ID of the menu
New menu to the main menu of the window children ID of your main menu
New Part to existing PartStack children ID of your PartStack

6. Tutorial: Contributing via fragments

6.1. Create Project and Java classes

In this section you will add a menu entry, a command and a handler to your main application model via fragments.

Create a plug-in project called com.example.e4.rcp.todo.contribute without a template and without an Activator. The following description abbreviate the plug-in name to *.contribute.

Add a dependency in your MANIFEST.MF file to the following plug-ins:

  • org.eclipse.swt

  • org.eclipse.jface

  • org.eclipse.e4.core.di

  • org.eclipse.e4.ui.workbench

  • org.eclipse.e4.ui.di

Imported packages has to list javax.inject with 1.0.0 as a minimum version.

Create the com.example.e4.todo.contribute.handler package and the following class.

package com.example.e4.rcp.contribute.handler;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;

public class OpenMapHandler {

  @Execute
  public void execute(Shell shell) {
    MessageDialog.openInformation(shell, "Test", "Just testing");
  }
} 

6.2. Create model fragment

Use the Eclipse 4 wizard to create a new fragment via the following menu: FileNewOther...Eclipse 4ModelNew Model Fragment. Select the com.example.e4.rcp.todo.contribute plug-in as the container and use fragment.e4xmi as the name for the file.

Select the Model Fragment node and press the Add button.

Use com.example.e4.rcp.todo.application as the Element id. This is the ID of the Application model element in your Application.e4xmi file.

You also need to define to which feature you will be adding to. Use commands as Featurename. Make sure you still have the Model Fragment selected and use the Add button to add a Command to your model fragment.

Adding a model fragment

Use com.example.e4.rcp.todo.contribute.command.openmap as ID and Open Map as name for the corresponding attributes of the command.

Adding a command to the model fragment

Create a new model fragment for the handler. The Element id is again the ID of your application ID, the Featurename is handlers. Add a Handler to this model fragment.

Adding a handler to the model fragment

Use com.example.e4.rcp.todo.contribute.handler.openmap as ID for the handler. Point to the OpenMapHandler class and your Open Map command.

Adding a handler to the model fragment

Add another Model Fragment to contribute a new menu to your application model. You will contribute to the main menu with the org.eclipse.ui.main.menu ID. The Featurename is children.

Adding a fragment for the menu

Add a Menu with the Map label and the com.example.e4.rcp.todo.contribute.menu.map ID.

Adding a menu entry

Add a HandledMenuItem which points to your command. The process of defining these entries is the same as defining menus in the Application.e4xmi and is therefore not described here in detail.

Adding a menu item to the menu

6.3. Register Fragment via extension

In your *.contribute plug-in add the org.eclipse.e4.workbench.model extension.

Adding the xtension for the fragment

Right-click on the extension and select Newfragment.

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
   <extension
        id="modelContribution"
         point="org.eclipse.e4.workbench.model">
      <fragment
            uri="fragment.e4xmi">
      </fragment>
   </extension>

</plugin> 

6.4. Update Feature and test

Add the *.contribute plug-in to your com.example.e4.rcp.todo.feature feature.

Run the Todo product. You should see the new Map entry in the application menu. If you select this entry a message dialog opens.

If the menu entry is not displayed, ensure that your IDs are correctly entered and that you either use the clearPersistedState flag or clear the workspace data in your Launch configuration.

Please note that your model entries should all have IDs.

6.5. Extend example: Contributing a Part

Define a new model fragment which contributes a part to an existing PartStack.

7. Tutorial: Contributing via processors

7.1. Enter dependencies and create Java classes

In the following example you will replace an existing menu entry in the Eclipse 4 application.

Continue to use com.example.e4.rcp.todo.contribute plug-in for this tutorial.

Add the following additional plug-ins to your dependencies to your MANIFEST.MF file.

  • org.eclipse.e4.ui.services

  • org.eclipse.e4.core.contexts

Create the following dialog and handler classes. The handler will be used later on in the new menu entry.

package com.example.e4.rcp.todo.contribute.dialogs;

import javax.inject.Inject;
import javax.inject.Named;

import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class ExitDialog extends Dialog {
  @Inject
  public ExitDialog(@Named(IServiceConstants.
      ACTIVE_SHELL) Shell shell) {
    super(shell);
  }

  @Override
  protected Control createDialogArea(Composite parent) {
    Label label = new Label(parent, SWT.NONE);
    label.setText("Closing this application may result in data loss. "
        + "Are you sure you want that");
    return parent;
  }

} 

package com.example.e4.rcp.todo.contribute.handler;

import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.jface.window.Window;

import de.vogella.e4.todo.contribute.dialogs.ExitDialog;

public class ExitHandlerWithCheck {
  @Execute
  public void execute(IEclipseContext context, IWorkbench workbench) {
    ExitDialog dialog = ContextInjectionFactory.
        make(ExitDialog.class, context);
    dialog.create();
    if (dialog.open() == Window.OK) {
      workbench.close();
    }
  }
} 

Create now the model processor class.

package com.example.e4.rcp.todo.contribute.processors;

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

import javax.inject.Inject;
import javax.inject.Named;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory;

public class MenuProcessor {
  
  // I get this via the parameter 
  // of the process definition
  @Inject
  @Named("org.eclipse.ui.file.menu")
  private MMenu menu;

  @Execute
  public void execute() {
//    System.out.println("Starting processor");
    // Remove the old exit menu entry
    if (menu != null && menu.getChildren() != null) {
      List<MMenuElement> list = new ArrayList<MMenuElement>();
      for (MMenuElement element : menu.getChildren()) {
        System.out.println(element);
        
        // Separaters have no label hence we
        // need to check for null
        if (element.getLabel() != null) {
          if (element.getLabel().contains("Exit")) {
            list.add(element);
          }
        }
      }
      menu.getChildren().removeAll(list);
    }

    // Now add a new menu entry
    MDirectMenuItem menuItem = MMenuFactory.INSTANCE.
        createDirectMenuItem();
    menuItem.setLabel("Another Exit");
    menuItem.setContributionURI("bundleclass://"
        + "com.example.e4.rcp.todo.contribute/"
        + "com.example.e4.rcp.todo.contribute" +
        ".handler.ExitHandlerWithCheck");
    menu.getChildren().add(menuItem);
  }
} 

7.2. Register processor via extension

In your *.contribute plug-in add a processor via an org.eclipse.e4.workbench.model extension.

The following assumes that you used org.eclipse.ui.file.menu as ID for your File menu in the main application model

Right-click on the processor and select Newelement. The parameter with the ID is the model element which is later on injected into your Java class for the processor. Use org.eclipse.ui.file.menu as id* parameter.

Add this plug-in to your product and run your product. The old exit menu entry should be removed and you should see the new menu entry.

8. Thank you

Please help me to support this article:

Flattr this

9. 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.com Google Group. I have created a short list how to create good questions which might also help you.

10. Links and Literature

10.1. Source Code

Source Code of Examples