KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > filesystems > AbstractFolder


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.filesystems;
21
22 import java.io.FileNotFoundException JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.ObjectInputStream JavaDoc;
25 import java.io.ObjectOutputStream JavaDoc;
26 import java.io.Serializable JavaDoc;
27 import java.lang.ref.Reference JavaDoc;
28 import java.lang.ref.WeakReference JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.Collection JavaDoc;
33 import java.util.Collections JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import java.util.EventListener JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.HashSet JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Set JavaDoc;
41 import org.openide.util.Enumerations;
42 import org.openide.util.NbBundle;
43 import org.openide.util.Utilities;
44
45 /** Implementation of the file object that simplyfies common
46 * tasks with hierarchy of objects for AbstractFileObject and MultiFileObject.
47 *
48 * @author Jaroslav Tulach,
49 */

50 abstract class AbstractFolder extends FileObject {
51     /** empty array */
52     private static final AbstractFolder[] EMPTY_ARRAY = new AbstractFolder[0];
53
54     /** default extension separator */
55     private static final char EXT_SEP = '.';
56
57     /** file system */
58     private FileSystem system;
59
60     /** name of the file (only name and extension) */
61     protected String JavaDoc name;
62
63     /** strong reference to parent (can be null for root) */
64     protected final AbstractFolder parent;
65
66     /** Stores the system name of the file system to test
67     * validity later.
68     */

69     boolean validFlag;
70
71     /** If root changes, all AbstractFolders in hierarchy are invalidated.
72      *@see #isValid()*/

73     private final AbstractFolder validRoot;
74
75     /** list of children */
76     private String JavaDoc[] children;
77
78     /** map that assigns file object to names. */
79     private Map JavaDoc<String JavaDoc,Reference JavaDoc<AbstractFolder>> map;
80
81     /** listeners */
82     private ListenerList<FileChangeListener> listeners;
83
84     /** Constructor. Takes reference to file system this file belongs to.
85     *
86     * @param fs the file system
87     * @param parent the parent object (folder)
88     * @param name name of the object (e.g. <code>filename.ext</code>)
89     */

90     public AbstractFolder(FileSystem fs, AbstractFolder parent, String JavaDoc name) {
91         this.system = fs;
92         this.parent = parent;
93         this.name = name;
94         validFlag = true;
95         validRoot = (parent != null) ? (AbstractFolder) fs.getRoot() : null;
96     }
97
98     /* Get the name without extension of this file or folder.
99     * Period at first position is not considered as extension-separator
100     * @return name of the file or folder(in its enclosing folder)
101     */

102     public final String JavaDoc getName() {
103         int i = name.lastIndexOf('.');
104
105         /** period at first position is not considered as extension-separator */
106         return (i <= 0) ? name : name.substring(0, i);
107     }
108
109     /* Get the extension of this file or folder.
110     * Period at first position is not considered as extension-separator
111     * This is the string after the last dot of the full name, if any.
112     *
113     * @return extension of the file or folder(if any) or empty string if there is none
114     */

115     public final String JavaDoc getExt() {
116         int i = name.lastIndexOf('.') + 1;
117
118         /** period at first position is not considered as extension-separator */
119         return ((i <= 1) || (i == name.length())) ? "" : name.substring(i); // NOI18N
120
}
121
122     /** Overrides the get name and ext method to make it faster then
123      * default implementation.
124      */

125     public final String JavaDoc getNameExt() {
126         return name;
127     }
128
129     /** Overridden in AbstractFolder */
130     final boolean isHasExtOverride() {
131         return true;
132     }
133
134     /** Overridden in AbstractFolder */
135     boolean hasExtOverride(String JavaDoc ext) {
136         if (ext == null) {
137             return false;
138         }
139
140         /** period at first position is not considered as extension-separator */
141         if ((name.length() - ext.length()) <= 1) {
142             return false;
143         }
144
145         boolean ret = name.endsWith(ext);
146
147         if (!ret) {
148             return false;
149         }
150
151         if (name.charAt(name.length() - ext.length() - 1) != '.') {
152             return false;
153         }
154
155         return true;
156     }
157
158     /* Getter for the right file system */
159     public final FileSystem getFileSystem() {
160         return system;
161     }
162
163     //
164
// Info
165
//
166

167     /* Test whether this object is the root folder.
168     * The root should always be a folder.
169     * @return true if the object is the root of a file system
170     */

171     public final boolean isRoot() {
172         return parent == null;
173     }
174
175     /* Test whether the file is valid. The file can be invalid if it has been deserialized
176     * and the file no longer exists on disk; or if the file has been deleted.
177     *
178     * @return true if the file object is valid
179     */

180     public final boolean isValid() {
181         // valid
182
if (parent == null) {
183             return validFlag;
184         }
185
186         boolean isValidRoot = getFileSystem().getRoot() == validRoot;
187
188         return validFlag && isValidRoot;
189     }
190
191     //
192
// List
193
//
194

195     /* Get parent folder.
196     * The returned object will satisfy {@link #isFolder}.
197     *
198     * @return the parent folder or <code>null</code> if this object {@link #isRoot}.
199     */

200     public final FileObject getParent() {
201         return parent;
202     }
203
204     /* Get all children of this folder (files and subfolders). If the file does not have children
205     * (does not exist or is not a folder) then an empty array should be returned. No particular order is assumed.
206     *
207     * @return array of direct children
208     * @see #getChildren(boolean)
209     * @see #getFolders
210     * @see #getData
211     */

212     public final synchronized FileObject[] getChildren() {
213         check();
214
215         if (children == null) {
216             return new FileObject[0];
217         }
218
219         int size = children.length;
220         ArrayList JavaDoc<FileObject> aList = new ArrayList JavaDoc<FileObject>();
221
222         for (int i = 0; i < size; i++) {
223             FileObject f = getChild(children[i]);
224
225             if (f != null) {
226                 aList.add(f);
227             }
228         }
229
230         return aList.toArray(new FileObject[0]);
231     }
232
233     /** Tries to find a resource.
234     * @param en enumeration of strings to scan
235     * @return found object or null
236     */

237     final FileObject find(Enumeration JavaDoc<String JavaDoc> en) {
238         AbstractFolder fo = this;
239
240         while ((fo != null) && en.hasMoreElements()) {
241             // try to go on
242
// lock to provide safety for getChild
243
synchronized (fo) {
244                 // JST: Better to call the check only here,
245
// than in getChild, than it is not called
246
// so often.
247
fo.check();
248
249                 fo = fo.getChild(en.nextElement());
250             }
251         }
252
253         // no next requirements or not found
254
return fo;
255     }
256
257     /** Tries to find a resource if it exists in memory.
258     * @param en enumeration of strings to scan
259     * @return found object or null
260     */

261     final FileObject findIfExists(Enumeration JavaDoc<String JavaDoc> en) {
262         Reference JavaDoc<AbstractFolder> r = findRefIfExists(en);
263
264         return (r == null) ? null : r.get();
265     }
266
267     /** Tries to find a resource if it exists in memory.
268     * @param en enumeration of strings to scan
269     * @return found object or null
270     */

271     final Reference JavaDoc<AbstractFolder> findRefIfExists(Enumeration JavaDoc<String JavaDoc> en) {
272         AbstractFolder fo = this;
273
274         while ((fo != null) && en.hasMoreElements()) {
275             if (fo.map == null) {
276                 // this object is not initialized yet
277
return null;
278             }
279
280             // try to go on
281
// lock to provide safety for getChild
282
synchronized (fo) {
283                 String JavaDoc name = en.nextElement();
284
285                 if (en.hasMoreElements()) {
286                     fo = fo.getChild(name);
287                 } else {
288                     return fo.map.get(name);
289                 }
290             }
291         }
292
293         // no next requirements or not found
294
return null;
295     }
296
297     /** Finds one child for given name .
298     * @param name the name of the child
299     * @return the file object or null if it does not exist
300     */

301     protected final AbstractFolder getChild(String JavaDoc name) {
302         return getChild(name, true);
303     }
304
305     private final AbstractFolder getChild(String JavaDoc name, boolean onlyValid) {
306         Reference JavaDoc<AbstractFolder> r = map.get(name);
307
308         if (r == null) {
309             //On OpenVMS, see if the name is stored in a different case
310
//to work around a JVM bug.
311
//
312
if (Utilities.getOperatingSystem() == Utilities.OS_VMS) {
313                 if (Character.isLowerCase(name.charAt(0))) {
314                     r = map.get(name.toUpperCase());
315                 } else {
316                     r = map.get(name.toLowerCase());
317                 }
318
319                 if (r == null) {
320                     return null;
321                 }
322             } else {
323                 return null;
324             }
325         }
326
327         AbstractFolder fo = r.get();
328
329         if (fo == null) {
330             // object does not exist => have to recreate it
331
fo = createFile(name);
332
333             if ((fo != null) && fo.isValid()) {
334                 map.put(name, (fo != null) ? createReference(fo) : null);
335             } else {
336                 if (onlyValid) {
337                     fo = null;
338                 }
339             }
340         }
341
342         return fo;
343     }
344
345     /** Get method for children array .
346     * @return array of children
347     */

348     final String JavaDoc[] getChildrenArray() {
349         return children;
350     }
351
352     /** Creates Reference. In FileSystem, which subclasses AbstractFileSystem, you can overload method
353     * createReference(FileObject fo) to achieve another type of Reference (weak, strong etc.)
354     * @param fo FileObject
355     * @return Reference to FileObject
356     */

357     protected Reference JavaDoc<AbstractFolder> createReference(AbstractFolder fo) {
358         return (new WeakReference JavaDoc<AbstractFolder>(fo));
359     }
360
361     /** Obtains enumeration of all existing subfiles.
362     */

363     final synchronized AbstractFolder[] subfiles() {
364         if (map == null) {
365             return EMPTY_ARRAY;
366         }
367
368         Iterator JavaDoc it = map.values().iterator();
369         ArrayList JavaDoc<FileObject> ll = new ArrayList JavaDoc<FileObject>(map.size() + 2);
370
371         while (it.hasNext()) {
372             Reference JavaDoc r = (Reference JavaDoc) it.next();
373
374             if (r == null) {
375                 continue;
376             }
377
378             AbstractFolder fo = (AbstractFolder) r.get();
379
380             if (fo != null /*&& (!fo.isFolder () || fo.map != null)*/ ) {
381                 // if the file object exists and either is not folder (then
382
// we have to check the time) or it is folder and it has
383
// some children
384
// => use it
385
ll.add(fo);
386             }
387         }
388
389         return ll.toArray(EMPTY_ARRAY);
390     }
391
392     final boolean isInitialized() {
393         return this.map != null;
394     }
395
396     /** Creates enumeration of existing subfiles in all tree
397     * of files.
398     *
399     * @param rec should it be recursive or not
400     * @return enumeration of AbstractFolders
401     */

402     final Enumeration JavaDoc<AbstractFolder> existingSubFiles(boolean rec) {
403         if (!rec) {
404             return Enumerations.array(subfiles());
405         } else {
406             class P implements org.openide.util.Enumerations.Processor<AbstractFolder, AbstractFolder> {
407                 public AbstractFolder process(AbstractFolder af, Collection JavaDoc<AbstractFolder> toAdd) {
408                     toAdd.addAll(Arrays.asList(af.subfiles()));
409
410                     return af;
411                 }
412             }
413
414             return Enumerations.queue(Enumerations.singleton(this), new P());
415         }
416     }
417
418     /* helper method for MFO.setAttribute. MFO can disable firing from underlaying
419      * layers. Should be reviewed in 3.4 or later
420       *@see MultiFileObject#setAttribute*/

421     abstract void setAttribute(String JavaDoc attrName, Object JavaDoc value, boolean fire)
422     throws IOException JavaDoc;
423
424     /** Retrieve file or folder contained in this folder by name.
425     * <em>Note</em> that neither file nor folder is created on disk.
426     * @param name basename of the file or folder (in this folder)
427     * @param ext extension of the file; <CODE>null</CODE> or <code>""</code>
428     * if the file should have no extension or if folder is requested
429     * @return the object representing this file or <CODE>null</CODE> if the file
430     * or folder does not exist
431     * @exception IllegalArgumentException if <code>this</code> is not a folder
432     */

433     public final synchronized FileObject getFileObject(String JavaDoc name, String JavaDoc ext) {
434         check();
435
436         if ((ext == null) || ext.equals("")) { // NOI18N
437

438             return getChild(name);
439         } else {
440             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(name.length() + 1 + ((ext == null) ? 0 : ext.length()));
441             sb.append(name).append(EXT_SEP).append(ext);
442
443             return getChild(sb.toString());
444         }
445     }
446
447     /* Refresh the contents of a folder. Rescans the list of children names.
448     */

449     public void refresh(boolean expected) {
450         if (!isInitialized() && isFolder()) {
451             return;
452         }
453
454         refresh(null, null, true, expected);
455     }
456
457     //
458
// Listeners section
459
//
460

461     /* Add new listener to this object.
462     * @param l the listener
463     */

464     public final void addFileChangeListener(FileChangeListener fcl) {
465         synchronized (EMPTY_ARRAY) {
466             if (listeners == null) {
467                 listeners = new ListenerList<FileChangeListener>();
468             }
469         }
470
471         listeners.add(fcl);
472     }
473
474     /* Remove listener from this object.
475     * @param l the listener
476     */

477     public final void removeFileChangeListener(FileChangeListener fcl) {
478         if (listeners != null) {
479             listeners.remove(fcl);
480         }
481     }
482
483     /** Fires event */
484     protected final void fileDeleted0(FileEvent fileevent) {
485         super.fireFileDeletedEvent(listeners(), fileevent);
486
487         if (fileevent.getFile().equals(this) && (parent != null)) {
488             FileEvent ev = new FileEvent(parent, fileevent.getFile(), fileevent.isExpected());
489             parent.fileDeleted0(ev);
490         }
491     }
492
493     /** Fires event */
494     protected final void fileCreated0(FileEvent fileevent, boolean isData) {
495         /*
496                 if(isData)
497                     super.fireFileDataCreatedEvent(listeners (), fileevent);
498                 else
499                     super.fireFileFolderCreatedEvent(listeners (), fileevent);
500         */

501         dispatchEvent(listeners(), fileevent);
502
503         if (fileevent.getFile().equals(this) && (parent != null)) {
504             FileEvent ev = new FileEvent(parent, fileevent.getFile(), fileevent.isExpected());
505             parent.fileCreated0(ev, isData);
506         }
507     }
508
509     /** Creates nad fires event */
510     protected final void fileCreated0(FileObject src, FileObject file, boolean expected) {
511         fileCreated0(new FileEvent(src, file, expected), false);
512     }
513
514     /** Fires event */
515     protected final void fileChanged0(FileEvent fileevent) {
516         super.fireFileChangedEvent(listeners(), fileevent);
517
518         if (fileevent.getFile().equals(this) && (parent != null)) {
519             FileEvent ev = new FileEvent(parent, fileevent.getFile(), fileevent.isExpected());
520             parent.fileChanged0(ev);
521         }
522     }
523
524     /** Fires event - but doesn`t fork events*/
525     final void fileChanged1(FileEvent fileevent) {
526         super.fireFileChangedEvent(listeners(), fileevent);
527     }
528
529     /** Fires event */
530     protected final void fileRenamed0(FileRenameEvent filerenameevent) {
531         super.fireFileRenamedEvent(listeners(), filerenameevent);
532
533         if (filerenameevent.getFile().equals(this) && (parent != null)) {
534             FileRenameEvent ev = new FileRenameEvent(
535                     parent, filerenameevent.getFile(), filerenameevent.getName(), filerenameevent.getExt(),
536                     filerenameevent.isExpected()
537                 );
538             parent.fileRenamed0(ev);
539         }
540     }
541
542     /** Fires event */
543     protected final void fileAttributeChanged0(FileAttributeEvent fileattributeevent) {
544         super.fireFileAttributeChangedEvent(listeners(), fileattributeevent);
545
546         if (fileattributeevent.getFile().equals(this) && (parent != null)) {
547             FileAttributeEvent ev = new FileAttributeEvent(
548                     parent, fileattributeevent.getFile(), fileattributeevent.getName(), fileattributeevent.getOldValue(),
549                     fileattributeevent.getNewValue(), fileattributeevent.isExpected()
550                 );
551             parent.fileAttributeChanged0(ev);
552         }
553     }
554
555     /** @return true if there is a listener
556     */

557     protected final boolean hasListeners() {
558         boolean fsHas = getFileSystem().getFCLSupport().hasListeners();
559         boolean repHas = false;
560         Repository rep = getFileSystem().getRepository();
561
562         if (rep != null) {
563             repHas = rep.getFCLSupport().hasListeners();
564         }
565
566         return (listeners != null && listeners.hasListeners()) || repHas || fsHas;
567     }
568
569     /** @return true if this folder or its parent have listeners
570     */

571     protected final boolean hasAtLeastOneListeners() {
572         return hasListeners() || ((parent != null) && parent.hasListeners());
573     }
574
575     /** @return enumeration of all listeners.
576     */

577     private final Enumeration JavaDoc<FileChangeListener> listeners() {
578         if (listeners == null) {
579             return Enumerations.empty();
580         } else {
581             return Collections.enumeration(listeners.getAllListeners());
582         }
583     }
584
585     //
586
// Refreshing the state of the object
587
//
588

589     /** Test if the file has been checked and if not, refreshes its
590     * content.
591     */

592     private final void check() {
593         if (map == null) {
594             refresh(null, null, false, false);
595
596             if (map == null) {
597                 // create empty map to mark that we are initialized
598
map = Collections.emptyMap();
599
600                 if (children == null) {
601                     children = new String JavaDoc[] { };
602                 }
603             }
604         }
605     }
606
607     /** Refresh the content of file. Ignores changes to the files provided,
608     * instead returns its file object.
609     * @param added do not notify addition of this file
610     * @param removed do not notify removing of this file
611     */

612     protected final void refresh(String JavaDoc added, String JavaDoc removed) {
613         this.refresh(added, removed, false);
614     }
615
616     /** Refresh the content of file. Ignores changes to the files provided,
617     * instead returns its file object.
618     * @param added do not notify addition of this file
619     * @param removed do not notify removing of this file
620     * @param reuseChildren a flag reuse children?
621     */

622     protected final void refresh(String JavaDoc added, String JavaDoc removed, boolean reuseChildren) {
623         if (reuseChildren && (removed != null)) {
624             String JavaDoc[] nc = new String JavaDoc[children.length];
625             System.arraycopy(children, 0, nc, 0, children.length);
626
627             for (int i = nc.length; --i >= 0;) {
628                 if (removed.equals(nc[i])) {
629                     nc[i] = null;
630
631                     break;
632                 }
633             }
634
635             refresh(added, removed, true, false, nc);
636         } else {
637             refresh(added, removed, true, false, null);
638         }
639     }
640
641     /** Method that allows subclasses to return its children.
642     *
643     * @return names (name . ext) of subfiles
644     */

645     protected abstract String JavaDoc[] list();
646
647     /** Method to create a file object for given subfile.
648     * @param name of the subfile
649     * @return the file object
650     */

651     protected abstract AbstractFolder createFile(String JavaDoc name);
652
653     /** Refresh the content of file. Ignores changes to the files provided,
654     * instead returns its file object.
655     * @param added do not notify addition of this file
656     * @param removed do not notify removing of this file
657     * @param fire true if we should fire changes
658     * @param expected true if the change has been expected by the user
659     */

660     protected void refresh(String JavaDoc added, String JavaDoc removed, boolean fire, boolean expected) {
661         this.refresh(added, removed, fire, expected, null);
662     }
663
664     void registerChild(String JavaDoc name) {
665         synchronized (this) {
666             if (map == null) {
667                 check();
668             }
669
670             Reference JavaDoc<AbstractFolder> o = map.put(name, new WeakReference JavaDoc<AbstractFolder>(null));
671
672             if (o != null) {
673                 map.put(name, o);
674             } else {
675                 String JavaDoc[] newChildren = new String JavaDoc[children.length + 1];
676                 System.arraycopy(children, 0, newChildren, 0, children.length);
677                 newChildren[children.length] = name;
678                 children = newChildren;
679             }
680         }
681     }
682
683     /** Refresh the content of file. Ignores changes to the files provided,
684     * instead returns its file object.
685     * @param added do not notify addition of this file
686     * @param removed do not notify removing of this file
687     * @param fire true if we should fire changes
688     * @param expected true if the change has been expected by the user
689     * @param list contains list of children
690     */

691     protected final void refreshFolder(
692         String JavaDoc added, String JavaDoc removed, boolean fire, boolean expected, final String JavaDoc[] list
693     ) {
694         try {
695             getFileSystem().beginAtomicAction();
696
697             // refresh of folder checks children
698
final String JavaDoc[] newChildren = getNewChildren(list);
699             final Set JavaDoc<String JavaDoc> addedNames;
700             final Map JavaDoc<String JavaDoc, AbstractFolder> removedPairs;
701
702             synchronized (this) {
703                 if ((children == null) && (newChildren == null)) {
704                     return;
705                 }
706
707                 final int initialCapacity = (newChildren != null) ? (((newChildren.length * 4) / 3) + 1) : 0;
708                 final HashMap JavaDoc<String JavaDoc, Reference JavaDoc<AbstractFolder>> newMap = new HashMap JavaDoc<String JavaDoc, Reference JavaDoc<AbstractFolder>>(initialCapacity);
709
710                 /*Just for firing event*/
711                 addedNames = new HashSet JavaDoc<String JavaDoc>(initialCapacity);
712
713                 if (newChildren != null) {
714                     final Reference JavaDoc<AbstractFolder> removedRef = ((map != null) ? map.get(removed) : null);
715
716                     for (int i = 0; i < newChildren.length; i++) {
717                         final String JavaDoc child = newChildren[i];
718                         Reference JavaDoc<AbstractFolder> foRef = null;
719
720                         if (map != null) {
721                             foRef = map.remove(child);
722
723                             if (((foRef != null) && (added != null) && (removed != null) && child.equals(removed))) {
724                                 // needs cvs checkout
725
foRef = null;
726                             }
727
728                             if ((added != null) && (removed != null) && child.equals(added)) {
729                                 foRef = removedRef;
730                             }
731
732                             if (((foRef != null) && (added == null) && (removed != null) && child.equals(removed))) {
733                                 // needs cvs checkout
734
foRef = null;
735                             }
736                         }
737
738                         if (foRef == null) {
739                             if (!child.equals(added)) {
740                                 addedNames.add(child);
741                             }
742
743                             // create new empty reference
744
foRef = new WeakReference JavaDoc<AbstractFolder>(null);
745                         }
746
747                         newMap.put(child, foRef);
748                     }
749                 }
750
751                 removedPairs = (map != null) ? dereferenceValues(map) : null;
752                 map = newMap;
753                 children = newChildren;
754             }
755
756             if (fire && (addedNames != null) && hasAtLeastOneListeners()) {
757                 // fire these files has been added
758
filesCreated(addedNames, expected);
759             }
760
761             if (fire && (removedPairs != null)) {
762                 if (removed != null) {
763                     removedPairs.remove(removed);
764                 }
765
766                 filesDeleted(removedPairs, expected);
767             }
768
769             if (
770                 fire && (added == null) && (removed == null) && !getFileSystem().isReadOnly() &&
771                     !(this instanceof MultiFileObject)
772             ) {
773                 Set JavaDoc<String JavaDoc> nameFilter = nameFilter = new HashSet JavaDoc<String JavaDoc>();
774
775                 if (addedNames != null) {
776                     nameFilter.addAll(addedNames);
777                 }
778
779                 if (removedPairs != null) {
780                     nameFilter.addAll(removedPairs.keySet());
781                 }
782
783                 refreshChildren(existingSubFiles(false), nameFilter, expected);
784             }
785         } finally {
786             getFileSystem().finishAtomicAction();
787         }
788     }
789
790     private void refreshChildren(final Enumeration JavaDoc<? extends AbstractFolder> subfiles, final Collection JavaDoc nameFilter, boolean expected) {
791         while (subfiles.hasMoreElements()) {
792             AbstractFolder child = subfiles.nextElement();
793
794             if (child.isData()) {
795                 if (!nameFilter.contains(child.getNameExt())) {
796                     child.refresh(expected);
797                 }
798             }
799         }
800     }
801
802     private void filesDeleted(final Map JavaDoc<String JavaDoc,AbstractFolder> removedToFire, final boolean expected) {
803         for (AbstractFolder fo : removedToFire.values()) {
804             fo.validFlag = false;
805
806             if (hasAtLeastOneListeners() || fo.hasAtLeastOneListeners()) {
807                 FileEvent ev = new FileEvent(fo, fo, expected);
808                 fo.fileDeleted0(ev);
809             }
810         }
811     }
812
813     private void filesCreated(final Set JavaDoc<String JavaDoc> addedToFire, final boolean expected) {
814         for (String JavaDoc s : addedToFire) {
815             AbstractFolder fo = getChild(s);
816
817             if (fo != null) {
818                 fileCreated0(this, fo, expected);
819             }
820         }
821     }
822
823     private Map JavaDoc<String JavaDoc, AbstractFolder> dereferenceValues(final Map JavaDoc<String JavaDoc, Reference JavaDoc<AbstractFolder>> map) {
824         Map JavaDoc<String JavaDoc, AbstractFolder> retVal = new HashMap JavaDoc<String JavaDoc, AbstractFolder>(map.size());
825         for (String JavaDoc name : map.keySet()) {
826             AbstractFolder child = getChild(name, false);
827
828             if (child != null) {
829                 retVal.put(name, child);
830             }
831         }
832
833         return retVal;
834     }
835
836     private String JavaDoc[] getNewChildren(final String JavaDoc[] list) {
837         String JavaDoc[] newChildren = (list != null) ? list : list();
838
839         if (isRoot() && (newChildren == null)) {
840             newChildren = new String JavaDoc[0];
841         }
842
843         if (newChildren != null) {
844             newChildren = stripNulls(newChildren);
845         }
846
847         return newChildren;
848     }
849
850     private static String JavaDoc[] stripNulls(final String JavaDoc[] children) {
851         String JavaDoc[] newChildren = children;
852         Collection JavaDoc<String JavaDoc> childrenList = new ArrayList JavaDoc<String JavaDoc>(Arrays.asList(newChildren));
853
854         for (Iterator JavaDoc<String JavaDoc> iterator = childrenList.iterator(); iterator.hasNext();) {
855             String JavaDoc child = iterator.next();
856
857             if (child == null) {
858                 iterator.remove();
859             }
860         }
861
862         if (childrenList.size() != newChildren.length) {
863             newChildren = childrenList.toArray(new String JavaDoc[childrenList.size()]);
864         }
865
866         return newChildren;
867     }
868
869     /** Refresh the content of file. Ignores changes to the files provided,
870     * instead returns its file object.
871     * @param added do not notify addition of this file
872     * @param removed do not notify removing of this file
873     * @param fire true if we should fire changes
874     * @param expected true if the change has been expected by the user
875     * @param list contains list of children
876     */

877     protected void refresh(String JavaDoc added, String JavaDoc removed, boolean fire, boolean expected, String JavaDoc[] list) {
878         if (isFolder()) {
879             refreshFolder(added, removed, fire, expected, list);
880         }
881     }
882
883     /** Notification that the output stream has been closed.
884      * @param fireFileChanged defines if FileEvent should be fired to notify about
885      * change of file after close of stream
886      */

887     protected void outputStreamClosed(boolean fireFileChanged) {
888         if (fireFileChanged) {
889             fileChanged0(new FileEvent(AbstractFolder.this));
890         }
891     }
892
893     //
894
// Serialization
895
//
896
public final Object JavaDoc writeReplace() {
897         return new Replace(this);
898     }
899
900     /* Delete this file. If the file is a folder and it is not empty then
901     * all of its contents are also recursively deleted.
902     *
903     * @param lock the lock obtained by a call to {@link #lock}
904     * @exception IOException if the file could not be deleted
905     */

906     final public void delete(FileLock lock) throws IOException JavaDoc {
907         if (isFolder()) {
908             FileObject[] fos = this.getChildren();
909
910             for (int i = 0; i < fos.length; i++) {
911                 FileObject fo = fos[i];
912                 FileLock foLock = fo.lock();
913
914                 try {
915                     fo.delete(foLock);
916                 } catch (IOException JavaDoc iex) {
917                     String JavaDoc message = NbBundle.getMessage(
918                             getClass(), "EXC_CannotDelete", //NOI18N
919

920                         // XXX use FileUtil.getFileDisplayName instead?
921
getPath(), fo.getFileSystem().getDisplayName()
922                         );
923                     ExternalUtil.annotate(iex, message); //NOI18N
924
throw iex;
925                 } finally {
926                     foLock.releaseLock();
927                 }
928             }
929         }
930
931         handleDelete(lock);
932     }
933
934     abstract void handleDelete(FileLock lock) throws IOException JavaDoc;
935
936     @SuppressWarnings JavaDoc("deprecation") // have to delegate for compat
937
public boolean canWrite() {
938         return !isReadOnly();
939     }
940
941     private static final class Replace implements Serializable JavaDoc {
942         private static final long serialVersionUID = 1L;
943         private transient FileObject f;
944         private String JavaDoc fsname;
945         private String JavaDoc path;
946         private URL JavaDoc url;
947
948         public Replace(FileObject f) {
949             this.f = f;
950         }
951
952         @SuppressWarnings JavaDoc("deprecation") // FileSystem.systemName historical part of serial form
953
private void writeObject(ObjectOutputStream JavaDoc oos)
954         throws IOException JavaDoc {
955             fsname = f.getFileSystem().getSystemName();
956             path = f.getPath();
957             url = f.getURL();
958             assert url != null : "No URL for " + path;
959             oos.defaultWriteObject();
960         }
961
962         private void readObject(ObjectInputStream JavaDoc ois)
963         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
964             ois.defaultReadObject();
965             assert fsname != null : "Should always have a non-null fsname here";
966
967             @SuppressWarnings JavaDoc("deprecation") // historical part of serial form
968
FileSystem fs = Repository.getDefault().findFileSystem(fsname);
969
970             if (fs != null) {
971                 assert path != null : "Should always have a non-null path here";
972                 f = fs.findResource(path);
973             }
974
975             if (f == null) {
976                 // Fall back to URL.
977
assert url != null : "Should always have a non-null URL here";
978
979                 f = URLMapper.findFileObject(url);
980
981                 if (f == null) {
982                     throw new FileNotFoundException JavaDoc("Could not restore: " + url); // NOI18N
983
}
984             }
985         }
986
987         public Object JavaDoc readResolve() {
988             assert f != null : "Did not read " + url;
989
990             return f;
991         }
992     }
993 }
994
Popular Tags