public interface

StateTrackable

sun.java2d.StateTrackable
Known Indirect Subclasses

Class Overview

This interface is implemented by classes which contain complex state so that other objects can track whether or not their state has changed since earlier interactions with the object.

The suggested usage pattern for code that manages some trackable data is as follows:

 class Trackable implements StateTrackable {
     TrackedInfo data;
     State curState = STABLE;
     StateTracker curTracker = null;
     // Hypothetical method to return a static piece of our tracked data.
     // Assume that Datum is either a copy of some piece of the tracked
     // data or that it is itself immutable.
     public Datum getSomeDatum(int key) {
         // No need to modify the state for this type of "get" call.
         return data.getDatum(key);
     }
     // Hypothetical method to return a raw reference to our tracked data.
     public TrackedInfo getRawHandleToInfo() {
         // Since we are returning a raw reference to our tracked
         // data and since we can not track what the caller will
         // do with that reference, we can no longer track the
         // state of this data.
         synchronized (this) {
             // Note: modifying both curState and curTracker requires
             // synchronization against the getStateTracker method.
             curState = UNTRACKABLE;
             curTracker = null;
         }
         return data;
     }
     // Hypothetical method to set a single piece of data to some
     // new static value.
     public void setSomeDatum(int key, Datum datum) {
         data.setDatum(key, datum);
         // We do not need to change state for this, we simply
         // invalidate the outstanding StateTracker objects.
         // Note: setting curTracker to null requires no synchronization.
         curTracker = null;
     }
     // getStateTracker must be synchronized against any code that
     // changes the State.
     public synchronized StateTracker getStateTracker() {
         StateTracker st = curTracker;
         if (st == null) {
             switch (curState) {
                 case IMMUTABLE:   st = StateTracker.ALWAYS_CURRENT; break;
                 case STABLE:      st = new Tracker(this); break;
                 case DYNAMIC:     st = StateTracker.NEVER_CURRENT; break;
                 case UNTRACKABLE: st = StateTracker.NEVER_CURRENT; break;
             }
             curTracker = st;
         }
         return st;
     }

     static class Tracker implements StateTracker {
         Trackable theTrackable;
         public Tracker(Trackable t) {
             theTrackable = t;
         }
         public boolean isCurrent() {
             return (theTrackable.curTracker == this);
         }
     }
 }
 
Note that the mechanism shown above for invalidating outstanding StateTracker objects is not the most theoretically conservative way to implement state tracking in a "set" method. There is a small window of opportunity after the data has changed before the outstanding StateTracker objects are invalidated and where they will indicate that the data is still the same as when they were instantiated. While this is technically inaccurate, it is acceptable since the more conservative approaches to state management are much more complex and cost much more in terms of performance for a very small gain in correctness. For example:

The most conservative approach would be to synchronize all accesses and all modifications to the data, including its State. This would require synchronized blocks around some potentially large bodies of code which would impact the multi-threaded scalability of the implementation. Further, if data is to be coordinated or transferred between two trackable objects then both would need to be synchronized raising the possibility of deadlock unless some strict rules of priority for the locking of the objects were established and followed religiously. Either or both of these drawbacks makes such an implementation infeasible.

A less conservative approach would be to change the state of the trackable object to DYNAMIC during all modifications of the data and then to change it back to STABLE after those modifications are complete. While this state transition more accurately reflects the temporary loss of tracking during the modification phase, in reality the time period of the modifications would be small in most cases and the 2 changes of state would each require synchronization.

In comparison the act of setting the curTracker reference to null in the usage pattern above effectively invalidates all outstanding Tracker objects as soon as possible after the change to the data and requires very little code and no synchronization to implement.

In the end it is up to the implementor of a StateTrackable object how fine the granularity of State updates should be managed based on the frequency and atomicity of the modifications and the consequences of returning an inaccurate State for a particularly small window of opportunity. Most implementations are likely to follow the liberal, but efficient guidelines found in the usage pattern proposed above.

Summary

Nested Classes
enum StateTrackable.State An enumeration describing the current state of a trackable object. 
Public Methods
abstract StateTrackable.State getState()
Returns the general state of the complex data held by this object.
abstract StateTracker getStateTracker()
Returns an object which can track future changes to the complex data stored in this object.

Public Methods

public abstract StateTrackable.State getState ()

Returns the general state of the complex data held by this object. This return value can be used to determine if it makes strategic sense to try and cache information about the current contents of this object. The StateTracker returned from the getStateTracker() method will further aid in determining when the data has been changed so that the caches can be verified upon future uses.

Returns
  • the current state of trackability of the complex data stored in this object.

public abstract StateTracker getStateTracker ()

Returns an object which can track future changes to the complex data stored in this object. If an external agent caches information about the complex data of this object, it should first get a StateTracker object from this method so that it can check if such information is current upon future uses. Note that a valid StateTracker will always be returned regardless of the return value of getState(), but in some cases the StateTracker may be a trivial implementation which always returns the same value from its isCurrent method.

  • If the current state is IMMUTABLE, this StateTracker and any future StateTracker objects returned from this method will always indicate that the state has not changed.
  • If the current state is UNTRACKABLE, this StateTracker and any future StateTracker objects returned from this method will always indicate that the state has changed.
  • If the current state is DYNAMIC, this StateTracker may always indicate that the current state has changed, but another StateTracker returned from this method in the future when the state has changed to STABLE will correctly track changes.
  • Otherwise the current state is STABLE and this StateTracker will indicate whether or not the data has changed since the time at which it was fetched from the object.

Returns
  • an object implementing the StateTracker interface that tracks whether changes have been made to the complex contents of this object since it was returned.