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.openide.filesystems;

import java.io.*;
import java.util.*;
import java.lang.ref.*;
import java.net.URL;
import org.openide.ErrorManager;
import org.openide.util.Enumerations;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;

/** Implementation of the file object that simplyfies common
* tasks with hierarchy of objects for AbstractFileObject and MultiFileObject.
*
* @author Jaroslav Tulach, 
*/
abstract class AbstractFolder extends FileObject {
    /** empty array */
    private static final AbstractFolder[] EMPTY_ARRAY = new AbstractFolder[0];


    /** default extension separator */
    private static final char EXT_SEP = '.';

    /** empty hash map to mark that we are initialized */
    private static final HashMap EMPTY = new HashMap (0);

    /** file system */
    private FileSystem system;

    /** name of the file (only name and extension) */
    protected String name;

    /** strong reference to parent (can be null for root) */
    protected final AbstractFolder parent;

    /** Stores the system name of the file system to test
    * validity later.
    */
    boolean validFlag;

    /** If root changes, all AbstractFolders in hierarchy are invalidated. 
     *@see #isValid()*/
    private AbstractFolder validRoot = null;
    
    /** list of children */
    private String[] children;

    /** map that assignes file object to names. (String, Reference (AbstractFileObject)) */
    private HashMap map;

    /** listeners */
    private ListenerList listeners;

    /** Constructor. Takes reference to file system this file belongs to.
    *
    * @param fs the file system
    * @param parent the parent object (folder)
    * @param name name of the object (e.g. filename.ext)
    */
    public AbstractFolder(
        FileSystem fs, AbstractFolder parent, String name
    ) {
        this.system = fs;
        this.parent = parent;
        this.name = name;
        validFlag = true;
        if (parent != null)
            validRoot = (AbstractFolder) fs.getRoot();
    }

    /* Get the name without extension of this file or folder.
    * Period at first position is not considered as extension-separator     
    * @return name of the file or folder(in its enclosing folder)
    */
    public final String getName () {
        int i = name.lastIndexOf ('.');
        /** period at first position is not considered as extension-separator */        
        return i <= 0 ? name : name.substring (0, i);
    }

    /* Get the extension of this file or folder.
    * Period at first position is not considered as extension-separator     
    * This is the string after the last dot of the full name, if any.
    *
    * @return extension of the file or folder(if any) or empty string if there is none
    */
    public final String getExt () {
        int i = name.lastIndexOf ('.') + 1;
        /** period at first position is not considered as extension-separator */
        return i <= 1 || i == name.length ()  ? "" : name.substring (i); // NOI18N
    }
    
    /** Overrides the get name and ext method to make it faster then 
     * default implementation.
     */
    public final String getNameExt () {
        return name;
    }
    
    
    /** Overriden in AbstractFolder */
    final boolean isHasExtOverride() {
        return true;
    }    

    /** Overriden in AbstractFolder */
    boolean hasExtOverride(String ext) {
        if (ext == null) {
            return false;
        }
        /** period at first position is not considered as extension-separator */        
        if (name.length() - ext.length() <= 1) {
            return false;
        }
        
        boolean ret = name.endsWith(ext);
        if (! ret) {
            return false;
        }
        
        if (name.charAt(name.length() - ext.length() - 1) != '.') {
            return false;
        }
                
        return true;
    }
    
    /* Getter for the right file system */
    public final FileSystem getFileSystem () {
        return system;
    }

    //
    // Info
    //

    /* Test whether this object is the root folder.
    * The root should always be a folder.
    * @return true if the object is the root of a file system
    */
    public final boolean isRoot () {
        return parent == null;
    }


    /* Test whether the file is valid. The file can be invalid if it has been deserialized
    * and the file no longer exists on disk; or if the file has been deleted.
    *
    * @return true if the file object is valid
    */
    public final boolean isValid () {
        // valid
        if (parent == null) {
            return true;
        }
        boolean isValidRoot = getFileSystem ().getRoot () == validRoot;
        return validFlag && isValidRoot;
    }

    //
    // List
    //

    /* Get parent folder.
    * The returned object will satisfy {@link #isFolder}.
    *
    * @return the parent folder or null if this object {@link #isRoot}.
    */
    public final FileObject getParent () {
        return parent;
    }


