ThingChangedEvent

ThingchangedEvents are used internally by VisAD to efficiently trasmit changes from a Thing to an Action. Unlike most other events in VisAD, ThingChangedEvents are "lossy" in that not all of them are delivered. This is by design, because once a Thing is changed, it stays changed relative to an Action until that Action acknowledges the change. The somewhat complex interplay between a Thing and an Action is designed to minimize the amount of work done by an Action as the result of a change.

Sending a ThingChangedEvent from ThingReferenceImpl to ActionImpl

ThingReferenceImpl

A ThingReferenceImpl is associated with an ActionImpl through the addThingChangedListener method. Rather than storing the ActionImpl directly, a reference to it is kept in a ThingChangedLink object. Since multiple ActionImpls can be associated with a single ThingReferenceImpl, each ThingReferenceImpl keeps a list of ThingChangedLinks.

A ThingChangedEvent is created in the incTick() method (which is called whenever the associated Thing is changed) and passed on to all the Actions via the ThingChangedLinks' queueThingChangedEvent method.

ThingReferenceImpl can also return a ThingChangedEvent via its acknowledgeThingChanged method, but this should only be called by ReferenceActionLink's getThingChangedEvent method. This is described more fully below.

(It would be nice if the acknowledgeThingChanged code could be moved directly into ThingChangedLink's getThingChangedEvent, but this proves to be difficult. Since either the ThingReferenceImpl or the Action could be on a a remote machine, the method must reside in the ThingReferenceImpl which has a Remote implementation, rather than in ThingChangedLink which does not.)

ThingChangedLink

Each ThingChangedLink contains a reference to the associated Action, along with space for a single saved ThingChangedEvent. Since ThingChangedEvents only indicate that the associated Thing has changed, only the most recent event needs to be saved.

As described above, a ThingChangedLink receives a ThingChangedEvent from its ThingReferenceImpl via the ThingChangedLink's queueThingChangedEvent method. If the Action isn't currently processing an event from this ThingChangedLink, queueThingChangedEvent passes the event on to the Action via the Action's thingChanged method and the ThingChangedLink notes that the Action is busy (by setting its internal Ball variable to false.) If the Action is busy (because Ball is false) queueThingChangedEvent saves the event.

An Action dequeues ThingChangedEvents by calling the getThingChangedEvent method for all of its ReferenceActionLinks. The ReferenceActionLink's getThingChangedEvent calls the associated ThingReferenceImpl's acknowledgeThingChanged method, which finds the appropriate ThingChangedLink and calls its acknowledgeThingChangedEvent method. If the ThingChangedLink doesn't have an event saved, it'll set its internal Ball variable to false (to indicate that the Action is no longer busy) and return null. If there's an event to return, acknowledgeThingChangedEvent returns it, leaving Ball set to false to indicate that the Action is still busy.

Doing things this way ensures that Action is called as soon as an associated Thing changes, but once it's been notified the Action isn't actively called again until it has finished handling all queued changes. This means that a Thing can be changed as frequently as necessary, but the Action only sees as many changes as necessary to model the change.

For example, some meter might be moved from a value of 1 to a value of 100 in a couple of seconds, but it might take the Action a half-second or so to deal with each change. Rather than forcing Action to deal with all the values sequentially (a process which would take 50 seconds or so), the code instead lets Action handle the first value, then skip over a bunch of intermediate values to the next current value until it reaches the final value. Rather than dealing with 100 values, Action would only need to deal with 4 or 5.

ReferenceActionLink

Just as ThingReferenceImpl tracks its associated Actions through ThingChangedLinks, so ActionImpl tracks its associated ThingReferences via a list of ReferenceActionLinks. In fact, there should be a corresponding ReferenceActionLink for every ThingChangedLink. However, ReferenceActionLink's logic is much simpler than ThingChangedLink.

As stated above, ReferenceActionLink's getThingChangedEvent basically acts as a front-end for the corresponding ThingChangedLink's acknowledgeThingChangedEvent, through the ThingReference's acknowledgeThingChanged, which finds the ThingChangedLink for the supplied Action and calls that ThingChangedLink's acknowledgeThingChangedLink method.

ReferenceActionLink also has a Ball variable, but this one keeps things in lock-step, since a getThingChangedEvent which returns a ThingChangedEvent (and thus sets ReferenceActionLink's Ball to false) must be followed by a call to the ReferenceActionLink's acknowledgeThingChangedEvent method (which sets Ball back to true) before getThingChangedEvent will return any more events.

ActionImpl

ActionImpl is the final target of all ThingChangedEvents. These are dealt with by an ActionImpl worker thread in the run method, by handing them off to the ActionImpl's thingChanged method.

The thingChanged method sends an acknowledgement back to the ReferenceActionLink (and releasing the implicit lock set by the call to the ReferenceActionLink's getThingChangedEvent It also queues up worker thread, which will eventually call the ActionImpl's doAction method, which is what this is all about.
Last modified: Tue Feb 12 16:18:05 CST 2002