alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code


/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.vcscore.cache;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.Reference;
import java.io.*;
import java.util.*;

/** main entry point into the cache. The class is a singleton to be found via the getInstance() static method.
 *  Stores all registered caches + makes sure the requests are processed by the right cache instance.
 *
 * 
 * @author  mkleint
 */

public class CacheHandler extends java.lang.Object {

    
    
    /** Strategy constant, to be used during Filesystem.children()
     * do just locla stuff.. no server comm, or reading disk cache   
     * 
     */
    public  static final int STRAT_LOCAL = 0;

    /** Strategy constant, to be called during FileSystem.annotateName().
     * Calls the readFromDisk() in CacheDir.
     * just local stuff + disk cache reading   
     */
    public  static final int STRAT_DISK = 3;
    
    /**  Strategy constant, do not apply any strategy. just search the current state of the cache.
     *  To be called from within the ReferenceQueue only to check if 
     *  the file is in cache without recreating it.(probably)
     */
    public  static final int STRAT_NONE = -1;

    /** 
     *  Strategy constant that causes a refresh of the file/directory.
     *  fires the checkServer() method in the FileSystemCache.
     *  For this strategy all files in the parent directory are forgotten and reloaded.
     *  
     */
    public static final int STRAT_REFRESH = 11;

    /** 
     *  Strategy constant that causes a recursive refresh of the directory.
     *  fires the checkServerRecursively() method in the FileSystemCache.
     *  For this strategy all files/dirs in the parent directory are forgotten and reloaded.
     */
    public static final int STRAT_REFRESH_RECURS = 12;
    
    /**
     * This strategy constant is to be used when accessing cache during any kind of refresh.
     * 
     */
    public static final int STRAT_REFRESHING = 10;
    
    /**
     * This strategy constant is to be used when we want to perform the refresh
     * of local files and have the directory loaded from the disk cache.
     */
    public static final int STRAT_DISK_AND_LOCAL_REFRESH = 4;
    
    /**
     * This strategy constant is to be used when we want to perform the refresh 
     * only on directories where the reading from disk fails.
     */
    public static final int STRAT_DISK_OR_REFRESH = 5;
    
    /**
     * This strategy constant is to be used when we want to perform the refresh 
     * only on directories where the reading from disk fails. Similar to
     * {@link #STRAT_DISK_OR_REFRESH}, but recursive. Directories, that do not
     * have associated disk caches should be retrieved by recursive refresh.
     */
    public static final int STRAT_DISK_OR_REFRESH_RECURS = 6;
    
    private static CacheHandler instance = null;
    
    /** Map chae type string to cache instance. */
    private Map cacheMap;

    /** In-memory cache size limit. */
    private static final int CACHE_SIZE = 403;

    /** LRU size limited in memory cache layer. */
    private final Map persistentData;
    private final ReferenceQueue cacheQueue;
    
    /** Holds cache files and direcories to permit their garbage collection only after
     * the referenced object is garbage-collected.
     * Put pairs of (reference-object, set of cache files) into this map. */
    private Map cacheFilesHolder;
    
    /** Creates new CacheHandler */
    private CacheHandler() {
        cacheMap = new Hashtable(); // to have synchronized access
        persistentData = Collections.synchronizedMap(new LRU(CACHE_SIZE)); // to have synchronized access
        cacheFilesHolder = Collections.synchronizedMap(new WeakHashMap());
        cacheQueue = org.openide.util.Utilities.activeReferenceQueue();
    }
    
    /** returns an instance of CacheHandler. Only one instance is needed throughout the IDE.
     */
    public static synchronized CacheHandler getInstance() {
        if (instance == null) {
            instance = new CacheHandler();
        }
        return instance;
    }
    
    ReferenceQueue getCacheFileReferenceQueue() {
        return cacheQueue;
    }
    
    void addReferencedData(Reference ref, CacheFile.PersistentData data) {
        persistentData.put(ref, data);
    }
    
    CacheFile.PersistentData getReferencedData(Reference ref) {
        return (CacheFile.PersistentData) persistentData.get(ref);
    }

    /** Creates a reference object. To be used in the Filesystem's createReference method to ensure
     * that the cache shrinks well.
     */
    public Reference createReference(Object obj, File file, String cacheId) {
        CacheFile cFile = getCacheFile(file, STRAT_NONE, cacheId);
        if (cFile != null) addCacheLocker(obj, cFile);
        
        //System.out.println("REFERENCE created ("+obj+", "+file+", "+cacheId+"), cache file found = "+cFile);
        //System.err.println("REFERENCE created ("+obj+", "+file+", "+cacheId+"), cache file found = "+cFile);
        CacheReference ref = new CacheReference(obj, cacheQueue);
        /*
        if (cFile != null) {
            cFile.addReference(ref);
        }
         */
        return ref;
    }
    
