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.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.openide.ErrorManager;
import org.openide.util.WeakSet;

import org.netbeans.modules.vcscore.cache.CacheDir;
import org.netbeans.modules.vcscore.cache.CacheFile;
import org.netbeans.modules.vcscore.cache.CacheHandler;

/**
 * File in the cache.
 * @author  Martin Entlicher
 */
public final class VcsCacheFile extends CacheFile {

    // true if the file is not in VCS
    //private boolean local = false;
    
    public VcsCacheFile(String memberOfCache) {
        super(memberOfCache, new VcsCacheFile.VcsPersistentData(false));
        //System.out.println("new File with anonymous name.");
        //Thread.currentThread().dumpStack();
    }

    public VcsCacheFile(String memberOfCache, String name) {
        super(memberOfCache, name, new VcsCacheFile.VcsPersistentData(false));
        //System.out.println("new File '"+name+"'");
    }

    public VcsCacheFile(String memberOfCache, String name, boolean local) {
        this(memberOfCache, name);
        setLocal(local);
        //System.out.println("new File '"+name+"', local = "+local);
    }

    VcsCacheFile(String memberOfCache, CacheFile.PersistentData data) {
        super(memberOfCache, data.getName(), data);
        //System.out.println("new File '"+data.getName()+"' FROM DATA");
    }

    public void setLocal (boolean local) {
        ((VcsCacheFile.VcsPersistentData) getPersistentData()).setLocal(local);
    }

    public boolean isLocal () {
        return ((VcsCacheFile.VcsPersistentData) getPersistentData()).isLocal();
    }
    
    public String getStatus() {
        CacheDir parent = getParent();
        if (isLocal() && parent != null && parent.isIgnoreListSet() && parent.isIgnored(getName())) {
            return CacheStatuses.STATUS_IGNORED;
        } else return super.getStatus();
    }
    
    protected void setParent(CacheDir par) {
        super.setParent(par);
        VcsCacheFile.VcsPersistentData vdata = (VcsCacheFile.VcsPersistentData) getPersistentData();
        if (par != null) {
            vdata.setCacheFileName(((VcsCacheDir) par).getCacheFileName());
        } else {
            vdata.setRemoved(true);
        }
        vdata.setModified(true); // I should be saved under my new parent
    }
    
    public static String readFileCacheName(String line, String cacheName, boolean[] isDir) {
        String[] elements = StatusFormat.getElementsFromLine(line);
        String name = elements[StatusFormat.ELEMENT_INDEX_FILE_NAME];
        if (name == null) throw new IllegalArgumentException("File name element is missing."); // NOI18N
        isDir[0] = name.endsWith("/"); // NOI18N
        return (isDir[0]) ? name.substring(0, name.length()-1) : name;
    }

    public static CacheFile readFileCache(String line, String cacheName, java.io.File parent) {
        //VcsCacheFile file = new VcsCacheFile(cacheName);
        //System.out.println("VcsCacheFile.readFileCache("+line+", "+cacheName+", "+parent+")");
        String[] elements = StatusFormat.getElementsFromLine(line);
        String name = elements[StatusFormat.ELEMENT_INDEX_FILE_NAME];
        if (name == null) throw new IllegalArgumentException("File name element is missing."); // NOI18N
        boolean fileIsDir = name.endsWith("/"); // NOI18N
        String fileName = (fileIsDir) ? name.substring(0, name.length()-1) : name;
        VcsCache cache = (VcsCache) CacheHandler.getInstance().getCache(cacheName);
        CacheFile file = null;
        if (cache != null) {
            VcsCacheDir parentDir = (VcsCacheDir) cache.getDir(parent.getAbsolutePath());
            if (parentDir != null) {
                file = parentDir.getChildIfExists(fileName);
            }
        }
        if (file == null) {
            if (fileIsDir) {
                file = new VcsCacheDir(cacheName, new java.io.File(parent, fileName));
            } else {
                file = new VcsCacheFile(cacheName);
            }
            file.setName(fileName);
        }
        RefreshCommandSupport.matchToFile(elements, file);
        if (file instanceof VcsCacheFile) ((VcsCacheFile) file).setLocal(false);
        if (file instanceof VcsCacheDir) ((VcsCacheDir) file).setLocal(false);
        file.getPersistentData().setModified(false);
        //System.out.println("VcsCacheFile.readFileCache("+line+", "+cacheName+", "+parent+") = "+file);
        return file;
    }
    
    /*
    public String writeLineToDisk() {
        return RefreshCommandSupport.getLineFromElements(RefreshCommandSupport.makeElements(this));
        /*
        StringBuffer buff = new StringBuffer("/");
        buff.append(getName());
        buff.append("/");
        buff.append(getStatus());
        buff.append("///"); //TODO - temporary
        //TODO
        return buff.toString();
         *
    }
     */

