|
||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
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 | |
---|---|
NetChangeObserver.ChangeType |
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.
|
||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |