Overview of the available services of the Eclipse platform

1. Eclipse platform services

1.1. What are Eclipse platform services?

Services are software components (based on an interface or a class) which provide functionality. The Eclipse platform defines several services. The classes which are created based on the application model can access these services via dependency injection.

To use an Eclipse service you specify the service dependency via an @Inject annotation and the Eclipse framework injects this component into your object.

The typical naming convention for Eclipse services interfaces is to start with an E and end with Service e.g. E*Service.

1.2. Overview of the available platform services

The following table gives an overview of the most important available platform services.

Table 1. Platform services

Service Description
EModelService Used to search for elements in the model, create new model elements, clone existing snippets and insert new elements into the runtime application model.
ESelectionService Used to retrieve and set the current active selection in the user interface.
ECommandService Gives access to existing commands and allows you to create and change commands.
EHandlerService Allows you to access, change and trigger handlers.
EPartService Provides API to access and modify parts. It allows you to switch perspectives. Can be used to trigger that parts save state, i.e. if the part behaves like an editor.
IEventBroker Provides functionality to send event data and to register for specified events and event topics.
StatusReporter Allows you to report Status objects.
EContextService Activate and deactivate key bindings defined as BindingContext in the application model. The content referred to in this service is the BindingContext and not the IEclipseContext.
IThemeEngine Allows to switch the styling of the application at runtime.

 

Other available services are:

  • org.eclipse.e4.core.services.Adapter – An adapter can adapt an object to the specified type, allowing clients to request domain-specific behavior for an object. It integrates IAdaptable and IAdapterManager. See the Adapter wiki for details.
  • org.eclipse.e4.core.services.Logger – Provides logging functionality

 

There are additional services available which depend on SWT.

  • EMenuService – Registers a popup menu (MPopupMenu) for an SWT control.
  • org.eclipse.jface.window.IShellProvider – allows access to a Shell

 

2. How are Eclipse platform services implemented?

Usually services have two parts: the interface definition and the implementation. How these two are linked is defined by a context function , an OSGi service or plain context value setting (IEclipseContext). Please note that there can be more than one service implementation for an interface.

3. Selection service

3.1. Usage of the selection service

The ESelectionService service allows you to retrieve and set the global selection in your current application window. Other classes in the application model can use the dependency injection mechanism to retrieve the relevant active selection directly.

A client can get the selection service via: @Inject ESelectionService.

3.2. Changing the current selection

You can change the current selection with the setSelection() method of the ESelectionService class. This is demonstrated in the following code.

 

// use field injection for the service
@Inject ESelectionService selectionService;

// viewer is a JFace Viewer
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
  @Override
  public void selectionChanged(SelectionChangedEvent event) {
    IStructuredSelection selection = (IStructuredSelection) 
        viewer.getSelection();
    selectionService.setSelection(selection.getFirstElement());
  }
});

 

3.3. Getting the selection

A client can retrieve the last selection for the current window directly from the ESelectionService via the getSelection() method. The getSelection(partId) method allows you to retrieve the selection of a specific part.

It is preferred that a class which is part of the application model uses dependency injection to retrieve the selection. The selection is stored under the key based on the IServiceConstants.ACTIVE_SELECTION constant. This key can be specified via the @Named annotation. The Eclipse framework ensures that selections are only injected if they have the fitting type.

The usage of the @Named annotation to retrieve the selection is demonstrated with the following method.

 

@Inject
public void setTodo(@Optional 
    @Named(IServiceConstants.ACTIVE_SELECTION) Todo todo) {
  if (todo != null) {
    // do something with the value
  }
}

 

4. Model Service

4.1. What is the model service?

The model service gives you access to the application model at runtime and allows you to modify it. For example, you can add and remove model elements. It also contains functionality to clone application model snippets which can be added to the application.

4.2. How to access the model service

This service can be accessed via dependency injection. For example, via field injection with the following statement: @Inject EModelService modelService;

4.3. Cloning elements or snippets

In the application model you can create Snippet model elements which can be used to create model object at runtime. Snippets can be used to create new objects via the model service. It is also possible to copy existing application model elements via the model service.

You can use the cloneElement() and cloneSnippet() methods of the model service to copy an existing element or snippet. The resulting object can be assigned to another model element.

4.4. Searching model elements

The findElements() method allows you to search for specific model elements. The following code shows an example for using the findElements() method.

 

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

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

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.EModelService;

public class ModelServiceExampleHandler {

  @Execute
  public void execute(MApplication application, EModelService service) {

    // find objects by ID
    findPartsById(application, service);

    // find objects by type
    findParts(application, service);

    // find objects by tags
    findObjectsByTag(application, service);

  }

  // example for search by ID
  private void findPartsById(MApplication application, EModelService service) {
    List<MPart> findElements = service.findElements(application, "mypart",
        MPart.class, null);
    System.out.println("Found part(s) : " + findElements.size());

  }