    public String toString(){
        return "VcsFile["+ // NOI18N
               "name='"+getName()+"'"+ // NOI18N
               ",status="+getStatus()+ // NOI18N
               ",locker="+getLocker()+ // NOI18N
               ",revision="+getRevision()+ // NOI18N
               ",sticky="+getSticky()+ // NOI18N
               ",attr="+getAttr()+ // NOI18N
               ",size="+getSize()+ // NOI18N
               ",date="+getDate()+ // NOI18N
               ",time="+getTime()+ // NOI18N
               ",local="+isLocal()+ // NOI18N
               "]"; // NOI18N
    }

    /* TEST METHOD ONLY *
    protected void finalize() throws Throwable {
        System.out.println("File "+getName()+"  FINALIZED");
    }
     */
    
    protected static class VcsPersistentData extends CacheFile.PersistentData {
        
        private File cacheFile = null;
        private boolean removed = false;
        private volatile boolean loaded = false;
        //private CacheFile.PersistentData parentData;
        private boolean errorLineReported = false;
        private Object errorLock = new Object();
        
        public VcsPersistentData(boolean directory) {
            super(directory);
            //System.out.println("CREATED VcsPersistentData: "+this);
        }
        
        /**
         * Set the data as removed. The write process should then remove
         * this data from the disk cache.
         */
        protected void setRemoved(boolean removed) {
            this.removed = removed;
        }
        
        protected final void setLoaded(boolean loaded) {
            this.loaded = loaded;
        }
        
        protected final boolean isLoaded() {
            return loaded;
        }
        
        void setCacheFileName(String cacheFileName) {
            this.cacheFile = (cacheFileName == null) ? null : new File(cacheFileName);
        }
        
        /**
         * If it's necessary to save the parent's data when I'm saved, set the
         * parent's data with this method.
         * It's recommended, that if this is directory data, parent directory
         * data should be set, so that the parent directory has correct content
         * in the disk cache.
         *
        void setParentData(CacheFile.PersistentData parentData) {
            this.parentData = parentData;
        }
         */
        
        public String writeLineToDisk() {
            if (removed) return "";
            String[] elements = RefreshCommandSupport.makeElements(this);
            if (isDirectory()) elements[StatusFormat.ELEMENT_INDEX_FILE_NAME] += "/"; // NOI18N
            return StatusFormat.getLineFromElements(elements);
        }
        
        /**
         * Subclasses need to implement this to store the data into disk cache.
         * This implementation stores not only this data, but also all it's siblings
         * for efficiency.
         */
        protected void doWriteToDisk() throws IOException {
            // Do not store data, that do not have a cache file to be written into
            // or data, that were not loaded yet.
            if (cacheFile == null || (isDirectory() && !isLoaded())) return ;
            Object lock = getFileAccessLock(cacheFile);
            try {
                synchronized (lock) {
                    //Just write the cache info for a file, no siblings information
                    //is written here.
                    //
                    BufferedWriter out = null;
                    try {
                        File cacheDir = cacheFile.getParentFile();
                        if (!cacheDir.exists()) cacheDir.mkdirs();
                        cacheFile.createNewFile();
                        out = new BufferedWriter(new FileWriter(cacheFile));
                        
                        if (isLocal()) {
                            //System.out.println("VcsPersistentData: WRITE: "+data.writeLineToDisk()+"\n"+
                            //                   "                   Written data = "+data+"\n"+
                            //                   "                   INTO "+cacheFile);
                            String line = writeLineToDisk();
                            if (line.length() > 0) {
                                out.write(line);
                                out.newLine();
                            }
                        }
                        setModified(false);
                        
                        out.flush();
                    } finally {
                        if (out != null) out.close();
                    }
                }
            } finally {
                releaseFileAccessLock(cacheFile, lock);
            }
        }
        
        private void setUnmodified(Set siblings) {
            for (Iterator it = siblings.iterator(); it.hasNext(); ) {
                VcsPersistentData data = (VcsPersistentData) it.next();
                data.setModified(false);
            }
        }
        