    /* Get all children of this folder (files and subfolders). If the file does not have children
    * (does not exist or is not a folder) then an empty array should be returned. No particular order is assumed.
    *
    * @return array of direct children
    * @see #getChildren(boolean)
    * @see #getFolders
    * @see #getData
    */
    public final synchronized FileObject[] getChildren () {
        check ();

        if (children == null) {
            return new FileObject[0];
        }

        int size = children.length;
        ArrayList aList = new ArrayList();
        for (int i = 0; i < size; i++) {
            FileObject f = getChild (children[i]);
            if (f != null) aList.add(f);
        }

        return (FileObject [])aList.toArray(new FileObject [0]);
    }

    /** Tries to find a resource.
    * @param en enumeration of strings to scan
    * @return found object or null
    */
    final FileObject find (Enumeration en) {
        AbstractFolder fo = this;
        while (fo != null && en.hasMoreElements ()) {
            // try to go on
            // lock to provide safety for getChild
            synchronized (fo) {
                // JST: Better to call the check only here,
                // than in getChild, than it is not called
                // so often.
                fo.check ();

                fo = fo.getChild ((String)en.nextElement ());
            }
        }
        // no next requirements or not found
        return fo;
    }


    /** Tries to find a resource if it exists in memory.
    * @param en enumeration of strings to scan
    * @return found object or null
    */
    final FileObject findIfExists (Enumeration en) {
        Reference r = findRefIfExists(en);
        return(r == null? null : (FileObject)r.get());
    }

    /** Tries to find a resource if it exists in memory.
    * @param en enumeration of strings to scan
    * @return found object or null
    */
    final Reference findRefIfExists (Enumeration en) {
        AbstractFolder fo = this;
        while (fo != null && en.hasMoreElements ()) {
            if (fo.map == null) {
                // this object is not initialized yet
                return null;
            }
            // try to go on
            // lock to provide safety for getChild
            synchronized (fo) {
                String name = (String)en.nextElement ();
                if (en.hasMoreElements()){
                    fo = fo.getChild(name);
                }else{
                    return((Reference)fo.map.get(name));
                }
            }
        }
        // no next requirements or not found
        return null;
    }

    /** Finds one child for given name .
    * @param name the name of the child
    * @return the file object or null if it does not exist
    */
    protected final AbstractFolder getChild (String name) {
        Reference r = (Reference)map.get (name);
        if (r == null) {
            //On OpenVMS, see if the name is stored in a different case
            //to work around a JVM bug.
            //
            if (Utilities.getOperatingSystem() == Utilities.OS_VMS) {
                if (Character.isLowerCase(name.charAt(0)))
                    r = (Reference)map.get(name.toUpperCase());
                else
                    r = (Reference)map.get(name.toLowerCase());
                if (r == null)
                    return null;
            } else
                return null;
        }

        AbstractFolder fo = (AbstractFolder)(r.get ());

        if (fo == null) {
            // object does not exist => have to recreate it
            fo = createFile (name);
            if (fo != null && !fo.isValid()) fo = null;    
            Reference value = (fo != null) ? createReference(fo) : null;
            map.put (name, value);
        }

        return fo;
    }

    /** Get method for children array .
    * @return array of children
    */
    final  String[] getChildrenArray () { return children;}
    
    
    /** Creates Reference. In FileSystem, which subclasses AbstractFileSystem, you can overload method
    * createReference(FileObject fo) to achieve another type of Reference (weak, strong etc.)
    * @param fo FileObject
    * @return Reference to FileObject
    */
    protected  Reference createReference(FileObject fo){
        return(new WeakReference (fo));
    }

    /** Obtains enumeration of all existing subfiles.
    */
    final synchronized AbstractFolder[] subfiles () {
        if (map == null) {
            return EMPTY_ARRAY;
        }
        Iterator it = map.values ().iterator ();
        ArrayList ll = new ArrayList(map.size() + 2);
        while (it.hasNext ()) {
            Reference r = (Reference)it.next ();
            if (r == null) {
                continue;
            }
            AbstractFolder fo = (AbstractFolder)r.get ();
            if (fo != null /*&& (!fo.isFolder () || fo.map != null)*/) {
                // if the file object exists and either is not folder (then
                // we have to check the time) or it is folder and it has
                // some children
                // => use it
                ll.add (fo);
            }
        }

        return (AbstractFolder[])ll.toArray (EMPTY_ARRAY);
    }

