/* |
|
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
package sun.java2d; |
|
/** |
|
* 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. |
|
* <p> |
|
* The suggested usage pattern for code that manages some trackable data |
|
* is as follows: |
|
* <pre> |
|
* 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); |
|
* } |
|
* } |
|
* } |
|
* </pre> |
|
* 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: |
|
* <p> |
|
* 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. |
|
* <p> |
|
* 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. |
|
* <p> |
|
* In comparison the act of setting the <code>curTracker</code> |
|
* reference to null in the usage pattern above effectively invalidates |
|
* all outstanding <code>Tracker</code> objects as soon as possible |
|
* after the change to the data and requires very little code and no |
|
* synchronization to implement. |
|
* <p> |
|
* 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. |
|
* |
|
* @since 1.7 |
|
*/ |
|
public interface StateTrackable { |
|
/** |
|
* An enumeration describing the current state of a trackable |
|
* object. |
|
* These values describe how often the complex data contained |
|
* in a trackable object can be changed and whether or not it |
|
* makes sense to try to track the data in its current state. |
|
* @see StateTrackable#getState |
|
* @since 1.7 |
|
*/ |
|
public enum State { |
|
/** |
|
* The complex data will never change again. |
|
* Information related to the current contents of the complex |
|
* data can be calculated and cached indefinitely with no |
|
* further checks to see if the information is stale. |
|
*/ |
|
IMMUTABLE, |
|
/** |
|
* The complex data is currently stable, but could change at |
|
* some point in the future. |
|
* Information related to the current contents of the complex |
|
* data can be calculated and cached, but a StateTracker should |
|
* be used to verify the freshness of such precalculated data |
|
* before each future use. |
|
*/ |
|
STABLE, |
|
/** |
|
* The complex data is currently in flux and is frequently |
|
* changing. |
|
* While information related to the current contents of the |
|
* complex data could be calculated and cached, there is a |
|
* reasonably high probability that the cached information |
|
* would be found to be out of date by the next time it is |
|
* used. |
|
* It may also be the case that the current contents are |
|
* temporarily untrackable, but that they may become trackable |
|
* again in the future. |
|
*/ |
|
DYNAMIC, |
|
/** |
|
* The complex data can currently be changed by external |
|
* references and agents in a way that cannot be tracked. |
|
* If any information about the current contents of the complex |
|
* data were to be cached, there would be no way to determine |
|
* whether or not that cached information was out of date. |
|
*/ |
|
UNTRACKABLE, |
|
}; |
|
/** |
|
* 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. |
|
* @return the current state of trackability of the complex |
|
* data stored in this object. |
|
* @see #getStateTracker |
|
* @since 1.7 |
|
*/ |
|
public State getState(); |
|
/** |
|
* 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 |
|
* {@link StateTracker#isCurrent isCurrent} method. |
|
* <ul> |
|
* <li>If the current state is {@link State#IMMUTABLE IMMUTABLE}, |
|
* this StateTracker and any future StateTracker objects |
|
* returned from this method will always indicate that |
|
* the state has not changed.</li> |
|
* <li>If the current state is {@link State#UNTRACKABLE UNTRACKABLE}, |
|
* this StateTracker and any future StateTracker objects |
|
* returned from this method will always indicate that |
|
* the state has changed.</li> |
|
* <li>If the current state is {@link State#DYNAMIC 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 {@link State#STABLE STABLE} will correctly track changes.</li> |
|
* <li>Otherwise the current state is {@link State#STABLE STABLE} |
|
* and this StateTracker will indicate whether or not the |
|
* data has changed since the time at which it was fetched |
|
* from the object.</li> |
|
* </ul> |
|
* @return an object implementing the StateTracker interface |
|
* that tracks whether changes have been made to the complex |
|
* contents of this object since it was returned. |
|
* @see State |
|
* @see #getState |
|
* @since 1.7 |
|
*/ |
|
public StateTracker getStateTracker(); |
|
} |