        private void doWriteToDisk(Set siblings, boolean canOverwrite) throws IOException {
            //System.err.println("VcsPersistentData("+cacheFile+").doWriteToDisk("+siblings.size()+", "+canOverwrite+")");
            if (!canOverwrite) {
                addSiblingsFromDisk(siblings);
                //System.out.println("SIBLINGS AFTER ADD from disk: "+dumpSiblings(true, siblings));
            }
            BufferedWriter out = null;
            try {
                File cacheDir = cacheFile.getParentFile();
                if (!cacheDir.exists()) cacheDir.mkdirs();
                cacheFile.createNewFile();
                out = new BufferedWriter(new FileWriter(cacheFile));
                for (Iterator it = siblings.iterator(); it.hasNext(); ) {
                    VcsPersistentData data = (VcsPersistentData) it.next();
                    if (!data.isLocal()) {
                        //System.err.println("VcsPersistentData: WRITE: "+data.writeLineToDisk()+"\n"+
                        //                   "                   Written data = "+data+"\n"+
                        //                   "                   INTO "+cacheFile);
                        String line = data.writeLineToDisk();
                        if (line.length() > 0) {
                            out.write(line);
                            out.newLine();
                        }
                    } else {
                        //System.err.println("VcsPersistentData: NOT Written: "+data);
                    }
                    data.setModified(false);
                }
                out.flush();
            } finally {
                if (out != null) out.close();
            }
            //System.out.println("Write finished.");
        }
        
        private void addSiblingsFromDisk(Set siblings) throws IOException {
            Set siblingsNames = new HashSet();
            for (Iterator it = siblings.iterator(); it.hasNext(); ) {
                CacheFile.PersistentData data = (CacheFile.PersistentData) it.next();
                siblingsNames.add(data.getName());
            }
            if (cacheFile.exists() && cacheFile.canRead()) {
                BufferedReader in = null;
                try {
                    in = new BufferedReader(new FileReader(cacheFile));
                    String line = null;
                    while ((line = in.readLine()) != null) {
                        try {
                            String[] elements = StatusFormat.getElementsFromLine(line);
                            String fileName = elements[StatusFormat.ELEMENT_INDEX_FILE_NAME];
                            if (fileName == null) {
                                synchronized (errorLock) {
                                    if (!errorLineReported) {
                                        ErrorManager.getDefault().notify(org.openide.ErrorManager.WARNING,
                                            ErrorManager.getDefault().annotate(
                                                new IllegalArgumentException("File name element is missing."), // NOI18N
                                                "Line read: '"+line+"' in file "+cacheFile)); // NOI18N
                                        errorLineReported = true;
                                    }
                                }
                                continue;
                            }
                            boolean isDir = fileName.endsWith("/");
                            if (isDir) fileName = fileName.substring(0, fileName.length() - 1);
                            if (!siblingsNames.contains(fileName)) {
                                VcsCacheFile.VcsPersistentData data = new VcsCacheFile.VcsPersistentData(isDir);
                                data.setName(fileName);
                                RefreshCommandSupport.matchToFile(elements, data);
                                data.setModified(false); // I just read them, they should not be modified!
                                siblings.add(data);
                                siblingsNames.add(data.getName());
                            }
                        } catch (IllegalArgumentException iaex) {
                            synchronized (errorLock) {
                                if (!errorLineReported) {
                                    ErrorManager.getDefault().notify(org.openide.ErrorManager.WARNING,
                                        ErrorManager.getDefault().annotate(iaex, "Line read: '"+line+"'"));
                                }
                            }
                        }
                    }
                    in.close();
                } catch (IOException e){
                    ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
                } finally {
                    if (in != null) { 
                        try {
                            in.close();
                        } catch (IOException exc) {}
                    }
                }
            }
        }
        
        private void doWriteToDiskSimple() throws IOException {
            Map dataMap = readExistingData();
            dataMap.put(getName(), this);
            BufferedWriter out = null;
            try {
                File cacheDir = cacheFile.getParentFile();
                if (!cacheDir.exists()) cacheDir.mkdirs();
                cacheFile.createNewFile();
                out = new BufferedWriter(new FileWriter(cacheFile));
                for (Iterator it = dataMap.values().iterator(); it.hasNext(); ) {
                    VcsPersistentData data = (VcsPersistentData) it.next();
                    if (!data.isLocal()) {
                        //System.err.println("VcsPersistentData: WRITE: "+data.writeLineToDisk()+"\n"+
                        //                   "                   Written data = "+data+"\n"+
                        //                   "                   INTO "+cacheFile);
                        String line = data.writeLineToDisk();
                        if (line.length() > 0) {
                            out.write(line);
                            out.newLine();
                        }
                    } else {
                        //System.err.println("VcsPersistentData: NOT Written: "+data);
                    }
                    data.setModified(false);
                }
                out.flush();
            } finally {
                if (out != null) out.close();
            }
        }
        