    final boolean isInitialized () {
        return this.map != null;
    }
    /** Creates enumeration of existing subfiles in all tree
    * of files.
    *
    * @param rec should it be recursive or not
    * @return enumeration of AbstractFolders
    */
    final Enumeration existingSubFiles (boolean rec) {
        if (!rec) {
            return Enumerations.array (subfiles ());
        } else {
            class P implements org.openide.util.Enumerations.Processor {
                public Object process(Object o, Collection toAdd) {
                   AbstractFolder af = (AbstractFolder)o;
                   toAdd.addAll (Arrays.asList (af.subfiles ()));
                   return o;
               }
            }
            return Enumerations.queue (
                Enumerations.singleton (this),
                new P ()
            );
        }
    }
    
    /* helper method for MFO.setAttribute. MFO can disable firing from underlaying
     * layers. Should be reviewed in 3.4 or later 
      *@see MultiFileObject#setAttribute*/
    abstract void setAttribute(String attrName, Object value, boolean fire) throws IOException;
        
    /** Retrieve file or folder contained in this folder by name.
    * Note that neither file nor folder is created on disk.
    * @param name basename of the file or folder (in this folder)
    * @param ext extension of the file; null or ""
    *    if the file should have no extension or if folder is requested
    * @return the object representing this file or null if the file
    *   or folder does not exist
    * @exception IllegalArgumentException if this is not a folder
    */
    public final synchronized FileObject getFileObject (String name, String ext) {
        check ();

        if (ext == null || ext.equals ("")) { // NOI18N
            return getChild (name);
        } else {
            StringBuffer sb = new StringBuffer(name.length() + 1 + ((ext == null) ? 0 : ext.length()));
            sb.append(name).append(EXT_SEP).append(ext);
            return getChild (sb.toString());
        }
    }

    /* Refresh the contents of a folder. Rescans the list of children names.
    */
    public void refresh(boolean expected) {
        if (!isInitialized () && isFolder ())
            return;
        
        refresh (null, null, true, expected);
    }


    //
    // Listeners section
    //

    /* Add new listener to this object.
    * @param l the listener
    */
    public final void addFileChangeListener(FileChangeListener fcl) {
        synchronized (EMPTY_ARRAY) {
            if (listeners == null) {
                listeners = new ListenerList (FileChangeListener.class);
            }
        }
        listeners.add(fcl);
    }


    /* Remove listener from this object.
    * @param l the listener
    */
    public final void removeFileChangeListener (FileChangeListener fcl) {
        if (listeners != null) {
            listeners.remove (fcl);
        }
    }

    /** Fires event */
    protected final void fileDeleted0(FileEvent fileevent) {
        super.fireFileDeletedEvent(listeners (), fileevent);
        if(fileevent.getFile().equals(this) && parent != null) {
            FileEvent ev = new FileEvent(parent, fileevent.getFile(),fileevent.isExpected ());
            parent.fileDeleted0(ev);
        }
    }

    /** Fires event */
    protected final void fileCreated0(FileEvent fileevent, boolean isData) {
/*
        if(isData)
            super.fireFileDataCreatedEvent(listeners (), fileevent);
        else
            super.fireFileFolderCreatedEvent(listeners (), fileevent);
*/
        dispatchEvent(listeners(), fileevent);

        if(fileevent.getFile().equals(this) && parent != null) {
            FileEvent ev = new FileEvent(parent, fileevent.getFile(), fileevent.isExpected ());
            parent.fileCreated0 (ev, isData);
        }
    }
    /** Creates nad fires event */
    protected final void fileCreated0(FileObject src, FileObject file, boolean expected) {
        fileCreated0(new FileEvent (src, file, expected), false);
    }
    
    /** Fires event */
    protected final void fileChanged0 (FileEvent fileevent) {
        super.fireFileChangedEvent(listeners (), fileevent);
        if(fileevent.getFile().equals(this) && parent != null) {
            FileEvent ev = new FileEvent(parent, fileevent.getFile(), fileevent.isExpected ());
            parent.fileChanged0 (ev);
        }
    }
    
    /** Fires event - but doesn`t fork events*/
    final void fileChanged1 (FileEvent fileevent) {
        super.fireFileChangedEvent(listeners (), fileevent);
    }
    
    /** Fires event */
    protected final void fileRenamed0 (FileRenameEvent filerenameevent) {
        super.fireFileRenamedEvent(listeners (), filerenameevent);
        if(filerenameevent.getFile().equals(this) && parent != null) {
            FileRenameEvent ev = new FileRenameEvent(
                                     parent,
                                     filerenameevent.getFile(),
                                     filerenameevent.getName(),
                                     filerenameevent.getExt(),
                                     filerenameevent.isExpected ()
                                 );
            parent.fileRenamed0 (ev);
        }
    }

