EMF Client Platform Core API

The EMF Change Broker

Many applications require to listen to entity objects. EMF supports this use case well, it allows to register listeners (“Adapters”) on every EObject, which get notified on every change of a model instance. The ready-to-use EContentAdpater can even be automatically subscribed to a complete tree of a model instance and is therefore notified about all changes in a model instance. However, when implementing Adapters in EMF, the developer typically has to filter the received events for relevance. As an example, you might want to listen only to changes on a certain entity type (“EClass”). Additionally, you ideally want to maintain as few EContentAdapter as possible, as they get notified about all changes, they can potentially slow down an application.

Both issues can be solved with the EMF ChangeBroker, a component of the EMF Client Platform.

The change broker is a stand-alone component, which can used in combination with any EMF model. There is a ready-to-use integration with the persistence layer of the EMF Client Platform, but the Change Broker can also be used stand-alone without other components of the EMF Client Platform.

The following diagram shows an overview of the ChangeBrokers’s architecture.

image01

To keep the component independent of any concrete change notification mechanism, the Broker itself does only dispatch notifications to listeners. The notifications are delivered by a “NotificationProvider”. In a simple scenario, this can just be an EContentAdapter, which forwards all notification of a model instance to the Broker. NotificationProvider need to implement the interface:

org.eclipse.emf.ecp.changebroker.spi.NotificationProvider

There is a ready-to-use implementation for the EMF Client Platform persistence layer:

org.eclipse.emf.ecp.changebroker.provider.internal.ECPNotificationProvider

If you want to implement a custom NotificationProvider for your own persistence layer or for plain xmi files, there is a conviniance implementation, which you can use as a base class:

org.eclipse.emf.ecp.changebroker.spi.AbstractNotificationProvider

A simple NotificationProvider could for example just register an EContentProvider on the model to be notified about changes and to push them to the ChangeBroker. In this case, make sure, that the following methods of the AbstractNotificationProvider get called by your custom NotificationProvider:

  • notify: When an element is changed. You need to pass the EMF Notifcation as a parameter
  • canDelete: Before an element gets deleted. If this method return fale, a Listener has given a veto to the delete, so it should not be deleted
  • preDelete: Before an element is deleted. Allows clean-up operations.
  • postDelete: After an element is deleted

The reason, why delete events are handled separately is that EMF does not support delete events natively. If you delete an element, e.g. with a DeleteCommand, EMF will remove the cross-references and then remove the element from its parent. In this case, you would just receive remove notifcations. Those are not automatically delete events. An element, which is moved in the containment hierarchy would trigger a remove and subsequently an add event. If you want to listen to delete events, we recommend you implement an explicit service (or method) to call in your application and trigger the ChangeBroker in this method.

Finally, you need to register your NotificationProvider as an OSGi service, so it can be picked-up by the ChangeBroker. We recommend to use declarative service for this purpose.

Once the NotificationProvider is set-up, you can use the ChangeBroker and register listeners to it. The ChangeProvider itself is an OSGi service, too, so you can retrieve it using declarative services, the OSGi API or dependency injection (in Eclipse 4).

The Change Broker supports the following types of listeners, which can registered to it:

  • ChangeObserver
    Is notified, when a change is done on the observed model instance. ChangeObserver can either listen to all changes of a model instance or only to changes on certain EAttributes, EReferences or EClasses. We provide a more detailed description in the next section.
  • ReadOnlyChangeObserver
    Are notified as ChangeObserver, but they are not allowed to do any changes on the model.
  • VetoableDeleteObserver
    Is notified, before a delete operation is executed. The observer can veto on the delete by returning “false”. In this case, the delete will be aborted and no other delete observer will be notified.
  • PreDeleteObserver
    Is notified before a delete operation is executed. The element is not yet deleted, therefore, the context of the element can be accessed in the observer.
  • PostDeleteObsever
    Is notified after a delete operation is executed. The element is deleted but can be accessed in the observer.

The Broker provides a fine-grained API to register listeners for particular events. As an example, the following registration will notify the listener only on changes on the EClass “myEClass”:

changeBroker.subscribeToEClass(myObserver, myEClass)

Analogously, it is also possible to register an observer to certain EFeatures (EAttributes or EReferences)

changeBroker.subscribeToFeature(observer, myEStructuralFeature);

Finally, you can also subscribe to a subtree of your model, more precisely to all changes which are done to an element of a certain EClass and its sub elements using:

changeBroker.subscribeToTree(observer, myEClass);

The ChangeBroker can also be turned off and on, in case you apply certain operations on a model instance, which should not trigger any notifications. As the ChangeBroker itself does not have any dependency except EMF, it can be used in various contexts and also without any other parts of the EMF Client Platform. We hope this component is of use for you. If you discover any issues or if you have feature requests, please use the newsgroup or the bug tracker to communicate those.

Listening to EMF Client Platform Events

The EMF Client Platform enables the developer to register for a couple of events and react, once they occur. Example for such events are the creation of a project, the modification of a repository or the modification of objects in a project. The EMF Client Platform facilitates an ObserverBus Pattern instead of a traditional Listener approach. All events are published thru this ObserverBus, inturn, all listeners register on this bus as observer. In this architecture, you need to know, what kind of observer you want to implement, but you don’t have to know a specific place to register it.

There are two ways of finding out, which listeners can be registered. First, by looking at the type hierarchy of ECPObserver. Open the Interface (e.g. by using CTRL+SHIFT+T) and press CTRL+T. The appearing list shows all available Observers you can implement:

image10

The documentation and signature of the interfaces will tell you, when a certain observer type will get notified.

Alternatively, if you know what you want to listen to, you can search for the right observer using CRTL+SHIFT+T. All observers start with “ECP” and end with “Observer”. In the middle of the name, an observer tells about the observed event. So, if you want to listen to events connected to projects, you can type “ECP*Project*Observer” to see all related observer types:

image18

Once you have selected the right observer, you only need to implement the respective interface. The following code example implements an ECPProjectOpenClosedObserver, which is notified in case a project is opened or closed.

private final class MyObserver implements ECPProjectOpenClosedObserver {
@Override
  public void projectChanged(ECPProject project, boolean opened) {
    if(opened){
      System.out.println("Project "+project.getName()+" has been opened.");
    }
    else {
      System.out.println("Project "+project.getName()+" has been closed.");
    }
  }
}

 

Finally you need to register and register your Observer on the ObserverBus. The ObserverBus can be retrieved using the ECPUtil. Once the Observer is not needed anymore it should be unregistered. The following code example registers and unregisters the example observer:

myObserver observer = new MyObserver();
ECPUtil.getECPObserverBus().register(observer);
ECPUtil.getECPObserverBus().unregister(observer);