Package org.modeshape.graph.observe

The Observation API provides several mechanisms for asynchronously observing changes to content.


Interface Summary
Observable Interface used to register listeners.
ObservationBus A simple Observer that is itself Observable.
Observer The interface for an observer of graph changes.

Class Summary
ChangeObserver Abstract class that is used to signal that a change set has occurred.
ChangeObservers Reusable manager of change listeners, typically employed by another Observable implementation.
Changes A set of changes that were made atomically.
LocalObservationBus A simple Observer that is itself Observable.
NetChangeObserver A specialized Observer that figures out the net changes made during a single set of changes.
NetChangeObserver.NetChange A notification of changes to a node.
NetChangeObserver.NetChanges A set of net changes that were made atomically.

Enum Summary

Package org.modeshape.graph.observe Description

The Observation API provides several mechanisms for asynchronously observing changes to content.

Many event frameworks define the listeners and sources as interfaces. While this is often useful, it requires the implementations properly address the thread-safe semantics of managing and calling the listeners. This observation framework uses abstract or concrete classes to minimize the effort required for implementing ChangeObserver or Observable. The classes also allow the framework to implement a number of utility methods, such as the unregister() method on ChangeObserver, that also save effort and code.

However, one of the more important reasons for providing classes is that ChangeObserver uses weak references to track the Observable instances, and the ChangeObservers class uses weak references for the listeners. This means that if an observers do not prevent Observable instances from being garbage collected, nor do observers prevent Observable instances from being garbage collected.


Any component that can have changes and be observed can implement the Observable interface. This interface allows Observers to register (or be registered) to receive notifications of the changes. However, a concrete and thread-safe implementation of this interface, called ChangeObservers, is available and should be used where possible, since it automatically manages the registered ChangeObserver instances and properly implements the register and unregister mechanisms.


Components that are to recieve notifications of changes are called observers. To create an observer, simply extend the ChangeObserver abstract class and provide an implementation of the ChangeObserver.notify(Changes) method. Then, register the observer with an Observable using its Observable.register(Observer) method. The observer's ChangeObserver.notify(Changes) method will then be called with the changes that have been made to the Observable.

When an observer is no longer needed, it should be unregistered from all Observable instances with which it was registered. The ChangeObserver class automatically tracks which Observable instances it is registered with, and calling the observer's ChangeObserver.unregister() will unregister the observer from all of these Observables. Alternatively, an observer can be unregistered from a single Observable using the Observable's Observable.unregister(Observer) method.


The Changes class represents the set of individual changes that have been made during a single, atomic operation. Each Changes instance has information about the source of the changes, the timestamp at which the changes occurred, and the individual changes that were made. These individual changes take the form of ChangeRequest objects, such as CreateNodeRequest, DeleteBranchRequest, etc. Each request is frozen, meaning it is immutable and will not change. Also none of the requests will be cancelled.

Using the actual ChangeRequest objects as the "events" has a number of advantages. First, there are already a number of existing ChangeRequest subclasses that describe various types of changes in quite a bit of detail; thus no need to duplicate the structure or come up with a generic event class.

Second, the requests have all the state required for an event, plus they often will have more. For example, the DeleteBranchRequest has the actual location of the branch that was delete (and in this way is not much different than a more generic event), but the CreateNodeRequest has the actual location of the created node along with the properties of that node. Additionally, the RemovePropertyRequest has the actual location of the node along with the name of the property that was removed. In many cases, these requests have all the information a more general event class might have but then hopefully enough information for many observers to use directly without having to read the graph to decide what actually changed.

Third, the requests that make up a Changes instance can actually be replayed. Consider the case of a cache that is backed by a RepositorySource, which might use an observer to keep the cache in sync. As the cache is notified of Changes, the cache can simply replay the changes against its source.

Copyright © 2008-2011 JBoss, a division of Red Hat. All Rights Reserved.