EMF provides an Adapter mechanism to notify listeners when
objects change. In a transactional environment, though, we can end up reacting to changes
only to find that they are reverted when a transaction rolls back. The EMF Transaction API
provides a different kind of listener interface, one that receives the same
Notifications, but not until the very end of a transaction:
the
ResourceSetListener.
The ResourceSetListener interface has two call-backs. A
post-commit event notifies a listener of all of the changes, in a single batch, that were
committed by a transaction. If a transaction rolls back, no event is sent because there
were no changes. There are exceptions for changes that are not (and need not be) undone,
such as resource loading and proxy resolution.
The other call-back is the pre-commit event, used in the implementation of triggers, which
is
another topic.
[
as SVG]
Post-Commit Listeners
As indicated above, post-commit listeners receive Notifications
after a transaction has successfully committed the changes that they represent. The
resourceSetChanged() call-back supplies a
ResourceSetChangeEvent
bearing the following information:
-
editingDomain: the editing domain in which resource set
the changes occurred
-
notifications: the list of notifications, in the order in
which they were fired, indicating the changes that occurred. These are the same
notifications that have already been received by Adapters
-
transaction: a reference to the Transaction
object that was completed. Amongst other things, this transaction has a status
(possibly containing warnings or info messages from validation), a
ChangeDescription summarizing the changes, and possibly
an OPTION_IS_UNDO_REDO_TRANSACTION marker option indicating
that the changes occurred in the undoing or redoing of a command
Listeners are attached to the editing domain. They can declare
NotificationFilters
that determine which notifications are of interest to them. The available filters test
various attributes of a notification and can be combined using standard Boolean operators.
TransactionalEditingDomain domain;
class MyListener extends ResourceSetListenerImpl {
public void resourceSetChanged(ResourceSetChangeEvent event) {
System.out.println("Domain " + event.getEditingDomain().getID() +
" changed " + event.getNotifications().size() + " times");
}
}
ResourceSetListener listener = new MyListener();
domain.addResourceSetListener(listener);
The
ResourceSetListenerImpl
class is a convenient base class for listeners, providing no-op implementations of the
call-backs for selective overriding.
Receiving all of the notifications that occurred during the transaction in one batch is
convenient for listeners that need to analyze the entire set of changes. Conversely,
sometimes it is more convenient to handle events one by one. A convenient listener
abstraction for such situations is the
DemultiplexingListener,
class. Simply implement the handleNotification() method to
deal with each notification individually.
class MyDemuxedListener extends DemultiplexingListener {
protected void handleNotification(TransactionalEditingDomain domain,
Notification notification) {
System.out.println("Domain " + domain.getID() +
" changed: " + notification.getNotifier());
}
}
Advantages of the ResourceSetChangedEvent include:
- listeners know that the changes are permanently committed
- notifications can be processed efficiently as an aggregate
- listeners don"t need to worry about dependency on "future" changes
- no further changes can occur while the change event is being dispatched
- listeners are invoked in read-only transactions, so that they can safely
read the resource set while analyzing the changes
Listeners need to be aware that notifications are delayed relative to the timing of the
changes. Notifications are only received after all changes are complete. Any given notification may
not correspond to the current state of the resource set, depending on subsequent changes.
Static Listener Registration
Attaching listeners to the editing domain at run-time works well for many applications.
However, sometimes a plug-in doesn't get a chance to attach a listener or isn't even
activated before interesting changes occur to which it needs to respond. For these
situations, the EMF Transaction API provides the
org.eclipse.emf.transaction.listeners
extension point. This allows applications to statically register listeners against one
or more editing domains. The associated editing domains may be
registered either statically or at run-time. In either
case, as soon as the editing domain is instantiated in or added to the registry, its
registered listeners are created and attached.
<extension point="org.eclipse.emf.transaction.listeners">
<listener class="org.eclipse.example.MyListener">
<editingDomain id="org.eclipse.example.MyEditingDomain"/>
</listener>
</extension>
A listener can be associated with zero or more editing domains, by ID. In the case of
zero editing domains, the listener is implicitly attached to all editing domains that
are registered, either statically or at run-time. Listeners cannot be registered on
editing domains that are not present in the
Registry,
even if they do have IDs.
Copyright (c) 2006, 2007 IBM Corporation and others. All Rights Reserved.