## This template may be useful for creating new Discussion pages ## This is a wiki comment - leave these in so that people can see them when editing the page ||'''Discussion Title''' : Cytoscape Event Handling ||'''Editor(s)''': ... || <> == About this document == This is an official Discussion page for '''Cytoscape Event Handling'''. == Status == ##Put the date and the status. Status can be e.g. "Not yet completely written", "Open for public discussion", "Closed for public discussion". There could be some explanation of the 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 == ## describe the nature of the issue === 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 discussion: 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 == ## particular bug? feature need? or implementation obstacle? 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 == ## what other issues does this topic involve? 1. For what types of events should we fire notifications? . What events are important enough to require notifications? What are Listeners likely to need? Common events that usually require notifications are are creation, modification, selection, and deletion events. Should Cytoscape be consistent in the types of notifications it fires (e.g, if one type of Cytoscape object fires creation notifications, then all Cytoscape objects should fire creation notifications)? Are there events where notifications are required before and after the event takes place? One example might be an import event, where it might be important for Listeners to know that an import is about to start so that it can perform different behavior during the import process (for example, see Complexity #6). 2. 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. 3. 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. 4. 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 Complexity #3). 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. 5. 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 somewhat inefficient, and having to compute what the changes were, which can 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. 6. 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, that work fine for a few change notifications, are now bogged down with large numbers of changes in attempting to do more involved 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 may only be partially constructed.<
> <
> '''Batching Notifications Using a !NotificationQueue''' <
> 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). 7. Do we want to centralize event handling in a "!ChangeManager"? . 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 == ## what features/functions are affected and how do they relate to particular applications == Possible Solution Strategies == ## initial ideas for how to go about addressing the issue 1. General Approach: Rule #1: When notifications are invoked, the state of all Cytoscape objects directly referened by the notificaton should be well defined and consistent. . Note that this is less restrictive then saying ''all'' Cytoscape objects should be well defined and consistent. This may be hard to achieve for complex nested operations and still have notifications triggered anywhere near when the events actually took place (if it can be, then all the better). * A corollary to Rule #1 is: . The consistency of other objects not directly referenced by the notification should be easily determined.<
> <
> Thus, we should be able to easily tell if some Cytoscape object is in an ill-defined state. For example, we might delete a !CyNetwork. During the removal, a !CyNode that belongs to the !CyNetwork may be deleted and we may receive an event notification about its deletion. If we attempt to examine this !CyNetwork during the !CyNode event notification, we should be able to easily determine if the !CyNetwork is consistent. 2. All Sources should completely and carefully document fired notifications. . Every Cytoscape API operation that fires events must be noted with explict information on what notifications are fired, what arguments are passed to the notification, the safety of modifying given arguments and inspecting objects in the environment, and any other relevent information needed. Without this kind of information, developers must look at the code and have no guarantee the notifications will be stable underneath them. 3. Creation event notifications should always be signalled after the created object is fully created or restored. . If the notifications occur before the object is fully created, inspection of the partially created object by the listener may lead to misleading or incorrect results (breaks Rule #1). 4. An Object deletion event notification should occur ''before'' the object is deleted (follow Rule #1). . This way a Listener can safely inspect the object to be deleted.<
> <
>It is a benefit to attempt to catch illegal object modifications made from within listeners, such as attempting to (re)delete an existing object we are in the middle of deleting. 5. Change event notifications (e.g., renames, deletions, additions) should never be fired when an object is not yet fully defined (e.g,. during object deletion or creation). 6. For more push oriented event notifications, create a standard EventNotification object used to pass all needed information. . We've found having an EventNOtification Type (e.g, EDGE, NODE, NETWORK, GROUP), and subType (e.g., ADDED, REMOVED, SET) and methods for setting and getting the affected object and any supporting information to be useful. 7. Consider adding a "!LifeState" to Cytoscape objects. . Each object would have information about it's Life state, such as CREATION_IN_PROGRESS, NORMAL, DELETION_IN_PROGRESS, DEAD. Have a !LifeState could: * Help listeners know if other objects they wish to investigate are in a consistent state. * Allows Sources (or !ChangeManager) to avoid unneeded notifications, based on object state (ignore firing notifications during CREATION_IN_PROGRESS). * Allow immediate catching of the use of deleted objects. For example: {{{ if (isState(LifeState.DELETED)) { // throw exception here } }}} == General Notes == == References == == Discussion == GaryBader - 2006-10-09 11:42:47 We should investigate the event handling model in the caWorkbench software by the Califano group at Columbia. They claim to have written an event model from scratch that is very efficient (for both of our use cases). Their software is project based and the user can load many tabs (their version of plugins). Changes to any project settings, such as selection of genes in a list, are propagated to all tabs, which dynamically update themselves. The code is open source.