    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package javafe.reader;
    004
    005    import java.util.Hashtable;
    006
    007    import javafe.ast.CompilationUnit;
    008    import javafe.genericfile.*;
    009
    010    /**
    011     * CachedReader takes a uncached Reader and produces a cached version
    012     * of it using a simple implementation of caching via a HashTable.
    013     *
    014     * <p> Reads from GenericFiles with null canonicalIDs are not cached.
    015     */
    016
    017    public class CachedReader extends Reader
    018    {
    019        /***************************************************
    020         *                                                 *
    021         * Creation:                                       *
    022         *                                                 *
    023         **************************************************/
    024
    025        /**
    026         * The underlying Reader whose results we are caching.
    027         */
    028        //@ invariant underlyingReader != null;
    029        protected Reader underlyingReader;
    030
    031        /**
    032         * Creating a cached version of a Reader:
    033         */
    034        //@ requires reader != null;
    035        public CachedReader(Reader reader) {
    036            underlyingReader = reader;
    037
    038            //+@ set cache.keyType = \type(String);
    039            //+@ set cache.elementType = \type(Object);
    040        }
    041
    042
    043        /***************************************************
    044         *                                                 *
    045         * The Cache itself:                               *
    046         *                                                 *
    047         **************************************************/
    048
    049        /**
    050         * Our cache; maps the non-null canonicalID (if it has one) of a
    051         * GenericFile (see GenericFile.getCanonicalID) to either a
    052         * CompilationUnit or a CachedReader_Null.
    053         */
    054        //@ invariant cache != null;
    055        //+@ invariant cache.keyType == \type(String);
    056        //+@ invariant cache.elementType == \type(Object);
    057        protected Hashtable cache = new Hashtable();
    058
    059
    060        /***************************************************
    061         *                                                 *
    062         * Caching methods:                                *
    063         *                                                 *
    064         **************************************************/
    065
    066        /**
    067         * Lookup a non-null GenericFile in the cache.
    068         */
    069        //@ requires target != null;
    070        final protected Object get(GenericFile target) {
    071            String canonicalID = target.getCanonicalID();
    072            if (canonicalID==null)
    073                return null;
    074
    075            return cache.get(canonicalID);
    076        }
    077
    078
    079        /**
    080         * Store information about a non-null GenericFile in the cache;
    081         * this has no effect if the GenericFile has a null canonicalID.
    082         */
    083        //@ requires target != null;
    084        final protected void put(GenericFile target, CompilationUnit value) {
    085            String canonicalID = target.getCanonicalID();
    086            if (canonicalID==null)
    087                return;
    088
    089            if (value != null)
    090                cache.put(canonicalID, value);
    091            else
    092                cache.put(canonicalID, new CachedReader_Null());
    093        }
    094
    095
    096        /**
    097         * Is the result of read on target cached for this Reader?<p>
    098         *
    099         * Target must be non-null.<p>
    100         */
    101        //@ requires target != null;
    102        public boolean isCached(GenericFile target) {
    103            String canonicalID = target.getCanonicalID();
    104            if (canonicalID==null)
    105                return false;
    106
    107            return cache.containsKey(canonicalID);
    108        }
    109
    110        /**
    111         * Flush the saved info (if any) for target for this Reader.
    112         *
    113         * Target must be non-null.<p>
    114         */
    115        //@ requires target != null;
    116        public void flushTarget(GenericFile target) {
    117            String canonicalID = target.getCanonicalID();
    118            if (canonicalID==null)
    119                return;
    120
    121            cache.remove(canonicalID);
    122        }
    123
    124        /**
    125         * Flush all cached information for this Reader.
    126         */
    127        public void flushAll() {
    128            cache = new Hashtable();
    129
    130            //+@ set cache.keyType = \type(String);
    131            //+@ set cache.elementType = \type(Object);
    132        }
    133
    134
    135        /***************************************************
    136         *                                                 *
    137         * Reading:                                        *
    138         *                                                 *
    139         **************************************************/
    140
    141        /**
    142         * Attempt to read and parse a CompilationUnit from target.
    143         * Any errors encountered are reported via javafe.util.ErrorSet.
    144         * Null is returned iff an error was encountered.<p>
    145         *
    146         *
    147         * By default, we attempt to read only a spec (e.g., specOnly is set
    148         * in the resulting CompilationUnit) to save time.  If avoidSpec is
    149         * true, we attempt to return a non-spec, although this may not
    150         * always be possible.<p>
    151         *
    152         *
    153         * The results of this function (including null results, but not
    154         * the action of reporting error messages) are cached.
    155         * Only the value of avoidSpec used the first time a given file is
    156         * read is used.  This may result in a spec being returned
    157         * unnecessarily when avoidSpec is true.<p>
    158         *
    159         * Target must be non-null.<p>
    160         */
    161        public CompilationUnit read(GenericFile target, boolean avoidSpec) {
    162            Object result = get(target);
    163            if (result != null) {
    164                if (result instanceof CompilationUnit)
    165                    return (CompilationUnit)result;
    166                else if (result instanceof CachedReader_Null)
    167                    return null;
    168                else
    169                    javafe.util.Assert.fail("impossible");
    170            }
    171
    172            CompilationUnit newResult = underlyingReader.read(target, avoidSpec);
    173            put(target, newResult);
    174            return newResult;
    175        }
    176    }
    177
    178
    179    /**
    180     * Instances of this class are used privately by CachedReader to
    181     * represent null values in Hashtables.
    182     */
    183    /*package*/ class CachedReader_Null {
    184    }