Differences between revisions 7 and 10 (spanning 3 versions)
Revision 7 as of 2006-10-06 16:36:51
Size: 4447
Editor: adsl-70-132-0-3
Comment:
Revision 10 as of 2006-10-06 18:16:22
Size: 14010
Editor: adsl-70-132-0-3
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.


Line 83: Line 195:


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. 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.

   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 a 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:

   a. Help listeners know if other objects they wish to investigate are in a consistent state.

   a. Allows Sources (or !ChangeManager) to avoid unneeded notifications, based on object state (ignore firing notifications during CREATION_IN_PROGRESS).

   a. Allow immediate catching of the use of deleted objects.
{{{
      if (isState(LifeState.DELETED)) { // throw exception here }
}}}

Discussion Title : ...

Editor(s): ...

TableOfContents([2])

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

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.

  • 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 a 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.

      if (isState(LifeState.DELETED)) { // throw exception here }

General Notes

References

Discussion

PageComment2

CyEvent_Handling (last edited 2009-02-12 01:04:13 by localhost)

Funding for Cytoscape is provided by a federal grant from the U.S. National Institute of General Medical Sciences (NIGMS) of the Na tional Institutes of Health (NIH) under award number GM070743-01. Corporate funding is provided through a contract from Unilever PLC.

MoinMoin Appliance - Powered by TurnKey Linux