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.caching;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.io.File;
import java.io.FilenameFilter;
import java.util.*;

import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.RequestProcessor;
import org.openide.util.WeakSet;
import org.openide.ErrorManager;

import org.netbeans.api.vcs.VcsManager;
import org.netbeans.api.vcs.commands.Command;
import org.netbeans.api.vcs.commands.CommandTask;

import org.netbeans.spi.vcs.commands.CommandSupport;

import org.netbeans.modules.vcscore.cache.*;
import org.netbeans.modules.vcscore.util.VcsUtilities;
import org.netbeans.modules.vcscore.VcsFactory;
import org.netbeans.modules.vcscore.DirReaderListener;
import org.netbeans.modules.vcscore.FileReaderListener;
import org.netbeans.modules.vcscore.VcsDirContainer;
import org.netbeans.modules.vcscore.VcsFileSystem;
import org.netbeans.modules.vcscore.commands.VcsCommand;//Executor;
import org.netbeans.modules.vcscore.commands.VcsDescribedCommand;

/**
 *
 * @author  Martin Entlicher
 */
public final class VcsCache extends FileSystemCache implements FileReaderListener {
    
    //public static final String VCS_CACHE_NAME = "VCS_Cache";
    
    private Reference fileSystem;
    private String fsRoot;
    private int rootNameLength;
    /** No file above this path key is cached. */
    private String normalizedRootKey;
    private int normalizedRootKeyLength;

    /** Staistics for limited in-memory cache. */
    private static long cacheHits = 0;

    /** Staistics for limited in-memory cache. */
    private static long cacheRequests = 0;