  // example for search by type
  private void findParts(MApplication application,
      EModelService service) {
    List<MPart> parts = service.findElements(application, null,
        MPart.class, null);
    System.out.println("Found parts(s) : " + parts.size());

  }

  // example for search by tag
  private void findObjectsByTag(MApplication application,
      EModelService service) {
    List<String> tags = new ArrayList<String>();
    tags.add("justatag");
    List<MUIElement> elementsWithTags = service.findElements(application,
        null, null, tags);
    System.out.println("Found parts(s) : " + elementsWithTags.size());
  }
}

 

Here is an example of how to find the perspective for a part.

 

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

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.workbench.modeling.EModelService;

public class FindPerspectiveHandler {
  @Execute
  public void execute(MApplication application, EModelService service) {
    // seach for a part with the following ID
    String ID = "com.example.e4.rcp.parts.tododetail";
    MUIElement element = service.find(ID, application);
    MPerspective perspective = service.getPerspectiveFor(element);
    System.out.println(perspective);
    // TODO do something useful with the perspective
  }
}

 

5. Application model modifications at runtime

5.1. Creating model elements

As the application 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.

To add your new model elements to the application you can use the model service or get existing elements injected.

 

The Eclipse framework automatically keeps track of the application model and changes in the model are reflected immediately in your application. For example, if you add a new window to your application, it becomes visible instantly.

 

5.2. Modifying existing model elements

You can also get the model elements injected and change their attributes.

The Eclipse framework keeps track of the attributes in your application model and updates your application accordingly. For example, if you inject an MPart and call its setLabel() method, the text of the part in a PartStack changes immediately.

6. Example for changing the application model

6.1. Example: Search perspective and change attributes

The following code shows how to access a PartSashContainer with the mypartsashcontainer ID. It also demonstrates how to modify model attributes.

In this example it changes the container data parameter for its children. This will arrange (layout) the parts in the container.

 

@Execute
public void execute(EModelService service, MWindow window) {
  MPartSashContainer find = (MPartSashContainer) service.
    find("mypartsashcontainer", window);
  List<MPartSashContainerElement> list = find.getChildren();

  int i = 0;
  // make the first part in the container larger
  for (MPartSashContainerElement element : list) {

    if (i > 0) {
      element.setContainerData("20");
    } else {
      element.setContainerData("80");
    }
    i++;
  }
}

 

6.2. Example: Dynamically create a new window

To create new model objects you can use the createModelElement() of the model service. After you created such an object you can add it to your application model at runtime.

For example, the creation of a new window for a running application is demonstrated by the following code snippet.

 

// create a new window and set its size
MWindow window = modelService.createModelElement(MWindow.class);
window.setWidth(200);
window.setHeight(300);

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

 

6.3. Example: Dynamically create a new part

The following code demonstrates how to create and add a new part to the currently active window.

 

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

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;

public class DynamicPartHandlerCode {
  // used as reference
  @Execute
  public void execute(MApplication application, EPartService partService,
      EModelService modelService) {

    // create new part
    MPart mPart = modelService.createModelElement(MPart.class);
    mPart.setLabel("Testing");
    mPart.setElementId("newid");
    mPart.setContributionURI("bundleclass://com.example.e4.rcp.todo/"
        + "com.example.e4.rcp.todo.parts.DynamicPart");
    partService.showPart(mPart, PartState.ACTIVATE);
  }
}

 

7. Part service and editor like behavior

7.1. What is the part service?

The part service allows you to find and perform actions on parts in the application model.

It also allows you to switch perspectives and to create and activate new parts based on PartDescriptors in the application model.

7.2. PartDescriptors

PartDescriptors are templates (blueprints) for parts which can be used to create parts. By defining a common set of attributes via such a blueprint it is possible to create concrete instances of it via the part service.

Via the Multiple property of the PartDescriptors you configure if multiple instances of this part can be created or not. Such a model element is depicted in the following screenshot.

Eclipse4Services-3

7.3. How to access the part service

Use dependency injection to get access to the part service. For example via the @Inject EPartService partService; statement.

7.4. Example: Showing and hiding parts

The following example shows how you can find parts, hide or show them. If the Visible attribute of the part was initially set to false (not visible), you need to call the setVisible(true) method of the model element to ensure that the part gets displayed.

 

@Inject private EPartService partService;

// search part with ID "com.example.todo.rcp.parts.tododetails"
// assume that a part with this ID exists
detailsTodoPart = partService.findPart("com.example.todo.rcp.parts.tododetails");

// hide the part
partService.hidePart(detailsTodoPart);

// required if initial not visible
detailsTodoPart.setVisible(true);

// show the part
partService.showPart(detailsTodoPart, PartState.VISIBLE);

 