        private Map readExistingData() {
            Map datas = new HashMap();
            if (cacheFile.exists() && cacheFile.canRead()) {
                BufferedReader in = null;
                try {
                    in = new BufferedReader(new FileReader(cacheFile));
                    String line = null;
                    while ((line = in.readLine()) != null) {
                        try {
                            String[] elements = StatusFormat.getElementsFromLine(line);
                            String fileName = elements[StatusFormat.ELEMENT_INDEX_FILE_NAME];
                            if (fileName == null) {
                                synchronized (errorLock) {
                                    if (!errorLineReported) {
                                        ErrorManager.getDefault().notify(org.openide.ErrorManager.WARNING,
                                            ErrorManager.getDefault().annotate(
                                                new IllegalArgumentException("File name element is missing."), // NOI18N
                                                "Line read: '"+line+"' in file "+cacheFile)); // NOI18N
                                        errorLineReported = true;
                                    }
                                }
                                continue;
                            }
                            boolean isDir = fileName.endsWith("/");
                            if (isDir) fileName = fileName.substring(0, fileName.length() - 1);
                            VcsCacheFile.VcsPersistentData data = new VcsCacheFile.VcsPersistentData(isDir);
                            data.setName(fileName);
                            RefreshCommandSupport.matchToFile(elements, data);
                            data.setModified(false); // I just read them, they should not be modified!
                            datas.put(fileName, data);
                        } catch (IllegalArgumentException iaex) {
                            synchronized (errorLock) {
                                if (!errorLineReported) {
                                    ErrorManager.getDefault().notify(org.openide.ErrorManager.WARNING,
                                        ErrorManager.getDefault().annotate(iaex, "Line read: '"+line+"'"));
                                }
                            }
                        }
                    }
                    in.close();
                } catch (IOException e){
                    ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
                } finally {
                    if (in != null) { 
                        try {
                            in.close();
                        } catch (IOException exc) {}
                    }
                }
            }
            return datas;
        }
        
        private static Map OPEN_FILES_LOCKS = new HashMap();
        
        /**
         * Process an exlusive access to a disk file.
         * @param file The disk file to access
         * @run The runnable task, that performs the access.
         *
        static void processCacheFileAccess(File file, Runnable run) {
            MutableInt lock;
            synchronized (OPEN_FILES_LOCKS) {
                lock = (MutableInt) OPEN_FILES_LOCKS.get(file);
                if (lock == null) {
                    lock = new MutableInt();
                    OPEN_FILES_LOCKS.put(file, lock);
                }
                lock.inc();
            }
            try {
                synchronized (lock) {
                    run.run();
                }
            } finally {
                synchronized (OPEN_FILES_LOCKS) {
                    lock.dec();
                    if (lock.get() == 0) {
                        OPEN_FILES_LOCKS.remove(file);
                    }
                }
            }
        }
         */
        
        /**
         * Get an exlusive access to a disk file. releaseFileAccessLock()
         * must be called after the access is finished to release the lock.
         * @param file The disk file to access
         * @return The lock object, that can be used to synchronize the exlusive
         * access to the file.
         */
        static Object getFileAccessLock(File file) {
            MutableInt lock;
            synchronized (OPEN_FILES_LOCKS) {
                lock = (MutableInt) OPEN_FILES_LOCKS.get(file);
                if (lock == null) {
                    lock = new MutableInt();
                    OPEN_FILES_LOCKS.put(file, lock);
                }
                lock.inc();
                //System.out.println("Lock ACQUIRED for file '"+file+"', "+lock);
                //System.err.println("Lock ACQUIRED for file '"+file+"', "+lock);
            }
            return lock;
        }
        
        /**
         * Release the exlusive access to a disk file.
         * @param file The disk file, that was accessed
         * @param lock The lock object obtained from getFileAccessLock().
         */
        static void releaseFileAccessLock(File file, Object lock) {
            if (!(lock instanceof MutableInt)) throw new IllegalArgumentException("Bad lock instance");
            MutableInt miLock = (MutableInt) lock;
            synchronized (OPEN_FILES_LOCKS) {
                miLock.dec();
                if (miLock.get() <= 0) {
                    OPEN_FILES_LOCKS.remove(file);
                }
                //System.out.println("Lock RELEASED for file '"+file+"', "+lock);
                //System.err.println("Lock RELEASED for file '"+file+"', "+lock);
            }
        }
        
        private static final class MutableInt {
            
            private int i;
            
            public MutableInt() {
                i = 0;
            }
            
            public void set(int i) {
                this.i = i;
            }
            
            public int get() {
                return i;
            }
            
            public void inc() {
                i++;
            }
            
            public void dec() {
                i--;
            }
            
            public String toString() {
                return Integer.toString(i);
            }
        }
    }
}
... 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.