    /** A hashtable of cache files, identified by full path.
     * Key: full path (string)  for Files File.getAbsolutePath()
     *                          for VcsCacheDirs VcsCacheDir.getAbsolutePath()
     * Value: a weak reference to instance of VcsCacheDir
     * 

* FS root typically does not contain a /CVS folder, * in which the disk cache is stored. If it does not exist * it caches nothing. Therefore roots must be held in memory. * @see #getCacheFileName(File) */ private Map permanentCache = Collections.synchronizedMap(new HashMap(5)); /** * The map of paths, which should be refreshed after they become non-local * with their strategies. */ private HashMap refreshStrategyWhenNonLocal; /** * The map of directories, that are scheduled for later refresh (those which * are being loaded and should be refreshed after the loading is finished). * The values are arrays of two objects: Boolean (whether to refresh recursively) * and Object (locker). */ private Map directoriesScheduledForRefresh; private static RequestProcessor refreshRequestProcessor = new RequestProcessor("Refresh Requests Processor"); /** Creates new VcsCache with default name VCS_CACHE_NAME * public VcsCache(Reference fileSystem) { this(fileSystem, VCS_CACHE_NAME); } */ /** Creates new VcsCache of a custom name * @param cacheName the cache name. */ public VcsCache(Reference fileSystem, String cacheName) { super(cacheName); //System.out.println("NEW VcsCache("+fileSystem+", "+cacheName+")"); this.fileSystem = fileSystem; updateFSRoot(); VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); fsystem.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { updateFSRoot(); } }); refreshStrategyWhenNonLocal = new HashMap(); directoriesScheduledForRefresh = new HashMap(); } /* void setFSRoot(File fsRoot) { this.fsRoot = fsRoot; } File getFSRoot() { return fsRoot; } */ private void updateFSRoot() { //System.out.println("VcsCache.updateFSRoot()"); VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); fsRoot = fsystem.getRootDirectory().getAbsolutePath(); // filesystem has to exist during construction normalizedRootKey = pathToKey(fsRoot); normalizedRootKeyLength = normalizedRootKey.length(); rootNameLength = fsRoot.length(); } /** * Get the path from the root of the filesystem for the given file. */ String getPath(File file) { String filePath = file.getAbsolutePath(); //System.out.println("VcsCache.getPath("+filePath+"), rootNameLength = "+rootNameLength); if (filePath.length() <= rootNameLength) return ""; // NOI18N String path; if (filePath.charAt(rootNameLength) == '/' || filePath.charAt(rootNameLength) == File.separatorChar) { path = filePath.substring(rootNameLength + 1); // skip the path separator also } else { path = filePath.substring(rootNameLength); } path = path.replace(File.separatorChar, '/'); //System.out.println(" -> path = "+path); return path; } String getAbsolutePath(File file) { return file.getAbsolutePath();//.replace(File.separatorChar, '/'); } private VcsFactory getFactory() { VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); if (fsystem == null) return null; return fsystem.getVcsFactory(); } /** Run the directory reader on the directory * @param dir the absolute path to the directory */ void runVcsDirReader(VcsCacheDir cacheDir, Object locker) { VcsFileSystem fsystem; //String path; synchronized (this) { fsystem = (VcsFileSystem) fileSystem.get(); if (fsystem == null) return ; //System.out.println("runVcsDirReader("+dir+"), absolutePath = "+getAbsolutePath(dir)+", cahceDir = "+cacheDir); //System.out.println("runVcsDirReader: cacheDir = "+cacheDir+", isBeingLoaded = "+cacheDir.isBeingLoaded()+", isLoaded = "+cacheDir.isLoaded()); if (cacheDir.isBeingLoaded()) return ; cacheDir.setBeingLoaded(true); //path = getPath(dir); } final CommandSupport list; if (fsystem.isOffLine()) { list = fsystem.getCommandSupport(VcsCommand.NAME_REFRESH + VcsCommand.NAME_SUFFIX_OFFLINE); } else { list = fsystem.getCommandSupport(VcsCommand.NAME_REFRESH); } if (list != null) { refreshRequestProcessor.post(new RefreshProcessStarter(list, cacheDir.getFile(), locker)); } else { synchronized (this) { cacheDir.setBeingLoaded(false); } } /* VcsFactory factory = fsystem.getVcsFactory(); VcsCommandExecutor exec = factory.getVcsDirReader(new VcsCache.DirReaderListenerWithLock(locker), path); if (exec != null) fsystem.getCommandsPool().startExecutor(exec, fsystem); */ } /** Run the recursive directory reader on the directory * @param dir the absolute path to the directory */ synchronized void runVcsDirReaderRecursive(VcsCacheDir cacheDir, Object locker) { VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); if (fsystem == null) return ; CommandSupport list; if (fsystem.isOffLine()) { list = fsystem.getCommandSupport(VcsCommand.NAME_REFRESH_RECURSIVELY + VcsCommand.NAME_SUFFIX_OFFLINE); } else { list = fsystem.getCommandSupport(VcsCommand.NAME_REFRESH_RECURSIVELY); } if (list != null) { refreshRequestProcessor.post(new RefreshProcessStarter(list, cacheDir.getFile(), locker)); } /* VcsFactory factory = fsystem.getVcsFactory(); VcsCommandExecutor exec = factory.getVcsDirReaderRecursive(new VcsCache.DirReaderListenerWithLock(locker), getPath(dir)); if (exec != null) fsystem.getCommandsPool().startExecutor(exec, fsystem); */ } /** * @return null if cannot be stored to disk */ String getCacheFileName(File dir) { VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); if (fsystem == null) return null; return fsystem.getCacheFileName(getPath(dir)); } String getLocalFileStatus() { VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); if (fsystem == null) return ""; // NOI18N FileStatusProvider statusProvider = fsystem.getStatusProvider(); if (statusProvider == null) return ""; // NOI18N return statusProvider.getLocalFileStatus(); } public void writeAllToDisk() { } protected void loadDir(CacheDir dir, int strategy, Object locker) { //System.out.println("dir = " + dir + " strategy=" + strategy); if (strategy == CacheHandler.STRAT_REFRESH || strategy == CacheHandler.STRAT_REFRESH_RECURS) { ((VcsCacheDir) dir).refreshLocal(strategy == CacheHandler.STRAT_REFRESH_RECURS); //dir.setComplete(true); if (!dir.isLocal()) { if (doesStrategyApply(dir, strategy, CacheHandler.STRAT_REFRESH)) { //System.out.println(" checking the server."); dir.checkServer(locker); //dir.setComplete(true); } if (doesStrategyApply(dir, strategy, CacheHandler.STRAT_REFRESHING)) { //dir.setComplete(true); dir.setAppliedLevel(CacheHandler.STRAT_REFRESHING); } if (doesStrategyApply(dir, strategy, CacheHandler.STRAT_REFRESH_RECURS)) { dir.checkServerRecursive(locker); //dir.setComplete(true); } } } else { super.loadDir(dir, strategy, locker); } if (dir.isLocal()) { if (doesStrategyApply(dir, strategy, CacheHandler.STRAT_REFRESH) || doesStrategyApply(dir, strategy, CacheHandler.STRAT_DISK)) { refreshStrategyWhenNonLocal.put(dir.getAbsolutePath(), new Integer(strategy)); refreshParentIfNecessary(dir, strategy); } } else { CacheDir[] subdirs = dir.getSubDirs(); for (int i = 0; i < subdirs.length; i++) { if (subdirs[i].isLocal()) continue; Integer refresh = (Integer) refreshStrategyWhenNonLocal.remove(subdirs[i].getAbsolutePath()); if (refresh != null) { loadDir(subdirs[i], refresh.intValue(), null); } } } } private void refreshParentIfNecessary(CacheDir dir, int strategy) { //System.out.println("refreshParentIfNecessary("+dir.getAbsolutePath()+", "+strategy+")"); CacheDir parent = dir.getParent(); if (parent != null) { Integer refresh = (Integer) refreshStrategyWhenNonLocal.get(parent.getAbsolutePath()); if (refresh != null) { refreshParentIfNecessary(parent, strategy); } else { if (!((VcsCacheDir) parent).isBeingLoaded()) { //System.out.println("REFRESHING NECESSARY PARENT: "+parent); loadDir(parent, strategy, null); } } } } public CacheFile getCacheFile(File toFind, int strategy, Object locker) { //boolean print = toFind.getAbsolutePath().endsWith("/A") || toFind.getAbsolutePath().endsWith("/B") || toFind.getAbsolutePath().indexOf("/A/") > 0 || toFind.getAbsolutePath().indexOf("/B/") > 0; //if (print) System.out.println("getCacheFile:" + toFind.toString() + " Strategy=" + strategy); //System.out.println("getCacheFile:" + toFind.toString() + " Strategy=" + strategy); VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); if (fsystem == null) return null; //System.out.println(toFind+".compareTo FS root ("+fsystem.getRootDirectory()+") = "+fsystem.getRootDirectory().compareTo(toFind)); String parentDir; boolean findThis = false; if (fsystem.getRootDirectory().equals(toFind) || toFind.getParentFile() == null) { parentDir = toFind.getAbsolutePath(); toFind = fsystem.getRootDirectory(); findThis = true; } else { parentDir = toFind.getParentFile().getAbsolutePath(); } CacheDir cacheDir = getDir(parentDir); //if (print) System.out.println(" parentDir = "+parentDir+" => cacheDir = "+cacheDir); if (cacheDir == null) { boolean[] grandParentExists = { false }; cacheDir = lookupCacheDir(new File(parentDir), grandParentExists); if (!grandParentExists[0]) { //System.out.println("DIDN'T find a parent dir '"+parentDir+"'! Initializing a new one..."); cacheDir = initCacheDir(new File(parentDir)); // We must keep the roots permanentCache.put(parentDir, new HardReference(cacheDir)); } //cacheDir = new VcsCacheDir(getId(), toFind.getParentFile()); //cacheDir.setParent(null); //registerDir(cacheDir); //if (cacheDir == null) System.out.println(" return null !!!"); if (cacheDir == null) return null; } if (strategy == CacheHandler.STRAT_DISK_AND_LOCAL_REFRESH) { int level = cacheDir.getAppliedLevel(); if (level >= CacheHandler.STRAT_DISK) { cacheDir.populateWithLocal(locker); cacheDir.setAppliedLevel(level); } strategy = CacheHandler.STRAT_DISK; } //System.out.println(" dir "+cacheDir+", isLoaded = "+((VcsCacheDir) cacheDir).isLoaded()+" applied level = "+cacheDir.getAppliedLevel()); if ((strategy == CacheHandler.STRAT_DISK_OR_REFRESH || strategy == CacheHandler.STRAT_DISK || strategy == CacheHandler.STRAT_NONE) && // when we're looking for "disk or refresh" level or "none" level cacheDir.getAppliedLevel() >= CacheHandler.STRAT_DISK// && // it's enough when the directory passed disk level already /*cacheDir.isComplete()*/) { // I have the directory loaded } else { //if (!cacheDir.isComplete() || !((VcsCacheDir) cacheDir).isLoaded()) { //System.out.println(" LOADING !!!!"); loadDir(cacheDir, strategy, locker); } //if (cacheDir == null) return null; //if (findThis) System.out.println(" return "+cacheDir.getAbsolutePath()); if (findThis) return cacheDir; String name = toFind.getName(); CacheFile file = cacheDir.getFile(name); //if (file != null) System.out.println(" return "+file); if (file != null) return file; CacheDir dir = cacheDir.getSubDir(name); /*if (dir != null) { System.out.println(" return "+dir.getAbsolutePath()); } else { System.out.println(" return null !!"); }*/ return dir; } public void doRefreshDir(CacheDir dir, boolean recursively) { doRefreshDir(dir, recursively, null); } public void doRefreshDir(CacheDir dir, boolean recursively, Object locker) { int strategy = recursively ? CacheHandler.STRAT_REFRESH_RECURS : CacheHandler.STRAT_REFRESH; if (dir instanceof VcsCacheDir) { VcsCacheDir vdir = (VcsCacheDir) dir; if (vdir.isBeingLoaded()) { // Someone is already refreshing this directory. // We need to schedule the refresh after this directory is loaded: synchronized (directoriesScheduledForRefresh) { Object[] params = (Object[]) directoriesScheduledForRefresh.get(vdir); if (params != null) { if (recursively && !((Boolean) params[0]).booleanValue()) { params[0] = Boolean.TRUE; } } else { params = new Object[] { ((recursively) ? Boolean.TRUE : Boolean.FALSE), locker }; directoriesScheduledForRefresh.put(vdir, params); } } } else { vdir.setLoaded(false); // to force the reload loadDir(dir, strategy, locker); } } else { loadDir(dir, strategy, locker); } } private void runScheduledRefresh(CacheDir dir) { Object[] params; synchronized (directoriesScheduledForRefresh) { params = (Object[]) directoriesScheduledForRefresh.remove(dir); } if (params != null) { doRefreshDir(dir, ((Boolean) params[0]).booleanValue(), params[1]); } } /* public CacheDir getCacheDir(File toFind, int strategy) { String parentDir = toFind.getParentFile().getAbsolutePath(); CacheDir cacheDir = getDir(parentDir); if (cacheDir == null) { //it doesn't have a parent -> is some kind of root. cacheDir = initCacheDir(toFind); loadDir(cacheDir, strategy); return cacheDir; } loadDir(cacheDir, strategy); if (cacheDir == null) return null; return cacheDir.getSubDir(toFind.getName()); } */ /** * Lookup for the cache dir in it's parents, do not make any changes to the * cache directory structure.. * This is necessary for the cache directories consistence. * @param file The file to find the cache dir for * @param grandParentExists A "pointer" to a single boolean value, which is * set to true if some grand parent exists. * @deprecated try to use faster {@link #seekCacheDir} */ private CacheDir lookupCacheDir(File file, boolean[] grandParentExists) { File parent = file.getParentFile(); //System.err.println("lookupCacheDir("+file+"), parent = "+parent); if (parent == null) return null; CacheDir parentDir = getDir(parent.getAbsolutePath()); //System.err.println("getDir("+parent.getAbsolutePath()+") = "+parentDir); if (parentDir == null) parentDir = lookupCacheDir(parent, grandParentExists); CacheDir dir = null; if (parentDir != null) { grandParentExists[0] = true; dir = parentDir.getSubDir(file.getName()); } return dir; } /** * Lookup for the cache dir in it's parents, do not make any changes to the * cache directory structure.. * This is necessary for the cache directories consistence. * @param path The normalized path to find the cache dir for * @param grandParentExists A "pointer" to a single boolean value, which is * set to true if some grand parent exists. */ private CacheDir seekCacheDir(String path, boolean[] grandParentExists) { //System.err.println("seekCacheDir("+path+")"); //assert normalizedRootKey.length() < path.length() : "ROOT " + normalizedRootKey + " cannot cover path " + path; // if (path.getParentFile() == null) retrun null; : if (normalizedRootKeyLength > path.length() || normalizedRootKey.equals(path)) { // we are at root return null; } String parentPath = path.substring(0, path.lastIndexOf(File.separatorChar)); CacheDir parentDir = getDir(parentPath); //System.err.println("getDir("+parentPath+") = "+parentDir); if (parentDir == null) parentDir = seekCacheDir(parentPath, grandParentExists); CacheDir dir = null; if (parentDir != null) { grandParentExists[0] = true; String fileName = path.substring(path.lastIndexOf(File.separatorChar) + 1); dir = parentDir.getSubDir(fileName); } return dir; } /** * Lookup for the cache dir in it's parents and create the necessary * intermediate files. * This is necessary for the cache directories consistence. * @param local Set the newly created directory as local or not. */ CacheDir lookupCacheDir(File file, boolean local) { File parent = file.getParentFile(); //System.err.println("lookupCacheDir("+file+"), parent = "+parent); if (parent == null) return null; CacheDir parentDir = getDir(parent.getAbsolutePath()); //System.err.println("getDir("+parent.getAbsolutePath()+") = "+parentDir); if (parentDir == null) parentDir = lookupCacheDir(parent, local); if (parentDir != null) { //System.err.println("lookupCacheDir: RETURN dir name = "+file.getName()+" of "+parentDir+"\n => "+parentDir.getSubDir(file.getName())); CacheDir dir = parentDir.getSubDir(file.getName()); if (dir == null) { dir = new VcsCacheDir(getId(), file); parentDir.addChildDir(dir, false); // I have to suppose, that the initial directory is not local, // otherwise no refresh would be performed on it. dir.setLocal(local); if (local) { dir.setStatus(getLocalFileStatus()); } else { ((VcsCacheDir) dir).readChildNamesFromDisk(); } //((VcsCacheFile.VcsPersistentData) dir.getPersistentData()).setModified(true); // To save it later - done by setParent() } registerDir(dir); //System.err.println("lookupCacheDir: RETURN dir = "+dir); return dir; } else { return null; } } private CacheDir initCacheDir(File toInit) { //System.out.println("initCacheDir("+toInit+")"); File parentFile = toInit.getParentFile(); CacheDir parentDir = null; if (parentFile != null) { parentDir = getDir(parentFile.getAbsolutePath()); } CacheDir initDir = null; if (parentDir == null && parentFile != null) { parentDir = lookupCacheDir(parentFile, false); } if (parentDir == null) { //System.out.println("initCacheDir ("+toInit+") without parent."); // the current dir will be prolly a root directory of sorts.. VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); if (fsystem == null) return null; VcsFactory factory = fsystem.getVcsFactory(); initDir = new VcsCacheDir(getId(), toInit); // I have to suppose, that the initial directory is not local, // otherwise no refresh would be performed on it. initDir.setLocal(false); ((VcsCacheFile.VcsPersistentData) initDir.getPersistentData()).setModified(true); // To save it later } else { // now let's see in the disc cache first.. parent has to have the curr. dir in the children list //System.out.println("initCacheDir has parent = "+parentDir.getName()); initDir = parentDir.getSubDir(toInit.getName()); if (initDir == null) { //System.out.println("initCacheDir ("+toInit+") parent does not contain me!"); initDir = new VcsCacheDir(getId(), toInit); parentDir.addChildDir(initDir, false); // I have to suppose, that the initial directory is not local, // otherwise no refresh would be performed on it. initDir.setLocal(false); //((VcsCacheFile.VcsPersistentData) initDir.getPersistentData()).setModified(true); // To save it later -- done by setParent() } } registerDir(initDir); //System.out.println("initCacheDir: initDir = "+initDir); return initDir; } //public boolean isCacheFile(File toFind) { //} /** Adds entry into size limited in-memory cache. */ public void registerDir(CacheDir dir) { if (dir != null) { String fullName = pathToKey(dir.getAbsolutePath()); File f = new File(fullName); if (getCacheFileName(f) == null) { // put into pernament cache permanentCache.put(fullName, new HardReference(dir)); } } } public void registerDirRecursive(CacheDir dir) { registerDir(dir); CacheDir[] dirs = dir.getSubDirs(); for (int i = 0; i < dirs.length; i++) { registerDirRecursive(dirs[i]); } } public void unregisterDir(CacheDir dir) { if (dir != null) { String fullName = pathToKey(dir.getAbsolutePath()); //System.err.println("VcsCache.unregisterDir("+fullName+")"); permanentCache.remove(fullName); CacheDir[] subDirs = dir.getSubDirs(); for (int i = 0; i < subDirs.length; i++) { unregisterDir(subDirs[i]); } } } private static final String SEPARATOR_DUPLICITY = File.separator + File.separator; /** Removes unnecasary File.separator duplicities in path making it 'canonical' :-). */ private static String pathToKey(String path) { while (path.endsWith(File.separator)) { path = path.substring(0, path.length() - 1); } int index; while((index = path.indexOf(SEPARATOR_DUPLICITY)) > 0) { path = path.substring(0, index) + path.substring(index + 1, path.length()); } return path; } /** * Get the cache directory * @param fullName the absolute path to the folder you want to obtain the cache for */ public CacheDir getDir(String fullName) { fullName = pathToKey(fullName); // XXX it's nightmare to observe requests here, you can see a lot of nonsense requests if ((cacheRequests % 1000) == 0) { if (cacheRequests != 0) { double percent = (((double)cacheHits)/(double)cacheRequests)*100; String msg = "VcsCache in-memory cache has " + percent + " % hits. Recent request " + fullName; // NOI18N ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, msg); } } // consult pernament cache CacheDir ret = null; Reference retRef = (Reference) permanentCache.get(fullName); if (retRef != null) { ret = (CacheDir) retRef.get(); if (ret != null) { return ret; } } cacheRequests++; boolean[] grandParentExists = { false }; CacheDir cacheDir = seekCacheDir(fullName, grandParentExists); return cacheDir; } /** Statistics of whole caching system. */ public static long getCacheHits() { return cacheHits; } /** Statistics of whole caching system. */ public static long getCacheRequests() { return cacheRequests; } /** * To be called when any change on directory occures that results in diferent appearence. */ private void heyDoRefreshDir(String path) { //System.out.println("heyDoRefreshDir("+path+")"); VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); if (fsystem != null) { org.openide.filesystems.FileObject fo = fsystem.findExistingResource(path); if (fo != null) { //System.out.println("heyDoRefreshDir("+path+") REFRESH CALLED."); fo.refresh(); // Also check the existing data in this folder for external modification. fsystem.checkForModifications(fo.getPath(), false, true, false); } } } /** * To be called when any change on directory occures that results in diferent appearence. */ private void heyDoRefreshDirRecursive(VcsCacheDir dir) { heyDoRefreshDir(getPath(dir.getFile())); CacheDir[] subdirs = dir.getSubDirs(); for(int i = 0; i < subdirs.length; i++) { //CacheDir subdir = subdirs[i]; //if (subdir != null) { heyDoRefreshDirRecursive((VcsCacheDir) subdirs[i]); //} } } private ArrayList getNonLocalSubfiles(VcsCacheDir dir) { String[] mySubFiles = dir.getFilesAndSubdirs(); ArrayList lastNonLocal = new ArrayList(Arrays.asList(mySubFiles)); for (int i = 0; i < lastNonLocal.size(); i++) { String fileName = (String) lastNonLocal.get(i); CacheFile file = dir.getFile(fileName); if (file instanceof VcsCacheFile) { if (((VcsCacheFile) file).isLocal()) lastNonLocal.remove(i--); } else if (file instanceof VcsCacheDir) { if (((VcsCacheDir) file).isLocal()) lastNonLocal.remove(i--); } CacheDir subDir = dir.getSubDir(fileName); if (subDir instanceof VcsCacheDir) { if (((VcsCacheDir) subDir).isLocal()) lastNonLocal.remove(i--); } } return lastNonLocal; } /** @param path the path relative to the fs root */ private VcsCacheDir createSubFiles(VcsFileSystem fs, String path, Collection rawData, Object locker) { // Cache provider has to be != null, otherwise I would not get here //System.out.println("createSubFiles("+path+", "+rawData+")"); VcsCacheDir dir = (VcsCacheDir) fs.getCacheProvider().getDir(path); //System.out.println("dir = "+dir+", path = "+((dir != null) ? ""+dir.getFile() : "null")); if (dir == null) { dir = createAndRefreshReadFolders(fs.getFile(path)); if (dir == null) { dir = (VcsCacheDir) initCacheDir(fs.getFile(path)); } } //CacheDir[] subDirs = dir.getSubDirs(); //String[] subDirPaths = new String[subDirs.length]; //ArrayList knownSubDirPaths = new ArrayList(); //for(int i = 0; i < subDirs.length; i++) knownSubDirPaths.add(subDirs[i].getAbsolutePath()); CacheHandler handler = CacheHandler.getInstance(); ArrayList lastNonLocal = getNonLocalSubfiles(dir); for (Iterator it = rawData.iterator(); it.hasNext(); ) { String[] elements = (String[]) it.next(); String elemName = StatusFormat.getFileName(elements); // Adjust the element name in case we have it as a directory // This is necessary for Subversion, because "svn status" does not // appent directory names with a slash. if (elemName != null && !elemName.endsWith("/") && dir.getSubDir(elemName) != null) { elements[StatusFormat.ELEMENT_INDEX_FILE_NAME] += "/"; } CacheFile file = RefreshCommandSupport.matchToFile(elements, fs.getCacheIdStr(), dir.getFile()); handler.addCacheLocker(locker, file); String fileName = file.getName(); if (file instanceof VcsCacheFile) { ((VcsCacheFile) file).setLocal(false); if (lastNonLocal.contains(fileName)) { dir.removeFile(fileName, false); dir.addFile(file, false); lastNonLocal.remove(fileName); } else { dir.addFile(file, true); } } else if (file instanceof VcsCacheDir) { VcsCacheDir sDir = (VcsCacheDir) file; sDir.setLocal(false); if (lastNonLocal.contains(fileName)) { // Has no sense to remove & add the same dir. We'll change the status only later. //dir.removeChildDir(fileName, false); //dir.addChildDir(sDir, false); lastNonLocal.remove(fileName); } else { dir.addChildDir(sDir, true); } if (sDir != dir.getSubDir(fileName)) { // There was already this dir in the cache VcsCacheDir origDir = (VcsCacheDir) dir.getSubDir(fileName); origDir.setStatus(sDir.getStatus()); origDir.setSticky(sDir.getSticky()); origDir.setLocker(sDir.getLocker()); origDir.setRevision(sDir.getRevision()); origDir.setSize(sDir.getSize()); origDir.setDate(sDir.getDate()); origDir.setTime(sDir.getTime()); origDir.setAttr(sDir.getAttr()); origDir.setLocal(false); handler.removeCacheLocker(locker, sDir); sDir = origDir; handler.addCacheLocker(locker, sDir); } Integer refresh = (Integer) refreshStrategyWhenNonLocal.remove(sDir.getAbsolutePath()); if (refresh != null) { loadDir(sDir, refresh.intValue(), null); } } //System.out.println("createSubFiles("+path+"): I've got file = "+file+"\nfile path = "+file.getAbsolutePath()); //System.out.println("elements = "+VcsUtilities.arrayToString(elements)+" => file = "+file); //if (file instanceof CacheDir) { // registerDir((CacheDir) file); -- done in addChildDir() //knownSubDirPaths.remove(file.getAbsolutePath()); //} } /* for(Iterator it = knownSubDirPaths.iterator(); it.hasNext(); ) { String subPath = (String) it.next(); dir.removeChildDir(VcsUtilities.getFileNamePart(subPath), true); } */ if (lastNonLocal.size() > 0) { for (int i = lastNonLocal.size() - 1; i >= 0; i--) { String fileName = (String) lastNonLocal.get(i); CacheFile file = dir.getFile(fileName); if (file != null) { dir.removeFile(fileName, true); } else { CacheDir subDir = dir.getSubDir(fileName); if (subDir != null) { dir.removeChildDir(fileName, true); } } } dir.refreshLocal(false); // Some !local files might change to local } //System.out.println("VcsCache.createDir("+path+"): dir = "+dir); dir.setLoaded(true); //System.out.println("createSubFiles("+path+") = "+dir); return dir; } private VcsCacheDir createSubFiles(VcsFileSystem fs, VcsDirContainer filesByName, Object locker) { Hashtable fileElements = (Hashtable) filesByName.getElement(); Collection rawData; if (fileElements == null) rawData = Collections.EMPTY_LIST; else rawData = fileElements.values(); CacheHandler handler = CacheHandler.getInstance(); VcsCacheDir dir = createSubFiles(fs, filesByName.getPath(), rawData, locker); handler.addCacheLocker(locker, dir); VcsDirContainer[] subfilesByName = filesByName.getSubdirContainers(); for(int i = 0; i < subfilesByName.length; i++) { //VcsDirContainer subfilesByName = filesByName.getSubdir(subdirs[i]); VcsCacheDir subDir; dir.addChildDir(subDir = createSubFiles(fs, subfilesByName[i], locker), true); handler.addCacheLocker(locker, subDir); } return dir; } // TODO similar pattern is ised in lookup cache methods private VcsCacheDir createAndRefreshReadFolders(File file) { File parent = file.getParentFile(); //System.err.println("createAndRefreshIntermediateFolders("+file+")"); if (parent == null) return null; VcsCacheDir parentDir = (VcsCacheDir) getDir(parent.getAbsolutePath()); //System.err.println("getDir("+parent.getAbsolutePath()+") = "+parentDir); if (parentDir == null) parentDir = createAndRefreshReadFolders(parent); if (parentDir != null) { if (!parentDir.isLocal() && !parentDir.isLoaded() && !parentDir.isBeingLoaded()) { getCacheFile(new File(parentDir.getFile(), "testing"), CacheHandler.STRAT_DISK_OR_REFRESH, null); /* It's dangerous to wait here, deadlock will happen when Refresh command will be executed, * because the OutputGrabbersProcessor will be locked here. try { parentDir.waitToLoad(); } catch (InterruptedException iex) { /* Ignored *//*} */ } //System.err.println("createAndRefreshIntermediateFolders: RETURN dir name = "+file.getName()+" of "+parentDir+"\n => "+parentDir.getSubDir(file.getName())); CacheDir dir = parentDir.getSubDir(file.getName()); if (dir == null) { dir = new VcsCacheDir(getId(), file); parentDir.addChildDir(dir, false); // I have to suppose, that the initial directory is not local, // otherwise no refresh would be performed on it. dir.setLocal(false); ((VcsCacheDir) dir).readChildNamesFromDisk(); //((VcsCacheFile.VcsPersistentData) dir.getPersistentData()).setModified(true); // To save it later - done by setParent() } parentDir.writeToDisk(); registerDir(dir); heyDoRefreshDir(getPath(parentDir.getFile())); //System.err.println("lookupCacheDir: RETURN dir = "+dir); return (VcsCacheDir) dir; } else { return null; } } /** * The reading of file attributes was finished. * @param path the path of the file relative to the file system root. * @param rawData the collection of attribute elements of one or more files. * Each elements should be an array of Strings with file name and status attributes. * If the array contains only a single element, it's considered as a file name, * which should be deleted from the cache. */ public void readFileFinished(String path, Collection rawData) { //System.out.println("readDirFinished("+path+", "+rawData+")"); VcsFileSystem fs = (VcsFileSystem) fileSystem.get(); if (fs == null) return; // FS no longer exists VcsCacheDir dir = (VcsCacheDir) fs.getCacheProvider().getDir(path); if (dir == null) { dir = createAndRefreshReadFolders(fs.getFile(path)); if (dir == null) { dir = (VcsCacheDir) initCacheDir(fs.getFile(path)); registerDir(dir); } } // Put all read files there not to free them till they are written. Set readFilesLocked = new HashSet(); for (Iterator it = rawData.iterator(); it.hasNext(); ) { String[] elements = (String[]) it.next(); if (elements.length == 1) { // Just the file name is there => I'll remove the file from the cache. CacheFile file = dir.getFile(elements[0]); if (file != null) { dir.removeFile(elements[0], true); } else { file = dir.getSubDir(elements[0]); if (file != null) { dir.removeChildDir(elements[0], true); } } continue; } CacheFile file = RefreshCommandSupport.matchToExistingFile(elements, fs.getCacheIdStr(), dir.getFile()); readFilesLocked.add(file); String fileName = file.getName(); boolean isAdded = false; if ((file instanceof VcsCacheFile) && (dir.getFile(fileName) == null)) { dir.addFile(file, true); isAdded = true; } else if ((file instanceof VcsCacheDir) && (dir.getSubDir(fileName) == null)) { dir.addChildDir((CacheDir) file, true); isAdded = true; } if (isAdded) { fireCacheHandlerEvent(EVENT_ADD, file); } else { try { fireCacheHandlerEvent(EVENT_CHANGED, file); } catch (java.lang.reflect.UndeclaredThrowableException utex) { throw (java.lang.reflect.UndeclaredThrowableException) org.openide.ErrorManager.getDefault().annotate(utex, "BAD cache file fired: "+file+", it's parent = "+file.getParent()+ ", dir = "+dir+", registered dir for file '"+dir.getFile().getAbsolutePath()+"' = "+getDir(dir.getFile().getAbsolutePath())+ "\nPlease attach this text to issue #24340"); } } } //VcsCacheDir dir = createSubFiles(fs, path, rawData); //System.out.println("readDirFinished: cacheDir = "+dir+", isBeingLoaded = "+dir.isBeingLoaded()+", isLoaded = "+dir.isLoaded()); dir.writeToDisk(); heyDoRefreshDir(getPath(dir.getFile())); } /** * Called by VcsDirReader when asynchronous reading of directory is completed. * @param path directory that was read by VcsDirReader relative to the filesystem root * @param rawData vector of String[] that describes files and subdirectories * @param success whether the refresh command succeeded. */ public void readDirFinished(String path, Collection rawData, boolean success, Object locker) { //System.out.println("VcsCache.readDirFinished("+path+", rawData = "+rawData+", success = "+success); /* for (Iterator it = rawData.iterator(); it.hasNext(); ) { String[] elements = (String[]) it.next(); System.out.print(VcsUtilities.arrayToString(elements)+", "); } System.out.println(""); */ VcsFileSystem fs = (VcsFileSystem) fileSystem.get(); if (fs == null) return; // FS no longer exists String absolutePath = fsRoot + File.separatorChar + path.replace('/', File.separatorChar); if (!success && rawData.size() == 0) { CacheDir dir = getDir(absolutePath); if (dir instanceof VcsCacheDir) { ((VcsCacheDir) dir).setBeingLoaded(false); ((VcsCacheDir) dir).setLoaded(true); } return ; } //lockFileObjects(absolutePath, false); VcsCacheDir dir = createSubFiles(fs, path, rawData, locker); //dir.populateWithLocal(null); This will set applied level to STRAT_LOCAL! The dir should already contain the local stuff anyway, it should have been already loaded with locals?? //System.out.println("readDirFinished: cacheDir = "+dir+", isBeingLoaded = "+dir.isBeingLoaded()+", isLoaded = "+dir.isLoaded()); registerDir(dir); dir.writeToDisk(); dir.setBeingLoaded(false); fireCacheHandlerEvent(EVENT_CHANGED, dir); //removeLockedFileObjects(absolutePath); heyDoRefreshDir(getPath(dir.getFile())); runScheduledRefresh(dir); } /** * Called by VcsDirReader when asynchronous recursive reading of directory is completed. * @param path directory that was read by VcsDirReaderRecursive relative to the filesystem root * @param rawData vector of String[] that describes files and subdirectories * @param success whether the refresh command succeeded. */ public void readDirFinishedRecursive(String path, VcsDirContainer rawData, boolean success, Object locker) { //System.out.println("VcsCache.readDirFinishedRecursive("+path+", "+rawData.getPath()+", rawData = "+rawData+", success = "+success); VcsFileSystem fs = (VcsFileSystem) fileSystem.get(); if (fs == null) return; // FS no longer exists String absolutePath = fsRoot + File.separatorChar + path.replace('/', File.separatorChar); //lockFileObjects(absolutePath, true); VcsCacheDir dir = createSubFiles(fs, rawData, locker); //populateWithLocalRecursively(dir); This will set applied level to STRAT_LOCAL! The locals should have been already loaded. registerDirRecursive(dir); dir.writeToDiskRecursively(); fireCacheHandlerEvent(EVENT_CHANGED_RECURSIVELY, dir); //removeLockedFileObjects(absolutePath); heyDoRefreshDirRecursive(dir); } private void populateWithLocalRecursively(CacheDir dir) { dir.populateWithLocal(null); CacheDir[] dirs = dir.getSubDirs(); for (int i = 0; i < dirs.length; i++) { populateWithLocalRecursively(dirs[i]); } } private static RequestProcessor ignoreListRequestProcessor; private static WeakSet vcsCacheInstanceSet; void createIgnoreList(final VcsCacheDir dir, final List parentIgnoreList) { VcsFileSystem fs = (VcsFileSystem) fileSystem.get(); if (fs == null) return; // FS no longer exists final VcsFileSystem.IgnoreListSupport ignSupport = fs.getIgnoreListSupport(); // Create the ignore list lazily. It usually takes time and we do not want // to block the AWT (potentionally). synchronized (VcsCache.class) { if (vcsCacheInstanceSet == null) { vcsCacheInstanceSet = new WeakSet(); } vcsCacheInstanceSet.add(this); if (ignoreListRequestProcessor == null) { ignoreListRequestProcessor = new RequestProcessor("Ignore List Creation Request Processor"); } ignoreListRequestProcessor.post(new Runnable() { public void run() { // serialize the creation of ignore list for every cache // system so that parent ignore lists are correctly set. // One private RequestProcessor is used to assure the serialization. if (dir.isIgnoreListSet()) return ; // The ignore list could // already be set List ignoreList = VcsUtilities.createIgnoreList(dir, getPath(dir.getFile()), ignSupport); dir.setIgnoreList(ignoreList); } }); } } protected void finalize() throws Throwable { super.finalize(); // Clean up the request processor if all instances of this class are finalized. synchronized (VcsCache.class) { if (vcsCacheInstanceSet != null && vcsCacheInstanceSet.isEmpty()) { vcsCacheInstanceSet = null; ignoreListRequestProcessor = null; } } } /** * Creates a list of FileObjects that are contents of the topNode. * Adds that list to the map of nodes being locked. * If such node is being already locked, the lock is multiplied. * boolean lockFileObjects(String absolutePath, boolean recursively) { // make path relative to fs.. String found = this.fsRoot; VcsFileSystem fsystem = (VcsFileSystem) fileSystem.get(); if (absolutePath.length() <= found.length()) return false; String path = absolutePath.substring(found.length()); path = path.replace(File.separatorChar,'/'); if (path.startsWith("/")) path = path.substring(1); // NOI18N FileObject topFO = fsystem.findResource(path); // System.out.println("topFO = " + topFO); return doLockFileObjects(topFO, absolutePath, recursively); } */ /** * Creates a list of FileObjects that are contents of the topNode. * Adds that list to the map of nodes being locked. * If such node is being already locked, the lock is multiplied. * boolean lockFileObjects(CacheDir topNode, boolean recursively) { String path = topNode.getAbsolutePath(); return lockFileObjects(path, recursively); } */ /** * A Runnable class, that starts the refresh command on background. */ private class RefreshProcessStarter extends Object implements Runnable { private CommandSupport list; private File dir; private Object locker; public RefreshProcessStarter(CommandSupport list, File dir, Object locker) { this.list = list; this.dir = dir; this.locker = locker; } public void run() { Command cmd = list.createCommand(); if (cmd instanceof VcsDescribedCommand) { ((VcsDescribedCommand) cmd).setDiskFiles(new File[] { dir }); ((VcsDescribedCommand) cmd).addDirReaderListener(new VcsCache.DirReaderListenerWithLock(locker)); VcsManager.getDefault().showCustomizer(cmd); cmd.execute(); } } } private class DirReaderListenerWithLock extends Object implements DirReaderListener { private Object locker; public DirReaderListenerWithLock(Object locker) { this.locker = locker; } /** The reading of a directory was finished. The files attributes data are provided. * @param path the path of the read directory relative to the file system root. * @param rawData the collection of arrays of elements defined in * {@link org.netbeans.modules.vcscore.caching.RefreshCommandSupport} class. * @param whether the reading process succeeded */ public void readDirFinished(String path, Collection rawData, boolean success) { VcsCache.this.readDirFinished(path, rawData, success, locker); locker = null; } /** The recursive reading of a directory was finished. The files attributes data are provided. * @param path the path of the read directory relative to the file system root. * @param rawData the container of the retrieved directory structure with * associated array of elements defined in * {@link org.netbeans.modules.vcscore.caching.RefreshCommandSupport} class. * @param whether the reading process succeeded */ public void readDirFinishedRecursive(String path, VcsDirContainer rawData, boolean success) { VcsCache.this.readDirFinishedRecursive(path, rawData, success, locker); locker = null; } } private static final class HardReference extends SoftReference { private Object obj; public HardReference(Object obj) { super(obj); this.obj = obj; } } }

... 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.