256 lines · 11.1 KB · Java
RawDownload
/* * 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();}