    /** Fires event */
    protected final void fileAttributeChanged0 (FileAttributeEvent fileattributeevent) {
        super.fireFileAttributeChangedEvent(listeners (), fileattributeevent);
        if(fileattributeevent.getFile().equals(this) && parent != null) {
            FileAttributeEvent ev = new FileAttributeEvent(
                                        parent,
                                        fileattributeevent.getFile(),
                                        fileattributeevent.getName(),
                                        fileattributeevent.getOldValue(),
                                        fileattributeevent.getNewValue(), 
                                        fileattributeevent.isExpected ()
                                    );
            parent.fileAttributeChanged0 (ev);
        }
    }

    /** @return true if there is a listener
    */
    protected final boolean hasListeners () {
        boolean fsHas = getFileSystem().getFCLSupport ().hasListeners ();
        boolean repHas = false;        
        Repository rep  = getFileSystem().getRepository ();
        if (rep != null)
            repHas = rep.getFCLSupport ().hasListeners ();        
        
        return (listeners != null && listeners.getAllListeners ().length != 0) || repHas || fsHas;
    }

    /** @return true if this folder or its parent have listeners
    */
    protected final boolean hasAtLeastOneListeners () {
        
        return hasListeners () || (parent != null && parent.hasListeners ());         
    }

    /** @return enumeration of all listeners.
    */
    private final Enumeration listeners () {
        if (listeners == null) {
            return Enumerations.empty();
        } else {
            return Enumerations.removeNulls (
                Enumerations.array (listeners.getAllListeners ())
            );
        }
    }

    //
    // Refreshing the state of the object
    //

    /** Test if the file has been checked and if not, refreshes its
    * content.
    */
    private final void check () {
        if (map == null) {
            refresh (null, null, false, false);
            if (map == null) {
                // create empty map to mark that we are initialized
                map = EMPTY;
                if (children == null) {
                    children = new String [] {};                   
                }
            }
        }
    }

    /** Refresh the content of file. Ignores changes to the files provided,
    * instead returns its file object.
    * @param added do not notify addition of this file
    * @param removed do not notify removing of this file
    */
    protected final void refresh (String added, String removed) {
        this.refresh(added, removed, false);
    }

    /** Refresh the content of file. Ignores changes to the files provided,
    * instead returns its file object.
    * @param added do not notify addition of this file
    * @param removed do not notify removing of this file
    * @param reuseChildren a flag reuse children?
    */
    protected final void refresh (String added, String removed, boolean reuseChildren) {
        if (reuseChildren && removed != null) {
            String[] nc = new String[children.length];
            System.arraycopy(children, 0, nc, 0, children.length);
            for (int i = nc.length; --i >= 0; ) {
                if (removed.equals(nc[i])) {
                    nc[i] = null;
                    break;
                }
            }
            refresh (added, removed, true, false, nc);
        } else {
            refresh (added, removed, true, false, null);
        }
    }

    /** Method that allows subclasses to return its children.
    *
    * @return names (name . ext) of subfiles
    */
    protected abstract String[] list ();

    /** Method to create a file object for given subfile.
    * @param name of the subfile
    * @return the file object
    */
    protected abstract AbstractFolder createFile (String name);

    /** Refresh the content of file. Ignores changes to the files provided,
    * instead returns its file object.
    * @param added do not notify addition of this file
    * @param removed do not notify removing of this file
    * @param fire true if we should fire changes
    * @param expected true if the change has been expected by the user
    */
    protected void refresh (
        String added, String removed, boolean fire, boolean expected
    ) {
        this.refresh(added, removed, fire, expected, null);
    }


    void registerChild (String name) {
        synchronized (this) {
            if (map == null)
                check ();

            Object o = map.put(name, new WeakReference(null));
            if (o != null) {
                map.put(name, o);
            } else {
                String newChildren[] = new String [children.length + 1];
                System.arraycopy(children, 0, newChildren, 0, children.length);
                newChildren [children.length] = name;
                children = newChildren;
            }
        }
    }

