KickJava   Java API By Example, From Geeks To Geeks.

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


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.File JavaDoc;
23 import java.io.FileNotFoundException JavaDoc;
24 import java.io.FilterOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.io.OutputStream JavaDoc;
28 import java.io.Serializable 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.LinkedList JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.StringTokenizer JavaDoc;
38 import org.openide.util.Enumerations;
39 import org.openide.util.NbBundle;
40
41 /** This is the base for all implementations of file objects on a filesystem.
42 * Provides basic information about the object (its name, parent,
43 * whether it exists, etc.) and operations on it (move, delete, etc.).
44 *
45 * @author Jaroslav Tulach, Petr Hamernik, Ian Formanek
46 */

47 public abstract class FileObject extends Object JavaDoc implements Serializable JavaDoc {
48     /** generated Serialized Version UID */
49     static final long serialVersionUID = 85305031923497718L;
50
51     /** Get the name without extension of this file or folder.
52     * Period at first position is not considered as extension-separator
53     * For the root folder of a filesystem, this will be the empty
54     * string (the extension will also be the empty string, and the
55     * fully qualified name with any delimiters will also be the
56     * empty string).
57     * @return name of the file or folder(in its enclosing folder)
58     */

59     public abstract String JavaDoc getName();
60
61     /** Get the extension of this file or folder.
62     * Period at first position is not considered as extension-separator
63     * This is the string after the last dot of the full name, if any.
64     *
65     * @return extension of the file or folder (if any) or empty string if there is none
66     */

67     public abstract String JavaDoc getExt();
68
69     /** Renames this file (or folder).
70     * Both the new basename and new extension should be specified.
71     * <p>
72     * Note that using this call, it is currently only possible to rename <em>within</em>
73     * a parent folder, and not to do moves <em>across</em> folders.
74     * Conversely, implementing filesystems need only implement "simple" renames.
75     * If you wish to move a file across folders, you should call {@link FileUtil#moveFile}.
76     * @param lock File must be locked before renaming.
77     * @param name new basename of file
78     * @param ext new extension of file (ignored for folders)
79     */

80     public abstract void rename(FileLock lock, String JavaDoc name, String JavaDoc ext)
81     throws IOException JavaDoc;
82
83     /** Copies this file. This allows the filesystem to perform any additional
84     * operation associated with the copy. But the default implementation is simple
85     * copy of the file and its attributes
86     *
87     * @param target target folder to move this file to
88     * @param name new basename of file
89     * @param ext new extension of file (ignored for folders)
90     * @return the newly created file object representing the moved file
91     */

92     public FileObject copy(FileObject target, String JavaDoc name, String JavaDoc ext)
93     throws IOException JavaDoc {
94         if (isFolder()) {
95             throw new IOException JavaDoc(NbBundle.getBundle(FileObject.class).getString("EXC_FolderCopy"));
96         }
97
98         FileObject dest = FileUtil.copyFileImpl(this, target, name, ext);
99
100         return dest;
101     }
102
103     /** Moves this file. This allows the filesystem to perform any additional
104     * operation associated with the move. But the default implementation is encapsulated
105     * as copy and delete.
106     *
107     * @param lock File must be locked before renaming.
108     * @param target target folder to move this file to
109     * @param name new basename of file
110     * @param ext new extension of file (ignored for folders)
111     * @return the newly created file object representing the moved file
112     */

113     public FileObject move(FileLock lock, FileObject target, String JavaDoc name, String JavaDoc ext)
114     throws IOException JavaDoc {
115         if (getParent().equals(target)) {
116             // it is possible to do only rename
117
rename(lock, name, ext);
118
119             return this;
120         } else {
121             // have to do copy
122
FileObject dest = copy(target, name, ext);
123             delete(lock);
124
125             return dest;
126         }
127     }
128
129     /**
130      * Gets a textual represtentation of this <code>FileObject</code>.
131      * The precise format is not defined. In particular it is probably
132      * <em>not</em> a resource path.
133      * For that purpose use {@link #getPath} directly.
134      * <p>Typically it is useful for debugging purposes. Example of correct usage:
135      * <pre>
136      * <font class="type">FileObject</font> <font class="variable-name">fo</font> = getSomeFileObject();
137      * ErrorManager.getDefault().log(<font class="string">"Got a change from "</font> + fo);
138      * </pre>
139      * @return some representation of this file object
140      */

141     public String JavaDoc toString() {
142         String JavaDoc cname = getClass().getName();
143         String JavaDoc cnameShort = cname.substring(cname.lastIndexOf('.') + 1);
144         
145         return cnameShort + '@' + Integer.toHexString(System.identityHashCode(this)) + '[' + getPath() +
146                 ']'; // NOI18N
147
}
148
149     /** Get the full resource path of this file object starting from the filesystem root.
150      * Folders are separated with forward slashes. File extensions, if present,
151      * are included. The root folder's path is the empty string. The path of a folder
152      * never ends with a slash.
153      * <p>Subclasses are strongly encouraged to override this method.
154      * <p>Never use this to get a display name for the file! Use {@link FileUtil#getFileDisplayName}.
155      * <p>Do not use this method to find a file path on disk! Use {@link FileUtil#toFile}.
156      * @return the path, for example <samp>path/from/root.ext</samp>
157      * @see FileSystem#findResource
158      * @since 3.7
159      */

160     public String JavaDoc getPath() {
161         StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
162         constructName(sb, '/');
163
164         return sb.toString();
165     }
166
167     /** Get fully-qualified filename. Does so by walking through all folders
168     * to the root of the filesystem. Separates files with provided <code>separatorChar</code>.
169     * The extension, if present, is separated from the basename with <code>extSepChar</code>.
170     * <p><strong>Note:</strong> <samp>fo.getPath()</samp> will have the
171     * same effect as using this method with <samp>/</samp> and <samp>.</samp> (the standard
172     * path and extension delimiters).
173     * @param separatorChar char to separate folders and files
174     * @param extSepChar char to separate extension
175     * @return the fully-qualified filename
176     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
177     */

178     @Deprecated JavaDoc
179     public String JavaDoc getPackageNameExt(char separatorChar, char extSepChar) {
180         assert FileUtil.assertDeprecatedMethod();
181
182         StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
183
184         if (isRoot() || getParent().isRoot()) {
185             return getNameExt();
186         }
187
188         getParent().constructName(sb, separatorChar);
189
190         String JavaDoc ext = getExt();
191
192         if ((ext == null) || ext.equals("")) { // NOI18N
193
sb.append(separatorChar).append(getNameExt());
194         } else {
195             sb.append(separatorChar).append(getName()).append(extSepChar).append(getExt());
196         }
197
198         return sb.toString();
199     }
200
201     /** Get fully-qualified filename, but without extension.
202     * Like {@link #getPackageNameExt} but omits the extension.
203     * @param separatorChar char to separate folders and files
204     * @return the fully-qualified filename
205     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
206     */

207     @Deprecated JavaDoc
208     public String JavaDoc getPackageName(char separatorChar) {
209         assert FileUtil.assertDeprecatedMethod();
210
211         StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
212
213         if (isRoot() || getParent().isRoot()) {
214             return (isFolder()) ? getNameExt() : getName();
215         }
216
217         getParent().constructName(sb, separatorChar);
218
219         //sb.append (separatorChar).append ((isFolder ()) ? getNameExt() : getName ());
220
sb.append(separatorChar).append(getName());
221
222         return sb.toString();
223     }
224
225     /** Getter for name and extension of a file object. Dot is used
226      * as separator between name and ext.
227      * @return string name of the file in the folder (with extension)
228      */

229     public String JavaDoc getNameExt() {
230         String JavaDoc n = getName();
231         String JavaDoc e = getExt();
232
233         return ((e == null) || (e.length() == 0)) ? n : (n + '.' + e);
234     }
235
236     /** Constructs path of file.
237     * @param sb string buffer
238     * @param sepChar separator character
239     */

240     private void constructName(StringBuilder JavaDoc sb, char sepChar) {
241         FileObject parent = getParent();
242
243         if ((parent != null) && !parent.isRoot()) {
244             parent.constructName(sb, sepChar);
245             sb.append(sepChar);
246         }
247
248         sb.append(getNameExt());
249     }
250
251     /** Get the filesystem containing this file.
252     * <p>
253     * Note that it may be possible for a stale file object to exist which refers to a now-defunct filesystem.
254     * If this is the case, this method will throw an exception.
255     * @return the filesystem
256     * @exception FileStateInvalidException if the reference to the file
257     * system has been lost (e.g., if the filesystem was deleted)
258     */

259     public abstract FileSystem getFileSystem() throws FileStateInvalidException;
260
261     /** Get parent folder.
262     * The returned object will satisfy {@link #isFolder}.
263     *
264     * @return the parent folder or <code>null</code> if this object {@link #isRoot}.
265     */

266     public abstract FileObject getParent();
267
268     /** Test whether this object is a folder.
269     * @return true if the file object is a folder (i.e., can have children)
270     */

271     public abstract boolean isFolder();
272
273     /**
274     * Get last modification time.
275     * @return the date
276     */

277     public abstract java.util.Date JavaDoc lastModified();
278
279     /** Test whether this object is the root folder.
280     * The root should always be a folder.
281     * @return true if the object is the root of a filesystem
282     */

283     public abstract boolean isRoot();
284
285     /** Test whether this object is a data object.
286     * This is exclusive with {@link #isFolder}.
287     * @return true if the file object represents data (i.e., can be read and written)
288     */

289     public abstract boolean isData();
290
291     /* Test whether the file is valid. The file can be invalid if it has been deserialized
292     * and the file no longer exists on disk; or if the file has been deleted.
293     *
294     * @return true if the file object is valid
295     */

296     public abstract boolean isValid();
297
298     /** Test whether there is a file with the same basename and only a changed extension in the same folder.
299     * The default implementation asks this file's parent using {@link #getFileObject(String name, String ext)}.
300     *
301     * @param ext the alternate extension
302     * @return true if there is such a file
303     */

304     public boolean existsExt(String JavaDoc ext) {
305         FileObject parent = getParent();
306
307         return (parent != null) && (parent.getFileObject(getName(), ext) != null);
308     }
309
310     /** Delete this file. If the file is a folder and it is not empty then
311     * all of its contents are also recursively deleted.
312     *
313     * @param lock the lock obtained by a call to {@link #lock}
314     * @exception IOException if the file could not be deleted
315     */

316     public abstract void delete(FileLock lock) throws IOException JavaDoc;
317
318     /** Delete this file. If the file is a folder and it is not empty then
319     * all of its contents are also recursively deleted. FileObject is locked
320     * before delete and finally is this lock released.
321     *
322     * @exception IOException if the file could not be deleted or
323     * FileAlreadyLockedException if the file is already locked {@link #lock}
324     * @since 1.15
325     */

326     public final void delete() throws IOException JavaDoc {
327         FileLock lock = lock();
328
329         try {
330             delete(lock);
331         } finally {
332             lock.releaseLock();
333         }
334     }
335
336     /** Get the file attribute with the specified name.
337     * @param attrName name of the attribute
338     * @return appropriate (serializable) value or <CODE>null</CODE> if the attribute is unset (or could not be properly restored for some reason)
339     */

340     abstract public Object JavaDoc getAttribute(String JavaDoc attrName);
341
342     /** Set the file attribute with the specified name.
343     * @param attrName name of the attribute
344     * @param value new value or <code>null</code> to clear the attribute. Must be serializable, although particular filesystems may or may not use serialization to store attribute values.
345     * @exception IOException if the attribute cannot be set. If serialization is used to store it, this may in fact be a subclass such as {@link java.io.NotSerializableException}.
346     */

347     abstract public void setAttribute(String JavaDoc attrName, Object JavaDoc value)
348     throws IOException JavaDoc;
349
350     /** Get all file attribute names for this file.
351     * @return enumeration of keys (as strings)
352     */

353     abstract public Enumeration JavaDoc<String JavaDoc> getAttributes();
354
355     /** Test whether this file has the specified extension.
356     * @param ext the extension the file should have
357     * @return true if the text after the last period (<code>.</code>) is equal to the given extension
358     */

359     public final boolean hasExt(String JavaDoc ext) {
360         if (isHasExtOverride()) {
361             return hasExtOverride(ext);
362         }
363
364         return getExt().equals(ext);
365     }
366
367     /** Overriden in AbstractFolder */
368     boolean isHasExtOverride() {
369         return false;
370     }
371
372     /** Overridden in AbstractFolder */
373     boolean hasExtOverride(String JavaDoc ext) {
374         return false;
375     }
376
377     /** Add new listener to this object.
378     * @param fcl the listener
379     */

380     public abstract void addFileChangeListener(FileChangeListener fcl);
381
382     /** Remove listener from this object.
383     * @param fcl the listener
384     */

385     public abstract void removeFileChangeListener(FileChangeListener fcl);
386
387     /** Fire data creation event.
388     * @param en listeners that should receive the event
389     * @param fe the event to fire in this object
390     */

391     protected void fireFileDataCreatedEvent(Enumeration JavaDoc<FileChangeListener> en, FileEvent fe) {
392         dispatchEvent(FCLSupport.Op.DATA_CREATED, en, fe);
393     }
394
395     /** Fire folder creation event.
396     * @param en listeners that should receive the event
397     * @param fe the event to fire in this object
398     */

399     protected void fireFileFolderCreatedEvent(Enumeration JavaDoc<FileChangeListener> en, FileEvent fe) {
400         dispatchEvent(FCLSupport.Op.FOLDER_CREATED, en, fe);
401     }
402
403     /** Fire file change event.
404     * @param en listeners that should receive the event
405     * @param fe the event to fire in this object
406     */

407     protected void fireFileChangedEvent(Enumeration JavaDoc<FileChangeListener> en, FileEvent fe) {
408         dispatchEvent(FCLSupport.Op.FILE_CHANGED, en, fe);
409     }
410
411     /** Fire file deletion event.
412     * @param en listeners that should receive the event
413     * @param fe the event to fire in this object
414     */

415     protected void fireFileDeletedEvent(Enumeration JavaDoc<FileChangeListener> en, FileEvent fe) {
416         dispatchEvent(FCLSupport.Op.FILE_DELETED, en, fe);
417     }
418
419     /** Fire file attribute change event.
420     * @param en listeners that should receive the event
421     * @param fe the event to fire in this object
422     */

423     protected void fireFileAttributeChangedEvent(Enumeration JavaDoc<FileChangeListener> en, FileAttributeEvent fe) {
424         dispatchEvent(FCLSupport.Op.ATTR_CHANGED, en, fe);
425     }
426
427     /** Fire file rename event.
428     * @param en listeners that should receive the event
429     * @param fe the event to fire in this object
430     */

431     protected void fireFileRenamedEvent(Enumeration JavaDoc<FileChangeListener> en, FileRenameEvent fe) {
432         dispatchEvent(FCLSupport.Op.FILE_RENAMED, en, fe);
433     }
434
435     /** Puts the dispatch event into the filesystem.
436     */

437     private final void dispatchEvent(FCLSupport.Op op, Enumeration JavaDoc<FileChangeListener> en, FileEvent fe) {
438         try {
439             FileSystem fs = getFileSystem();
440             fs.dispatchEvent(new ED(op, en, fe));
441         } catch (FileStateInvalidException ex) {
442             // no filesystem, no notification
443
}
444     }
445
446     final void dispatchEvent(Enumeration JavaDoc<FileChangeListener> en, FileEvent fe) {
447         try {
448             getFileSystem().dispatchEvent(new ED(en, fe));
449         } catch (FileStateInvalidException ex) {
450             // no filesystem, no notification
451
}
452     }
453
454     /** Get the MIME type of this file.
455     * The MIME type identifies the type of the file's contents and should be used in the same way as in the <B>Java
456     * Activation Framework</B> or in the {@link java.awt.datatransfer} package.
457     * <P>
458     * The default implementation calls {@link FileUtil#getMIMEType}.
459     * (As a fallback return value, <code>content/unknown</code> is used.)
460     * @return the MIME type textual representation, e.g. <code>"text/plain"</code>; never <code>null</code>
461     */

462     public String JavaDoc getMIMEType() {
463         return FileUtil.getMIMETypeOrDefault(this);
464     }
465
466     /** Get the size of the file.
467     * @return the size of the file in bytes or zero if the file does not contain data (does not
468     * exist or is a folder).
469     */

470     public abstract long getSize();
471
472     /** Get input stream.
473     * @return an input stream to read the contents of this file
474     * @exception FileNotFoundException if the file does not exists, is a folder
475     * rather than a regular file or is invalid
476     */

477     public abstract InputStream JavaDoc getInputStream() throws FileNotFoundException JavaDoc;
478
479     /** Get output stream.
480     * @param lock the lock that belongs to this file (obtained by a call to
481     * {@link #lock})
482     * @return output stream to overwrite the contents of this file
483     * @exception IOException if an error occures (the file is invalid, etc.)
484     */

485     public abstract OutputStream JavaDoc getOutputStream(FileLock lock)
486     throws IOException JavaDoc;
487
488     /** Get output stream.
489      * @return output stream to overwrite the contents of this file
490      * @throws IOException if an error occurs (the file is invalid, etc.)
491      * @throws FileAlreadyLockedException if the file is already locked
492      * @since 6.6
493      */

494     public final OutputStream JavaDoc getOutputStream() throws FileAlreadyLockedException, IOException JavaDoc {
495         final FileLock lock = lock();
496         final OutputStream JavaDoc os;
497         try {
498             os = getOutputStream(lock);
499             return new FilterOutputStream JavaDoc(os) {
500                 public void close() throws IOException JavaDoc {
501                     try {
502                         super.close();
503                         lock.releaseLock();
504                     } catch(IOException JavaDoc iex) {
505                         if (lock.isValid()) {
506                             lock.releaseLock();
507                         }
508                         throw iex;
509                     }
510                 }
511             };
512         } catch(IOException JavaDoc iex) {
513             if (lock.isValid()) {
514                 lock.releaseLock();
515             }
516             throw iex;
517         }
518     }
519
520     
521     /** Lock this file.
522     * @return lock that can be used to perform various modifications on the file
523     * @throws FileAlreadyLockedException if the file is already locked
524     * @throws UserQuestionException in case when the lock cannot be obtained now,
525     * but the underlaying implementation is able to do it after some
526     * complex/dangerous/long-lasting operation and request confirmation
527     * from the user
528     *
529     */

530     public abstract FileLock lock() throws IOException JavaDoc;
531
532     /** Indicate whether this file is important from a user perspective.
533     * This method allows a filesystem to distingush between important and
534     * unimportant files when this distinction is possible.
535     * <P>
536     * <em>For example:</em> Java sources have important <code>.java</code> files and
537     * unimportant <code>.class</code> files. If the filesystem provides
538     * an "archive" feature it should archive only <code>.java</code> files.
539     * @param b true if the file should be considered important
540     * @deprecated No longer used. Instead use
541     * <a HREF="@PROJECTS/QUERIES@/org/netbeans/api/queries/SharabilityQuery.html"><code>SharabilityQuery</code></a>.
542     */

543     @Deprecated JavaDoc
544     public abstract void setImportant(boolean b);
545
546     /** Get all children of this folder (files and subfolders). If the file does not have children
547     * (does not exist or is not a folder) then an empty array should be returned. No particular order is assumed.
548     *
549     * @return array of direct children
550     * @see #getChildren(boolean)
551     * @see #getFolders
552     * @see #getData
553     */

554     public abstract FileObject[] getChildren();
555
556     /** Enumerate all children of this folder. If the children should be enumerated
557     * recursively, first all direct children are listed; then children of direct subfolders; and so on.
558     *
559     * @param rec whether to enumerate recursively
560     * @return enumeration of type <code>FileObject</code>
561     */

562     public Enumeration JavaDoc<? extends FileObject> getChildren(final boolean rec) {
563         class WithChildren implements Enumerations.Processor<FileObject, FileObject> {
564             public FileObject process(FileObject fo, Collection JavaDoc<FileObject> toAdd) {
565                 if (rec && fo.isFolder()) {
566                     toAdd.addAll(Arrays.asList(fo.getChildren()));
567                 }
568
569                 return fo;
570             }
571         }
572
573         return Enumerations.queue(Enumerations.array(getChildren()), new WithChildren());
574     }
575
576     /** Enumerate the subfolders of this folder.
577     * @param rec whether to recursively list subfolders
578     * @return enumeration of type <code>FileObject</code> (satisfying {@link #isFolder})
579     */

580     public Enumeration JavaDoc<? extends FileObject> getFolders(boolean rec) {
581         return Enumerations.filter(getChildren(rec), new OnlyFolders(true));
582     }
583
584     /** Enumerate all data files in this folder.
585     * @param rec whether to recursively search subfolders
586     * @return enumeration of type <code>FileObject</code> (satisfying {@link #isData})
587     */

588     public Enumeration JavaDoc<? extends FileObject> getData(boolean rec) {
589         return Enumerations.filter(getChildren(rec), new OnlyFolders(false));
590     }
591
592     /** Retrieve file or folder contained in this folder by name.
593     * <em>Note</em> that neither file nor folder is created on disk.
594     * @param name basename of the file or folder (in this folder)
595     * @param ext extension of the file; <CODE>null</CODE> or <code>""</code>
596     * if the file should have no extension or if folder is requested
597     * @return the object representing this file or <CODE>null</CODE> if the file
598     * or folder does not exist
599     * @exception IllegalArgumentException if <code>this</code> is not a folder
600     */

601     public abstract FileObject getFileObject(String JavaDoc name, String JavaDoc ext);
602
603     /** Retrieve file or folder relative to a current folder, with a given relative path.
604     * <em>Note</em> that neither file nor folder is created on disk. This method isn't final since revision 1.93.
605     * @param relativePath is just basename of the file or (since 4.16) the relative path delimited by '/'
606     * @return the object representing this file or <CODE>null</CODE> if the file
607     * or folder does not exist
608     * @exception IllegalArgumentException if <code>this</code> is not a folder
609     */

610     public FileObject getFileObject(String JavaDoc relativePath) {
611         if (relativePath.startsWith("/")) {
612             relativePath = relativePath.substring(1);
613         }
614
615         FileObject myObj = this;
616         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(relativePath, "/");
617
618         while ((myObj != null) && st.hasMoreTokens()) {
619             String JavaDoc nameExt = st.nextToken();
620             myObj = myObj.getFileObject(nameExt, null);
621         }
622
623         return myObj;
624     }
625
626     /**
627      * Create a new folder below this one with the specified name.
628      * Fires {@link FileChangeListener#fileFolderCreated}.
629      *
630      * @param name the name of folder to create. Periods in name are allowed (but no slashes).
631      * @return the new folder
632      * @exception IOException if the folder cannot be created (e.g. already exists), or if <code>this</code> is not a folder
633      * @see FileUtil#createFolder
634      */

635     public abstract FileObject createFolder(String JavaDoc name)
636     throws IOException JavaDoc;
637
638     /**
639      * Create new data file in this folder with the specified name.
640      * Fires {@link FileChangeListener#fileDataCreated}.
641      *
642      * @param name the name of data object to create (can contain a period, but no slashes)
643      * @param ext the extension of the file (or <code>null</code> or <code>""</code>)
644      * @return the new data file object
645      * @exception IOException if the file cannot be created (e.g. already exists), or if <code>this</code> is not a folder
646      * @see FileUtil#createData
647      */

648     public abstract FileObject createData(String JavaDoc name, String JavaDoc ext)
649     throws IOException JavaDoc;
650
651     /**
652      * Create new data file in this folder with the specified name.
653      * Fires {@link FileChangeListener#fileDataCreated}.
654      *
655      * @param name the name of data object to create (can contain a period, but no slashes)
656      * @return the new data file object
657      * @exception IOException if the file cannot be created (e.g. already exists), or if <code>this</code> is not a folder
658      * @since 1.17
659      * @see FileUtil#createData
660      */

661     public FileObject createData(String JavaDoc name) throws IOException JavaDoc {
662         return createData(name, ""); // NOI18N
663
}
664
665     /** Test whether this file can be written to or not.
666      * <P>
667      * The value returned from this method should indicate the capabilities of the
668      * file from the point of view of users of the FileObject's API, the actual
669      * state of the file on a disk does not matter if the implementation of the
670      * filesystem can change it when requested.
671      * <P>
672      * The result returned from this method should be tight together with
673      * the expected behaviour of <code>getOutputStream</code>. If it is
674      * likely that the method successfully returns a stream that can be
675      * written to, let the <code>isReadOnly</code> return <code>false</code>.
676      * <P>
677      * Also other fileobject methods like <code>delete</code>
678      * are suggested to be connected to result of this method. If not
679      * read only, then it can be deleted, etc.
680      * <p>
681      * It is a good idea to call this method before attempting to perform any
682      * operation on the FileObject that might throw an IOException simply
683      * because it is read-only. If isReadOnly returns true, the operation may
684      * be skipped, or the user notified that it cannot be done.
685      * <em>However</em> it is often desirable for the user to be able to
686      * continue the operation in case the filesystem supports making a file
687      * writable. In this case calling code should:
688      * <ol>
689      * <li>Call {@link #lock} and catch any exception thrown.
690      * <li>Then:
691      * <ul>
692      * <li>If no exception is thrown, proceed with the operation.
693      * <li>If a <code>UserQuestionException</code> is thrown,
694      * call {@link org.openide.util.UserQuestionException#confirmed} on it
695      * (asynchronously - do not block any important threads). If <code>true</code>,
696      * proceed with the operation. If <code>false</code>, exit.
697      * If an <code>IOException</code> is thrown, notify it and exit.
698      * <li>If another <code>IOException</code> is thrown, call {@link #isReadOnly}.
699      * If <code>true</code>, ignore the exception (it is expected).
700      * If <code>false</code>, notify it.
701      * </ul>
702      * In either case, exit.
703      * </ol>
704      * <p>
705      *
706      * @return <CODE>true</CODE> if file is read-only
707      * @deprecated Please use the {@link #canWrite}.
708      */

709     @Deprecated JavaDoc
710     public abstract boolean isReadOnly();
711
712     /**
713      * Tests if this file can be written to.
714      * <P>
715      * The default implementation simply uses <code> java.io.File.canWrite </code>
716      * if there exists conversion to <code> java.io.File</code> (see {@link FileUtil#toFile}).
717      * If conversion is not possible, then deprecated method {@link #isReadOnly} is used.
718      * @return true if this file can be written, false if not.
719      * @since 3.31
720      */

721     public boolean canWrite() {
722         File JavaDoc f = FileUtil.toFile(this);
723
724         if (f != null) {
725             return f.canWrite();
726         }
727
728         return !isReadOnly();
729     }
730
731     /**
732      * Tests if this file can be read.
733      * <P>
734      * The default implementation simply uses <code> java.io.File.canRead </code>
735      * if there exists conversion to <code> java.io.File</code> (see {@link FileUtil#toFile}).
736      * If conversion is not possible, then <code>true </code> is returned.
737      * @return true if this file can be read, false if not.
738      * @since 3.31
739      */

740     public boolean canRead() {
741         File JavaDoc f = FileUtil.toFile(this);
742
743         if (f != null) {
744             return f.canRead();
745         }
746
747         return true;
748     }
749
750     /** Should check for external modifications. For folders it should reread
751     * the content of disk, for data file it should check for the last
752     * time the file has been modified.
753     *
754     * @param expected should the file events be marked as expected change or not?
755     * @see FileEvent#isExpected
756     */

757     public void refresh(boolean expected) {
758     }
759
760     /** Should check for external modifications. For folders it should reread
761     * the content of disk, for data file it should check for the last
762     * time the file has been modified.
763     * <P>
764     * The file events are marked as unexpected.
765     */

766     public void refresh() {
767         refresh(false);
768     }
769
770     /** Get URL that can be used to access this file.
771      * If the file object does not correspond to a disk file or JAR entry,
772      * the URL will only be usable within NetBeans as it uses a special protocol handler.
773      * Otherwise an attempt is made to produce an external URL.
774     * @return URL of this file object
775     * @exception FileStateInvalidException if the file is not valid
776      * @see URLMapper#findURL
777      * @see URLMapper#INTERNAL
778     */

779     public final URL JavaDoc getURL() throws FileStateInvalidException {
780         // XXX why does this still throw FSIE? need not
781
return URLMapper.findURL(this, URLMapper.INTERNAL);
782     }
783
784     /**
785      * Tests if file really exists or is missing. Some operation on it may be restricted.
786      * @return true indicates that the file is missing.
787      * @since 1.9
788      */

789     public boolean isVirtual() {
790         return false;
791     }
792
793     /** Listeners registered from MultiFileObject are considered as priority
794      * listeners.
795      */

796     static boolean isPriorityListener(FileChangeListener fcl) {
797         if (fcl instanceof PriorityFileChangeListener) {
798             return true;
799         } else {
800             return false;
801         }
802     }
803
804     interface PriorityFileChangeListener extends FileChangeListener {}
805
806     private class ED extends FileSystem.EventDispatcher {
807         private FCLSupport.Op op;
808         private Enumeration JavaDoc<FileChangeListener> en;
809         final private List JavaDoc<FileChangeListener> fsList;
810         final private List JavaDoc<FileChangeListener> repList;
811         
812         
813         private FileEvent fe;
814
815         public ED(FCLSupport.Op op, Enumeration JavaDoc<FileChangeListener> en, FileEvent fe) {
816             this.op = op;
817             this.en = en;
818             this.fe = fe;
819             FileSystem fs = null;
820             try {
821                 fs = this.fe.getFile().getFileSystem();
822             } catch (FileStateInvalidException ex) {
823                 ExternalUtil.exception(ex);
824             }
825             ListenerList<FileChangeListener> fsll = (fs != null) ? fs.getFCLSupport().listeners : null;
826             ListenerList<FileChangeListener> repll = (fs != null && fs.getRepository() != null) ? fs.getRepository().getFCLSupport().listeners : null;
827             fsList = (fsll != null) ? new ArrayList JavaDoc<FileChangeListener>(fsll.getAllListeners()) :
828                 new ArrayList JavaDoc<FileChangeListener>();
829             repList = (repll != null) ? new ArrayList JavaDoc<FileChangeListener>(repll.getAllListeners()) :
830                 new ArrayList JavaDoc<FileChangeListener>();
831             
832         }
833
834         public ED(Enumeration JavaDoc<FileChangeListener> en, FileEvent fe) {
835             this(null, en, fe);
836         }
837
838         /** @param onlyPriority if true then invokes only priority listeners
839          * else all listeners are invoked.
840          */

841         protected void dispatch(boolean onlyPriority) {
842             if (this.op == null) {
843                 this.op = fe.getFile().isFolder() ? FCLSupport.Op.FOLDER_CREATED : FCLSupport.Op.DATA_CREATED;
844             }
845
846             LinkedList JavaDoc<FileChangeListener> newEnum = new LinkedList JavaDoc<FileChangeListener>(); // later lazy
847

848             while (en.hasMoreElements()) {
849                 FileChangeListener fcl = en.nextElement();
850
851                 if (onlyPriority && !isPriorityListener(fcl)) {
852                     newEnum.add(fcl);
853
854                     continue;
855                 }
856                 FCLSupport.dispatchEvent(fcl, fe, op);
857             }
858
859             if (onlyPriority) {
860                 this.en = Collections.enumeration(newEnum);
861             }
862
863             /** FileEvents are forked in may cases. But FileEvents fired from
864              * FileSystem and from Repository mustn`t be forked.
865              */

866             FileObject fo = fe.getFile();
867             boolean transmit = false;
868             if (fo != null) {
869                 switch (op) {
870                     case FILE_CHANGED:
871                         transmit = fo.equals(fe.getSource());
872                         break;
873                     default:
874                         transmit = !fo.equals(fe.getSource());
875                 }
876                 
877             }
878
879             if (!en.hasMoreElements() && transmit && !onlyPriority) {
880                 FileSystem fs = null;
881                 Repository rep = null;
882
883                 try {
884                     fs = fe.getFile().getFileSystem();
885                     rep = fs.getRepository();
886                 } catch (FileStateInvalidException fsix) {
887                     return;
888                 }
889                 if (fs != null && fsList != null) {
890                     for (FileChangeListener fcl : fsList) {
891                         fs.getFCLSupport().dispatchEvent(fcl, fe, op);
892                     }
893                 }
894
895
896                 if (rep != null && repList != null) {
897                     for (FileChangeListener fcl : repList) {
898                         rep.getFCLSupport().dispatchEvent(fcl, fe, op);
899                     }
900                 }
901             }
902         }
903
904         protected void setAtomicActionLink(EventControl.AtomicActionLink propID) {
905             fe.setAtomicActionLink(propID);
906         }
907     }
908
909     /** Filters folders or data files.
910      */

911     private static final class OnlyFolders implements Enumerations.Processor<FileObject, FileObject> {
912         private boolean folders;
913
914         public OnlyFolders(boolean folders) {
915             this.folders = folders;
916         }
917
918         public FileObject process(FileObject obj, Collection JavaDoc<FileObject> coll) {
919             FileObject fo = obj;
920
921             if (folders) {
922                 return fo.isFolder() ? fo : null;
923             } else {
924                 return fo.isData() ? fo : null;
925             }
926         }
927     }
928      // end of OnlyFolders
929
}
930
Popular Tags