Events and E4

The E4 Eclipse application uses events internally to manage the state of the user interface. The decoupling allows the user interface mechanisms to be separated from the user interface renderer, which allows different user interfaces to be presented (such as JavaFX).

There is an E4-specific wrapper for the EventAdmin service called the IEventBroker. This provides a simple mechanism to post or send objects to a particular topic, as well as frontends to register event listeners. It has specific ties to E4 and is present in the UI package. Create a plug-in named com.packtpub.e4.advanced.event.e4.

Tip

To write portable code that processes events headlessly, consider using EventAdmin directly.

Sending events with E4

The IEventBroker can be injected into an E4 component using standard injection techniques, and from that, events can be posted synchronously or asynchronously. Create a class named E4Sender in the com.packtpub.e4.advanced.event.e4 plugin.

Obtaining the service in E4 is done through injection. Since the sender requires this, it will be a non-optional component:

@Inject
IEventBroker broker;

Having obtained the broker service, it can be used to send the e-mail event, in the same way as the previous EventAdmin example:

public void send() {
  String topic = "smtp/high";
  String body = "Sample email sent via event at "
    + System.currentTimeMillis();
  Map<String, String> email = new HashMap<String, String>();
  email.put("Subject", "Hello World");
  email.put("From", address);
  email.put("To", address);
  email.put("DATA", body);
  broker.send(topic, email);
}

The IEventBroker has the same kind of event delivery as with the EventAdmin service; it can either be used to send events asynchronously with post, or synchronously with send.

Tip

There is a subtle difference between EventAdmin and IEventBroker. The former only accepts a Map or Dictionary, while the latter takes any object. If a Map or Dictionary is passed to IEventBroker, it will be passed straight through to the EventAdmin without modification. If the object passed is of another type, it will be wrapped in a Map with the key IEventBroker.DATA (org.eclipse.e4.data).

Receiving events with E4

Since the IEventBroker uses EventAdmin under the covers, it is possible to process an Event with the same mechanism as used earlier in the chapter. However, there is an easier way to receive events with E4 using the @EventTopic and @UIEventTopic annotations. Create a class named E4Receiver in the com.packtpub.e4.advanced.event.e4 plugin.

A method in an E4 component can be annotated with the @Inject and @Optional annotations, and the argument can be annotated with the @EventTopic annotation.

If the argument is an OSGi Event, then it will be passed through as it is. This allows the complete set of properties to be pulled from the Event object and processed in one call:

@Inject
LogService log;
@Inject
@Optional
void receive(@EventTopic("smtp/*") Event event) {
  log.log(LogService.LOG_INFO,
   "Received e-mail to " + event.getProperty("To"));
}

Tip

If the argument type is not an OSGi Event and the type matches the value of the IEventBroker.DATA, then that is used directly. If not, the handler will be ignored. This allows broker.send("topic","value") to be received with an annotation receive(@EventTopic("topic") String value).

The event will be delivered on a background thread. If the processing of the event requires UI interactions, then these will need to be remapped to run on the UI thread instead. E4 provides a UISynchronizer that allows code to run on the UI thread.

There is an alternative annotation that can be used to indicate that the event needs to run on the UI thread. Modifying the annotation to @UIEventTopic instead of @EventTopic will result in the code being automatically run on the UI thread:

void receive(@UIEventTopic("smtp/*") Event event) {
  …
}

Tip

When setting up an event handler in E4 (whether @UIEventTopic or @EventTopic), the documentation suggests using a non-public method. The injector can call non-public methods, and by making the methods non-public, it is ensured that they are not called directly. However, marking them as private may result in the compiler or IDE eliminating the code. Therefore, a minimum of package-level or protected access should be used for such handler methods.

Subscribing E4 EventHandlers directly

It's possible to subscribe event handlers using the EventAdmin directly, but it's also possible to use the IEventBroker to subscribe (and unsubscribe) event handlers. As with EventAdmin, the subscription takes a topic and the handler. By default, calls will be run on the UI thread.

@Inject
IEventBroker broker;
public void subscribeUI(EventHandler handler) {
  // will be called on the UI thread
  broker.subscribe("smtp/*", handler);
}

This allows a custom-built handler to receive events and guarantee that they will be run on the UI thread. E4 uses an (internal) implementation of EventHandler, which delegates to the passed handler, optionally wrapping it in a UISynchronizer.

Create a class named E4Subscriber in the com.packtpub.e4.advanced.event.e4 plugin. To use the IEventBroker class without taking the UI thread, or to pass in a filter, there is an alternative method that provides more options:

public void subscribe(EventHandler handler) {
  broker.subscribe("smtp/*", "(Subject=Hello World)",
   handler, true);
}

The final parameter is whether to run the method headlessly or not (in other words, do not run in the UI). In this case, the true value says that this event should not be run in the UI.

This API is mainly useful if a handler always needs to be run in the UI. Alternatively, the body of the handler can trivially wrap itself in a UI block, such as a UIJob or via the UISynchronize class.

For events that do not need the UI, it is generally more efficient to register them with EventAdmin directly.

Comparison between EventAdmin and IEventBroker

When writing code to handle events, either the EventAdmin or the IEventBroker can be used. Although it may appear that the IEventBroker isolates the caller from having to deal with OSGi classes, if there are several properties that need to be acquired, then casting to an OSGi Event is often necessary.

The other problem is that the IEventBroker has direct references to the EventHandler class in the unsubscribe and subscribe methods. So, any dependency on the IEventBroker will automatically have a dependency on the OSGi EventAdmin classes.

The IEventBroker adds two things that are useful in an E4 application:

  • Wrapping in an appropriate E4 context. This allows the event handler to receive injectable content when an event is received, including being able to receive other E4 contextual information
  • Wrapping in the UI thread, which allows the event handler to process or interact with UI components.

When writing a handler that needs UI or E4 injection, use the IEventBroker to register or use the @EventTopic or @UIEventTopic annotations.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset