Size: 4447
Comment:
|
Size: 10530
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 30: | Line 30: |
and user selection of some !CyEdges and !CyNodes within a !CyNetworkView. |
change of an attribute value associated with a !CyNode, and user selection of some !CyEdges and !CyNodes within a !CyNetworkView. |
Line 78: | Line 79: |
1. What objects can be examined by a Listener and how does the Listener know if the Objects are in a consistent state? During a notification, the state of various Cytoscape objects may be examined by the Listener. What guarantee does the Listener have that the state of the Cytoscape objects are consistent? It must be made clear what objects can be examined, either through documentation, through calling a method that determines consistency, or by ensuring the implementation is such that object state is consistent at the time of the notification. 2. How specific are the Sources to which a Listener can listen? At one extreme, a Listener could register to receive, say deletion notifications, from all sources. Less extreme would be receiving deletion notifications from any instance of a particular class, like a !CyNetwork. At the other extreme is registering interest in a specific instance of a given class, as in "tell me when !CyNetwork 4 is deleted." Instance specific notifications are more efficient in that they avoid unneeded notifications but require more management overhead in terms of registering and unregistering interest in objects. Instance specific notifications also imply tracking listeners on a per-instance basis. Note that some events are inherently class-specific, not instance-specific, such as creation events. 3. How specific are the events to which a Listener can listen? As one extreme, a Listener could only listen for a general message that something changed. On the other extreme, a very specific type of change can be listened for. An example of the two extremes is the general Java Swing !PropertyChangeEvent versus the specific !CyNetworkNodeAddedEvent. For the !PropertyChangeEvent, there may large numbers of listeners and a listener listening to such events my get large numbers of notifications for which it must filter (e.g., check the event type). For the specific !CyNetworkNodeAddedEvent, a Listener will only notified when a Node is added to a !CyNetwork (possibly one !CyNetwork of interest, based on issue #1). Specific event listening is more efficient in that is avoids unneeded notifications but proliferate more classes and interfaces since there will be more notification interfaces and potentially more listener event interfaces. 4. How much information should be passed in an event notification (push vs pull)? How much information is directly passed about a specific event (pushed) versus the listener having to query the Source for information (pull). In the exteme, the push model packages up a lot of information to pass to the listener and the pull model passes nothing. The tradeoff is between receiving unneeded information, which may be some what inefficient, and having to compute what the changes were, which could be very inefficient. For example, we might have a !CyNetwork where an Edge was added. In the pull model, the Listener may only be told that a !CyNetwork changed. For some listeners, this may be enough information for them to do their processing, however, if the listener must know that an Edge was added and exactly which Edge, it must somehow compute this information, if even possible. In the push model, the listener would be told that an Edge was added and exactly what Edge. If the listener doesn't care about this information, then it is a waste, if the listener does need to know about the edge, then this is efficient. 5. When should event notifications be fired in batches or not fired at all? In the simple case, we would always fire notifications whenever a Source's state changes, but there are cases where this is a problem. Consider importing a large !CyNetwork and its attributes. During the import process, the !CyNetwork is created and many !CyNodes and !CyEdges are created and added to this !CyNetwork along with large numbers of attribute changes. Now, various Listeners, such as the !CytoscapeEditor, work fine for a few change notifications, are now bogged down with large numbers of changes and are attempting to do computationally intensive operations, like refreshing the display after every notification. Do we want to fire just one high-level !CyNetwork creation event or include all the low-level events that occurred in creating the Network, or to somehow "batch" up large numbers of events in a way the Listeners know they are receiving a batch? Change notifications may not want to be fired at all during construction. For example, when the !CyNetwork is being imported, we might not want to have !CyNode/!CyEdge add events taking place because the !CyNetwork to which the !CyNodes and !CyEdges belong is only partially constructed.[[BR]] [[BR]]'''Batching Notifications Using a !NotificationQueue''' [[BR]]One way to batch notifications is to place them on a Queue (!NotificationQueue) and then, at appropriately determined times (when the object structure is more consistent), dispatch them. Note that care must be taken in dispatching notifications in this queue, since objects may have changed in ways that make certain events wrong or unneeded. For example, we may queue a bunch of notifications that occur during the deletion of an object. The queue may then be processed after the object was deleted, forcing the events referring to this object to be no longer valid (e.g., we are forced to throw out events on deleted objects). 6. Do we want to centralize event handling in a "!ChangeManger"? A !ChangeManager can be created that handles all the "heavy-lifting" of registering listeners and performing notifications. This can reduce the duplication of code and reduce potential bugs in the notification process. |
Discussion Title : ... |
Editor(s): ... |
About this document
This is an official Discussion page for Cytoscape Event Handling.
Status
Open for public discussion.
How to Discuss
To view/add discussion comments, click on any of 'Comment' links below. By adding your ideas to the Wiki directly, we can more easily organize everyone's ideas, and keep clear records. Try to keep the discussion as concrete and constructive as possible. Be sure to include today's date and your name for each comment.
Discussion Topic
Backgound
Event handling considers how to cleanly, flexibly, and efficiently notify other classes, components, and plugins of important events that take place. In Cytoscape, examples of events are the creation or deletion of a CyNode, the addition of a CyEdge to a given CyNetwork, change of an attribute value associated with a CyNode, and user selection of some CyEdges and CyNodes within a CyNetworkView.
There are many situations where event handling is needed. One common one is whenever a component must monitor the content of another component or class. For example, the CytoscapeEditor would monitor any changes to a CyNetwork being edited so that changes to the CyNetwork, outside of the editor, could be correctly reflected in the Editor. Another example is the Agilent Literature Search plugin that keeps and displays literature information associated with CyEdges in a CyNetwork. If one of these CyEdges is deleted, the associated literature information in the plugin must be updated.
A key concern of most event handling mechanisms is to avoid strongly coupling the components that fire events with the components that want to find out about events. For example, it is not a viable solution to hardcode event notification calls from a component to the components that want to find out about events. This is because the components interested in event information are usually unknown, or likely to change (e.g., any arbitrary plugin).
To avoid strongly coupling components, a general mechanism is used throughout Java's AWT, Swing, and within Java Beans, called the [http://java.sun.com/j2se/1.3/docs/guide/awt/designspec/events.html Delegation Event Model]. This model is based on the Observer Design pattern (see Design Patterns, Gamma et. al, p. 293). Cytoscape's event handling is an extension of this model.
Terminology
Some terminology used in this document:
- Event Listener (or just Listener)
An instance of a class that implements a specific listener interface in order to obtain event notifications. This is equivalent to the ConcreteObserver in the Observer design pattern.
- Event Source (or just Source)
The object whose state changes are of interest to Event Listeners (which will find out about the state change through an event notification). This is equivalent to the ConcreteSubject in the Observer design pattern.
- Event Notification (or just Notification)
- The method invoked on an Event Listener to specify that an event took place. The method invocation may include extra information about the event through extra passed parameters.
Source of Issue
Cytoscape's existing event handling is spotty, inconsistent, and undocumented. This has led to various bugs, inefficiencies, and the need for various work arounds by several plugins (and probably in the core). A consistent overall procedure and design are needed for how Cytoscape should treat event handling and existing core code should be changed to follow this procedure and design.
Complexities
1. What objects can be examined by a Listener and how does the Listener know if the Objects are in a consistent state?
- During a notification, the state of various Cytoscape objects may be examined by the Listener. What guarantee does the Listener have that the state of the Cytoscape objects are consistent? It must be made clear what objects can be examined, either through documentation, through calling a method that determines consistency, or by ensuring the implementation is such that object state is consistent at the time of the notification.
2. How specific are the Sources to which a Listener can listen?
- At one extreme, a Listener could register to receive, say deletion notifications, from all sources. Less extreme would be receiving deletion notifications from any instance of a particular class,
like a CyNetwork. At the other extreme is registering interest in a specific instance of a given class, as in "tell me when CyNetwork 4 is deleted." Instance specific notifications are more efficient in that they avoid unneeded notifications but require more management overhead in terms of registering and unregistering interest in objects. Instance specific notifications also imply tracking listeners on a per-instance basis. Note that some events are inherently class-specific, not instance-specific, such as creation events.
3. How specific are the events to which a Listener can listen?
- As one extreme, a Listener could only listen for a general message that something changed. On the other extreme, a very specific type of change can be listened for. An example of the two extremes is the
general Java Swing PropertyChangeEvent versus the specific CyNetworkNodeAddedEvent. For the PropertyChangeEvent, there may large numbers of listeners and a listener listening to such events my get large numbers of notifications for which it must filter (e.g., check the event type). For the specific CyNetworkNodeAddedEvent, a Listener will only notified when a Node is added to a CyNetwork (possibly one CyNetwork of interest, based on issue #1). Specific event listening is more efficient in that is avoids unneeded notifications but proliferate more classes and interfaces since there will be more notification interfaces and potentially more listener event interfaces.
4. How much information should be passed in an event notification (push vs pull)?
- How much information is directly passed about a specific event (pushed) versus the listener having to query the Source for information (pull). In the exteme, the push model packages up a lot of information to pass to the listener and the pull model passes nothing. The tradeoff is between receiving unneeded information, which may be some what inefficient, and having to compute what the changes were, which could be very inefficient.
For example, we might have a CyNetwork where an Edge was added. In the pull model, the Listener may only be told that a CyNetwork changed. For some listeners, this may be enough information for them to do their processing, however, if the listener must know that an Edge was added and exactly which Edge, it must somehow compute this information, if even possible. In the push model, the listener would be told that an Edge was added and exactly what Edge. If the listener doesn't care about this information, then it is a waste, if the listener does need to know about the edge, then this is efficient.
5. When should event notifications be fired in batches or not fired at all?
- In the simple case, we would always fire notifications whenever a Source's state changes, but there are cases where this is a
problem. Consider importing a large CyNetwork and its attributes. During the import process, the CyNetwork is created and many CyNodes and CyEdges are created and added to this CyNetwork along with large numbers of attribute changes. Now, various Listeners, such as the CytoscapeEditor, work fine for a few change notifications, are now bogged down with large numbers of changes and are attempting to do computationally intensive operations, like refreshing the display after every notification.
Do we want to fire just one high-level CyNetwork creation event or include all the low-level events that occurred in creating the Network, or to somehow "batch" up large numbers of events in a way the Listeners know they are receiving a batch? Change notifications may not want to be fired at all during
construction. For example, when the CyNetwork is being imported, we might not want to have !CyNode/!CyEdge add events taking place because the CyNetwork to which the CyNodes and CyEdges belong is only partially constructed.BR
BRBatching Notifications Using a NotificationQueue
BROne way to batch notifications is to place them on a Queue (NotificationQueue) and then, at appropriately determined times (when the object structure is more consistent), dispatch them. Note that care must be taken in dispatching notifications in this queue, since objects may have changed in ways that make certain events wrong or unneeded. For example, we may queue a bunch of notifications that occur during the deletion of an object. The queue may then be processed after the object was deleted, forcing the events referring to this object to be no longer valid (e.g., we are forced to throw out events on deleted objects).
6. Do we want to centralize event handling in a "ChangeManger"?
A ChangeManager can be created that handles all the "heavy-lifting" of registering listeners and performing notifications. This can reduce the duplication of code and reduce potential bugs in the notification process.
Use Cases
Possible Solution Strategies
General Notes
References