    /** Add a holder object for a cache directory. This will assure, that the
     * cache directory will not be released from the memory before the locker.
     * The locker must be released in order to the cache directory be released.
     * @param lock The locker object
     * @param file The cache directory
     */
    public final void addCacheLocker(Object lock, CacheFile file) {
        //System.err.println("addCacheLocker("+lock+", "+file.getName()+")");
        if (lock == null) return ;
        Set s = (Set) cacheFilesHolder.get(lock);
        if (s == null) {
            s = new HashSet();
            cacheFilesHolder.put(lock, s);
        }
        s.add(file);
        //printCacheLockers();
    }
    
    /*
    private void printCacheLockers() {
        System.out.println("\nCache LOCKERS:");
        for (Iterator it = new HashSet(cacheFilesHolder.keySet()).iterator(); it.hasNext(); ) {
            Object locker = it.next();
            System.out.print("locker = "+locker+", locked files: ");
            Set s = (Set) cacheFilesHolder.get(locker);
            for (Iterator it2 = s.iterator(); it2.hasNext(); ) {
                System.out.print(((CacheFile) it2.next()).getAbsolutePath()+", ");
            }
            System.out.println("");
        }
        System.out.println("");
    }
     */
    
    public final void removeCacheLocker(Object lock, CacheFile file) {
        Set s = (Set) cacheFilesHolder.get(lock);
        if (s != null) {
            s.remove(file);
            if (s.isEmpty()) cacheFilesHolder.remove(lock);
        }
    }

    /** The preffered way of getting files/dirs from the cache.
     * @param toFind     the file we want to get from the cache.
     * @param strategy   crutial parameter. Defines what measures should be taken by the cache
     *                   to locate the file needed.
     *                   Following strategies are defined:

* STRAT_NONE - nothing is done (currently used only in the reference queue so that the cache isn't rebuild when shrinking.

* STRAT_LOCAL - loads the file only from the local dir structure.

* STRAT_DISK - reads the file(s) that stores the content of cache previously written to disk.

* STRAT_REFRESH - checks the server for new states.

* STRAT_REFRESH_RECURS - for directories performs recursive refresh. * * @param cacheFs the calling filesystem (interface CacheFileSystem) that provides the cacheID string in order to find the cache instance in the registry *

For STRAT_REFRESH, STRAT_REFRESH_RECURS and STRAT_REFRESHING or higher, * the disk cache is not consulted (REFRESH/R_R also does clear the cache and relaods) * */ public CacheFile getCacheFile(File toFind, int strategy, CachedFileSystem cacheFs) { return getCacheFile(toFind, strategy, cacheFs.getCacheId()); } /** Way of getting files/dirs from the cache. For details see... * */ public CacheFile getCacheFile(File toFind, int strategy, String type) { return getCacheFile(toFind, strategy, type, null); } /** Way of getting files/dirs from the cache. For details see... * * @param locker The locker for cache files and directories. An object, that is used to * prevent the obtained filea and directories from being garbage-collected. * The cache objects are kept in memory until the locker * object is kept in the memory. */ public CacheFile getCacheFile(File toFind, int strategy, String type, Object locker) { FileSystemCache cache = getCache(type); if (cache == null) { return null; } return cache.getCacheFile(toFind, strategy, locker); } /** adds a new cache to the registry. To be called when the filesystem gets created/upon restarting the IDE. * @param type IDString that identifies the cache. (the cacheID can be 1 for a single filesystem or for all filesystems of one kind. */ public void registerCacheType(String type, FileSystemCache cacheObject) { cacheMap.put(type, cacheObject); } /** Opposite action to registerCache. Do when unmounting filesystem that has it's own cache. */ public void unregistedType(String type) { cacheMap.remove(type); } /** * utility method for grabbing the right cache for the specified ID. * Not to be used for file retrieval tasks. */ public FileSystemCache getCache(CachedFileSystem type) { FileSystemCache cache = (FileSystemCache)cacheMap.get(type.getCacheId()); return cache; } /** utility method for grabbing the right cache for the specified ID. * Not to be used for file retrieval tasks. */ public FileSystemCache getCache(String type) { FileSystemCache cache = (FileSystemCache)cacheMap.get(type); return cache; } public void uninstall() { if (cacheMap != null) { Iterator it = cacheMap.values().iterator(); while (it.hasNext()) { FileSystemCache cch = (FileSystemCache)it.next(); cch.removeAllListeners(); } cacheMap.clear(); cacheMap = null; } instance = null; } /** Limited size LRU map implementation. */ private static class LRU extends LinkedHashMap { private final int maxSize; public LRU(int maxSize) { super(maxSize *2, 0.5f, true); this.maxSize = maxSize; } protected boolean removeEldestEntry(Map.Entry eldest) { return size() > maxSize; } } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.