7.5. Example: Switching perspectives

The following example shows how you can switch to another perspective with the part service.

 

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

import java.util.List;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;

public class SwitchPerspectiveHandler {
  @Execute
  public void execute(MApplication app, EPartService partService, 
      EModelService modelService) {
    MPerspective element = 
        (MPerspective) modelService.find("secondperspective", app);
    // now switch perspective
    partService.switchPerspective(element);
  }
}

 

7.6. Example: PartDescriptor and creating parts dynamically

If you define a PartDescriptor in your application model, you can use the EPartService to create a part from this template.

The following screenshot shows the definition of a PartDescriptor in the application model. As the Multiple parameter is set, it is possible to create several parts based on this template.

 

Eclipse4Services-4

The part service allows you to create a new part based on this template. This is demonstrated by the following example code.

 

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

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;

public class OpenPartHandler {

  @Execute
  public void execute(EPartService partService) {

    // create a new Part based on a PartDescriptor
    // in the application model 
    // assume the ID is used for the PartDescriptor
    MPart part = partService
        .createPart("com.example.e4.rcp.todo.partdescriptor.fileeditor");
    part.setLabel("New Dynamic Part");

    // If multiple parts of this type are now allowed 
    // in the application model, 
    // then the provided part will be shown 
    // and returned
    partService.showPart(part, PartState.ACTIVATE);
  }
}

 

8. Implementing editor like behavior

8.1. Parts which behave similar to editors

An editor is a part which requires that the user triggers a save operation to persist data changes in the editor. Editors that contain data, which can be saved, are typically called dirty.

The part service allows you to save dirty parts. Every part can mark itself as dirty, hence behave like an editor.

8.2. MDirtyable and @Persist

A part has the MDirtyable attribute which indicates that it can be marked as dirty. Dirty indicates that the part contains data which has been changed but not yet saved. The MDirtyable object can get injected into a part.

You can use the setDirty(boolean) method to mark the part as dirty.

The following snippet demonstrates how to use the MDirtyable model property in a part to flag it as dirty after a button was pressed.

 

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);
      }
    });
  }

}

 

The part service allows you to query the dirty parts and to call a method annotated with @Persist on the dirty parts. This method saves the data of the part and sets the dirty flag back to false if the save operation was successful.

 

@Persist
public void save(MDirtyable dirty, ITodoService todoService) {
  // save changes via ITodoService for example
  todoService.saveTodo(todo);
  // save was successful
  dirty.setDirty(false);
}

 

8.3. Use part service to trigger save in editors

The part service allows you to trigger the @Persist method on the dirty parts via the saveAll() method.

The EPartService searches in each part which is marked as dirty for a method annotated with @Persist. This method is called by the framework and has to save the data which the editor holds. If saving the data was successful it should call the setDirty(false) method on the MDirtyable object.

The following example demonstrates that.

 

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

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

public class SaveHandler {

  @Execute
  void execute(EPartService partService) {
    partService.saveAll(false);
  }
}

 

8.4. MPart and multiple editors

You can use the MPart model element to create multiple editors. Every model element can get persisted data assigned which can be accessed via the getPersistedState() method.

In its @PostConstruct method the implementation class can get the MPart injected and access its persisted state. This information can be used to configure the editor.

8.5. MInputPart

Alternatively to the usage of MPart for implementing editors you could use the MInputPart model element. The Eclipse platform team currently does not use MInputPart for the Eclipse IDE implementation. They use the approach described in Section 8.4, “MPart and multiple editors”. For this reason the author of this book recommends the usage of MPart to implement editors.

9. Command and Handler service

9.1. Purpose of the command and handler service

The command and handler services provide the functionality to work with commands and handlers.

Via the handler service you can create, activate and trigger handlers based on commands. The command service allows you to access, and configure commands, i.e. by setting the parameters.

9.2. Access to command and handler service

You can use dependency injection to access the services. The relevant interfaces are ECommandService and EHandlerService.

9.3. Example

The following example shows how to add a new handler to an existing command. It assumes that the AboutHandler class already exists.

 

Command command = commandService.getCommand("com.example.mycommand");

// check if the command is defined
System.out.println(command.isDefined());

// activate Handler, assume AboutHandler() class exists already
handlerService.activateHandler("com.example.mycommand", 
    new AboutHandler());

ParameterizedCommand cmd =
  commandService.createCommand("com.example.mycommand", null);

// check if the command can get executed
System.out.println(handlerService.canExecute(cmd));

// execute the command
handlerService.executeHandler(cmd);

 

10. Learn more about Eclipse 4 RCP development

I hope you enjoyed this part of the Eclipse 4 series. 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.

You find a complete and extended description of Eclipse 4 RCP development in the upcoming Eclipse 4 RCP book of Lars Vogel.