    /** Refresh the content of file. Ignores changes to the files provided,
    * instead returns its file object.
    * @param added do not notify addition of this file
    * @param removed do not notify removing of this file
    * @param fire true if we should fire changes
    * @param expected true if the change has been expected by the user
    * @param list contains list of children
    */
    protected final void refreshFolder (
        String added, String removed, boolean fire, boolean expected, String[] list
    ) {
        try {
            getFileSystem ().beginAtomicAction ();
            synchronized (this) {
                if (list == null) {
                    list = list();
                }
                // refresh of folder checks children
                String[] newChildren = list;

                if (newChildren == null && parent == null) {
                    // if root => we have to have children
                    newChildren = new String[0];
                }

                if (children == null && newChildren == null) {
                    // no change and we are still date file
                    return;
                }

                //    System.out.println ("Refresh: " + this + " fire: " + fire); // NOI18N
                //    Thread.dumpStack ();

                // new map (String, AbstractFileObject)
                HashMap m;
                // set of added files (String)
                Set add;
                // moreover map will contain only such files that disappeared
                int newChildrenContainNull = 0;

                if (newChildren != null) {
                    int size = newChildren.length;

                    m = new HashMap (size * 4 / 3 + 1, 0.75f);
                    add = new HashSet (size * 4 / 3 + 1, 0.75f);

                    Object replaceInSteadOfRemoved = map != null ? map.get (removed) : null;

                    for (int i = 0; i < size; i++) {
                        String ch = newChildren[i];

                        if (ch == null) {
                            // ignore this and
                            newChildrenContainNull++;
                            continue;
                        }

                        Reference old = map == null ? null : (Reference)map.remove (ch);
                        /** #18340 - ch.equals(removed) may seem a little confusing because 
                         * one would expect that  children doesn`t contain removed.
                         * But in CVS filesystems renaming of FileObject means that 
                         * two FileObjects will be present (old - needs checkout, 
                         * new - localy added). 
                         */
                        boolean isSpecialRename = (added != null && ch.equals(removed));
                        if (old == null || isSpecialRename) {
                            // create new empty reference
                            old = new WeakReference (null);
                            add.add (ch);
                        }
                        m.put (ch, old);
                    }

                    if (added != null && replaceInSteadOfRemoved != null) {
                        m.put (added, replaceInSteadOfRemoved);
                    }

                } else {
                    m = new HashMap (0);
                    add = Collections.EMPTY_SET;
                }

                // maps (String, AbstractFileObject) between objects that has diappeared
                HashMap disappeared = null;

                if (fire) {
                    // a set of files to notify that has been added
                    if (added != null) {
                        add.remove (added);
                    }

                    if (map != null) {
                        //
                        // MAP IS CHANGING TO (String, AbstractFileObject)
                        // this should be fine cause map is replaced immediatelly after
                        // this loop
                        //

                        disappeared = new HashMap ();
                        Iterator it = map.entrySet ().iterator ();
                        while (it.hasNext ()) {
                            Map.Entry entry = (Map.Entry)it.next ();
                            // uses the value and replaces it immediatelly                            
                            String name = (String)entry.getKey ();
                            AbstractFolder child = getChild (name);
                            if (child != null) disappeared.put(name, child);
                        }

                        // remove the removed
                        if (removed != null) {
                            disappeared.remove (removed);
                        }

                        if (disappeared.isEmpty ()) {
                            disappeared = null;
                        }
                    }
                }

                // use the new map
                // Map now contains the right content
                map = m;

                if (newChildrenContainNull != 0) {
                    // exclude nulls from the array
                    String[] arr = new String[newChildren.length - newChildrenContainNull];

                    int j = 0;
                    for (int i = 0; i < newChildren.length; i++) {
                        if (newChildren[i] != null) {
                            arr[j++] = newChildren[i];
                        }
                    }
                    children = arr;
                } else {
                    // ok, no nulls in the array
                    children = newChildren;
                }


                if (fire && !add.isEmpty () && hasAtLeastOneListeners ()) {
                    // fire these files has been added
                    for (Iterator it = add.iterator (); it.hasNext (); ) {
                        String name = (String)it.next ();

                        AbstractFolder fo = getChild (name);
                        if (fo == null) continue;

                        fileCreated0 (this, fo, expected);
                        // a change in children
                        //        changed = true;
                    }
                }

                if (fire && disappeared != null) {
                    // fire these files has been removed
                    for (Iterator it = disappeared.values ().iterator (); it.hasNext (); ) {
                        AbstractFolder fo = (AbstractFolder)it.next ();
                        fo.validFlag = false;

                        if (hasAtLeastOneListeners () || fo.hasAtLeastOneListeners ()) {
                            FileEvent ev = new FileEvent (fo , fo, expected);
                            fo.fileDeleted0 (ev);
                        }
                        // a change happened
                        //        changed = true;
                    }
                }
                  
                if (fire && added == null && removed == null && !getFileSystem().isReadOnly()) {                   
                    Enumeration subfiles = existingSubFiles(false);
                    Set addedAndRemoved = null;                    

                    while (subfiles.hasMoreElements()) {                        
                        AbstractFolder child = (AbstractFolder) subfiles.nextElement();
                        
                        if (child.isData()) {
                            if (addedAndRemoved == null) {
                                addedAndRemoved = new HashSet ();
                                if (add != null) addedAndRemoved.addAll(add);
                                if (added != null) addedAndRemoved.add(added);
                                if (disappeared != null) addedAndRemoved.addAll(disappeared.keySet());
                                if (removed != null) addedAndRemoved.add(removed);
                            }
                            if (!addedAndRemoved.contains(child.getNameExt())) {
                                child.refresh(expected);        
                            }                                
                        }
                    }

                }
            }
        } finally {
            getFileSystem ().finishAtomicAction ();
        }
    }
    /** Refresh the content of file. Ignores changes to the files provided,
    * instead returns its file object.
    * @param added do not notify addition of this file
    * @param removed do not notify removing of this file
    * @param fire true if we should fire changes
    * @param expected true if the change has been expected by the user
    * @param list contains list of children
    */
    protected void refresh (
        String added, String removed, boolean fire, boolean expected, String[] list
    ) {
        if (isFolder ()) {
            refreshFolder (added, removed, fire, expected, list);
        }
    }
    
    /** Notification that the output stream has been closed.
     * @param fireFileChanged defines if FileEvent should be fired to notify about 
     * change of file after close of stream
     */
    protected void outputStreamClosed (boolean fireFileChanged) {
        if (fireFileChanged)
            fileChanged0 (new FileEvent (AbstractFolder.this));
    }
        

    //
    // Serialization
    //

    public final Object writeReplace () {
        return new Replace(this);
    }
    
    /* Delete this file. If the file is a folder and it is not empty then
    * all of its contents are also recursively deleted.
    *
    * @param lock the lock obtained by a call to {@link #lock}
    * @exception IOException if the file could not be deleted
    */    
    final public void delete(FileLock lock) throws IOException {
        if (isFolder ()) {
            FileObject[] fos = this.getChildren();
            for (int i = 0; i < fos.length; i++) {
                FileObject fo = fos[i];
                FileLock foLock = fo.lock();
                try {
                    fo.delete(foLock);
                } catch (IOException iex) {
                    String   message = NbBundle.getMessage(getClass(), "EXC_CannotDelete", //NOI18N
                    // XXX use FileUtil.getFileDisplayName instead?
                    getPath(), fo.getFileSystem().getDisplayName());
                    ExternalUtil.annotate(iex, message);//NOI18N                    
                    throw iex;
                } finally {
                    foLock.releaseLock();
                }
            }
        }
        handleDelete (lock);        
    }
    
    abstract void handleDelete (FileLock lock) throws IOException;
    
    private static final class Replace implements Serializable {
        
        private static final long serialVersionUID = 1L;
        
        private transient FileObject f;
        private String fsname;
        private String path;
        private URL url;
        
        public Replace(FileObject f) {
            this.f = f;
        }
        
        private void writeObject(ObjectOutputStream oos) throws IOException {
            fsname = f.getFileSystem().getSystemName();
            path = f.getPath();
            url = f.getURL();
            assert url != null : "No URL for " + path;
            oos.defaultWriteObject();
        }
        
        private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
            ois.defaultReadObject();
            assert fsname != null : "Should always have a non-null fsname here";
            FileSystem fs = Repository.getDefault().findFileSystem(fsname);
            if (fs != null) {
                assert path != null : "Should always have a non-null path here";
                f = fs.findResource(path);
            }
            if (f == null) {
                // Fall back to URL.
                assert url != null : "Should always have a non-null URL here";
                FileObject[] fos = URLMapper.findFileObjects(url);
                if (fos.length >= 1) {
                    f = fos[0];
                } else {
                    throw new FileNotFoundException("Could not restore: " + url); // NOI18N
                }
            }
        }
        
        public Object readResolve() {
            assert f != null : "Did not read " + url;
            return f;
        }
        
    }
    
}
... 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.