Version 6.1
Copyright © 2009, 2010 , 2011 , 2012 Lars Vogel
08.10.2012
| Revision History | |||
|---|---|---|---|
| Revision 0.1 | 14.02.2009 | Lars Vogel |
created |
| Revision 0.2 - 6.1 | 16.02.2009 - 08.10.2012 | Lars Vogel |
bug fixes and enhancements |
Table of Contents
The following description is based on Eclipse 4 RCP tutorial .
In your application you frequently have the need to communicate between application components.
For example the user selects an object in a
Tree
widget and a
part
is updated with this information.
This example can be handled by the selection service. But frequently you want to propagate more than just a selection between the different components of your application. For example a non-visual component wants to send a data update to all relevant visual components.
For this purpose the Eclipse platform provides a global event based communication system, called the event bus. Software components can register for certain events and other components can send new events to the event bus.
The Eclipse platform will make sure that registered components will receive the messages. Eclipse 4 uses this event system for the complete internal communication.
The Eclipse framework uses the event notification system for its
internal
communication based on the
IEventBroker
service.
This communication service can also be used
to
communicate
between your
own application components.
IEventBroker
is based on the OSGi
EventAdmin
service but has been wrapped with a simpler API.
It also automatically
removes any
event subscriptions
when the defining
IEclipseContext
is disposed.
The following plug-ins contain the
IEventBroker
functionality:
org.eclipse.e4.core.servicesorg.eclipse.osgi.services
Via the
IEventBroker
service you can send or post events.
The classes in your application can
register as
event
listeners
for
specific events. Other classes in your
application
use the
service to
send events.
You can subscribe to specific topics but also use wildcards to
subscribe to all subevents. Subevents are separated by
/.
package com.example.e4.rcp.todo.events; public interface MyEventConstants { public static final String TOPIC_TODO_DATA_UPDATE = "TOPIC_TODO_DATA_UPDATE/*"; public static final String TOPIC_TODO_DATA_UPDATE_NEW = "TOPIC_TODO_DATA_UPDATE/NEW"; public static final String TOPIC_TODO_DATA_UPDATE_DELETE = "TOPIC_TODO_DATA_UPDATE/DELETED"; public static final String TOPIC_TODO_DATA_UPDATE_UPDATED = "TOPIC_TODO_DATA_UPDATE/UPDATED"; }
@Inject @Optional private void getNotified(@UIEventTopic(MyEventConstants.TOPIC_TODO_DATA_UPDATE) String s) { if (viewer!=null) { viewer.setInput(model.getTodos()); } }
The
IEventBroker
service can be injected via dependency injection.
@Inject private IEventBroker eventBroker;
The following code examples assumes that you have a class named
MyEventConstants
defined which contains a static final field (constant)) for the
TOPIC_NEWDATA
string.
The
IEventBroker
service
collects all events and
sends them
to the registered classes.
This can be done
asynchronously or
synchronously.
@Inject IEventBroker broker; ... // asynchronously broker.post(MyEventConstants.TOPIC_NEWDATA, "New data");
@Inject IEventBroker broker;
...
// synchronously sending a todo
// Caller will block until delivery
broker.send(TOPIC_NEWDATA, todo);
You can now send arbitrary Java objects or primitives through the event bus.
You can use dependency injection to register and respond to events.
The
@EventTopic
and
@UIEventTopic
annotations tag methods and fields that should be notified on event
changes. The
@UIEventTopic
ensures the event notification is
performed
in the user interface
thread.
// Constant for event registration public static final String TOPIC_NEWDATA = "TOPIC_NEWDATA"; // Register to the topic TOPIC_NEWDATA for // objects of type Todo @Inject @Optional void closeHandler(@UIEventTopic(TOPIC_NEWDATA) Todo todo) { // Do something } //Register to the topic TOPIC_NEWDATA for //objects of type String @Inject @Optional void closeHandler(@UIEventTopic(TOPIC_NEWDATA) String s) { // Do something }
Alternatively an object can also register an instance of the
EventHandler
directly with
the
IEventBroker
via the
subscribe()
method. Using dependency injection for subscribing should be
preferred compared to the direct subscription.
It is also possible to register for Eclipse
framework
events. The
UIEvents
class from the
org.eclipse.e4.ui.workbench
contains all framework events. This class also contains in its
Javadoc information about the purpose of events.
For example the
UIEvents.UILifeCycle.APP_STARTUP_COMPLETE
event is triggered once the application has started. This event was
introduced with Eclipse 4.3, see https://bugs.eclipse.org/376821.
Or the
UIEvents.UILifeCycle.ACTIVATE
event is triggered if a
part
is activated.
@Inject @Optional public void partActivation(@UIEventTopic(UIEvents.UILifeCycle.ACTIVATE) Event event) { // Do something System.out.println("Got Part"); }
This allows you for example to put a Context variable called
myactivePartId
on every part change
into the application context.
// Set a context variable @Inject @Optional public void partActivation(@UIEventTopic(UIEvents.UILifeCycle.ACTIVATE) Event event, MApplication application) { // Don't inject MPart and IEclipseContext! Need from root context here MPart activePart = (MPart) event. getProperty(UIEvents.EventTags.ELEMENT); IEclipseContext context = application.getContext(); if (activePart != null) { context.set("myactivePartId", activePart.getElementId()); } }
This context variable can be used to define a visible-when clause which can be used to restrict the visibility of menus and toolbars.
<?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.4"?> <plugin> <extension id="product" point="org.eclipse.core.runtime.products"> <product application="org.eclipse.e4.ui.workbench.swt.E4Application" name="to-do"> <property name="applicationXMI" value="com.example.e4.rcp.todo/Application.e4xmi"> </property> <property name="appName" value="to-do"> </property> </product> </extension> <extension point="org.eclipse.core.expressions.definitions"> <definition id="com.example.e4.rcp.todo.todooverviewselected"> <with variable="myactivePartId"> <equals value="com.example.e4.rcp.ui.parts.todooverview"> </equals> </with> </definition> </extension> </plugin>

The Eclipse platform places several ContextVariables into the
context. Several
keys are defined in the
IServiceConstants
interface.
Context variables
can be used to share your application state,
instead
of the
IEventBroker
service.
If you put
Context variables
into a
context which is
available to other objects, for example the
application
context, these
other objects can use
@Inject
to get these
Context variables
injected.
The
IEventBroker
is a global event bus and is unaware of the
IEclipseContext
hierarchy.
Context variables
provide an improved way to manage scoped shared
application state.
The advantage of the
IEventBroker
Service is that it supports
sending event
information without
knowing who
is receiving
it. Interested
classes
can register for
events without
knowing who is
going to provide
them.
This is known as
the whiteboard
pattern and
this pattern supports the creation of very loosely
coupled application
components.
The disadvantage is that it is a global bus, i.e. there is no scoping of the events. Publishers have to ensure they provide enough information in the event for subscribers to discriminate and decide that the particular event is applicable to them.
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.