View Javadoc

1   /*
2    * Copyright (c) 2005 The University of Reading
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    * 1. Redistributions of source code must retain the above copyright
9    *    notice, this list of conditions and the following disclaimer.
10   * 2. Redistributions in binary form must reproduce the above copyright
11   *    notice, this list of conditions and the following disclaimer in the
12   *    documentation and/or other materials provided with the distribution.
13   * 3. Neither the name of the University of Reading, nor the names of the
14   *    authors or contributors may be used to endorse or promote products
15   *    derived from this software without specific prior written permission.
16   * 
17   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27   */
28  
29  package uk.ac.rdg.resc.jstyx.client;
30  
31  import java.io.File;
32  import java.io.FileFilter;
33  import java.io.FilenameFilter;
34  import java.io.IOException;
35  import java.util.ArrayList;
36  
37  import org.apache.log4j.Logger;
38  
39  import uk.ac.rdg.resc.jstyx.client.CStyxFile;
40  import uk.ac.rdg.resc.jstyx.StyxException;
41  
42  /***
43   * Wraps a CStyxFile as a java.io.File. This allows Styx servers to be browsed
44   * by Java-based filesystem viewers
45   *
46   * @author Jon Blower
47   * $Revision: 259 $
48   * $Date: 2005-05-23 17:48:23 +0100 (Mon, 23 May 2005) $
49   * $Log$
50   * Revision 1.3  2005/05/23 16:48:17  jonblower
51   * Overhauled CStyxFile (esp. asynchronous methods) and StyxConnection (added cache of CStyxFiles)
52   *
53   * Revision 1.2  2005/03/11 13:58:25  jonblower
54   * Merged MINA-Test_20059309 into main line of development
55   *
56   * Revision 1.1.2.1  2005/03/11 08:29:52  jonblower
57   * Moved to log4j logging system (from apache commons logging)
58   *
59   * Revision 1.1  2005/03/07 08:27:51  jonblower
60   * Initial import
61   *
62   */
63  public class FileWrapper extends File
64  {
65      private static final Logger log = Logger.getLogger(FileWrapper.class);
66      
67      private CStyxFile file;
68      
69      /***
70       * Creates a new instance of FileWrapper that wraps the given CStyxFile.
71       * @todo What happens if the file isn't connected to an open connection yet?
72       */
73      public FileWrapper(CStyxFile file)
74      {
75          super(file.getPath());
76          this.file = file;
77          log.debug("Created FileWrapper(" + file.getPath() + ")");
78      }
79      
80      /***
81       * @return the CStyxFile that this FileWrapper wraps
82       */
83      public CStyxFile getCStyxFile()
84      {
85          return this.file;
86      }
87      
88      /***
89       * Gets the name of the file, i.e. the last part of the path
90       */
91      public String getName()
92      {
93          return this.file.getName();
94      }
95      
96      /***
97       * Gets the full path of the file. Makes sure that "/" is used as the separator
98       */
99      public String getPath()
100     {
101         return this.file.getPath();
102     }
103     
104     /***
105      * @return a string representing the parent of this file, or null if this
106      * is the root directory
107      */
108     public String getParent()
109     {
110         log.debug("Called getParent() for " + this.getPath());
111         String path = this.file.getPath();
112         if (path.endsWith("/"))
113         {
114             path = path.substring(0, path.length() - 1);
115         }
116         int lastSlash = path.lastIndexOf("/");
117         if (lastSlash == -1)
118         {
119             // This is the root directory
120             return null;
121         }
122         else
123         {
124             // Return the path up until (and including) the last slash
125             return path.substring(0, lastSlash);
126         }
127     }
128     
129     /***
130      * @return the parent of this FileWrapper as another FileWrapper, or null
131      * if this file does not have a parent
132      */
133     public File getParentFile()
134     {
135         log.debug("Called getParentFile() for " + this.getPath());
136         String parentPath = this.getParent();
137         if (parentPath == null)
138         {
139             return null;
140         }
141         if (parentPath.equals(this.getPath()))
142         {
143             // This is the root directory
144             return null;
145         }
146         else
147         {
148             CStyxFile newFile = this.file.getConnection().getFile(parentPath);
149             return new FileWrapper(newFile);
150         }
151     }
152     
153     /***
154      * @return true if this path starts with a slash (always return true
155      * since CStyxFile always stores the full pathname)
156      */
157     public boolean isAbsolute()
158     {
159         if (!this.getPath().startsWith("/"))
160         {
161             log.warn("Path " + this.getPath() + " is not absolute");
162         }
163         return true;
164     }
165     
166     /***
167      * @return the absolute pathname of this file. Simply returns this.getPath()
168      * since pathnames are always absolute.
169      */
170     public String getAbsolutePath()
171     {
172         return this.getPath();
173     }
174     
175     /***
176      * @return a FileWrapper representing the absolute pathname. Simply returns
177      * this object, since pathnames are always absolute
178      */
179     public File getAbsoluteFile()
180     {
181         return this;
182     }
183     
184     /***
185      * @return the canonical filename, i.e. the unique filename after removing
186      * . and .. parts of the path.  Simply returns the absolute path.
187      */
188     public String getCanonicalPath() throws IOException
189     {
190         return this.getAbsolutePath();
191     }
192     
193     /***
194      * @return a FileWrapper that represents the canonical filename. Simply
195      * returns the absolute File (i.e. this object)
196      */
197     public File getCanonicalFile() throws IOException
198     {
199         return this.getAbsoluteFile();
200     }
201     
202     /***
203      * Tests whether this FileWrapper wraps a directory
204      */
205     public boolean isDirectory()
206     {
207         try
208         {
209             return this.file.isDirectory();
210         }
211         catch(StyxException se)
212         {
213             log.error(se.getMessage());
214             return false;
215         }
216     }
217     
218     /***
219      * Tests whether this FileWrapper wraps a normal file (i.e. not a directory)
220      * @todo Should test that it's not an auth file, append-only, exclusive etc
221      */
222     public boolean isFile()
223     {
224         return !this.isDirectory();
225     }
226     
227     /***
228      * @return the length of the file in bytes
229      */
230     public long length()
231     {
232         try
233         {
234             return this.file.getLength();
235         }
236         catch(StyxException se)
237         {
238             log.error(se.getMessage());
239             return 0;
240         }
241     }
242     
243     /***
244      * @return The time that the file was last modified, in milliseconds
245      * since the epoch
246      */
247     public long lastModified()
248     {
249         try
250         {
251             return this.file.getLastModified().getTime();
252         }
253         catch(StyxException se)
254         {
255             log.error(se.getMessage());
256             return 0;
257         }
258     }
259     
260     /***
261      * @return Array of strings naming the files and directories in the directory
262      * that this FileWrapper represents. Returns null if this is not a directory.
263      */
264     public String[] list()
265     {
266         log.debug("Called (String[])list() for " + this.getPath());
267         try
268         {
269             CStyxFile[] files = this.file.getChildren();
270             if (files == null)
271             {
272                 return null;
273             }
274             String[] filenames = new String[files.length];
275             for (int i = 0; i < files.length; i++)
276             {
277                 filenames[i] = files[i].getPath();
278             }
279             return filenames;
280         }
281         catch(StyxException se)
282         {
283             log.error(se.getMessage());
284             return null;
285         }
286     }
287     
288     /***
289      * Returns an array of abstract pathnames denoting the files and
290      * directories in the directory denoted by this abstract pathname that
291      * satisfy the specified filter.
292      */
293     public String[] list(FilenameFilter filter)
294     {
295         log.debug("Called (String[])list(FilenameFilter) for " + this.getPath());
296         try
297         {
298             CStyxFile[] files = this.file.getChildren();
299             if (files == null)
300             {
301                 return null;
302             }
303             ArrayList v = new ArrayList();
304             for (int i = 0; i < files.length; i++)
305             {
306                 String name = files[i].getPath();
307                 if ((filter == null) || filter.accept(this, name))
308                 {
309                     v.add(name);
310                 }
311             }
312             return (String[])(v.toArray(new String[0]));
313         }
314         catch(StyxException se)
315         {
316             log.error(se.getMessage());
317             return null;
318         }
319     }
320     
321     /***
322      * Returns an array of FileWrappers denoting the files in this
323      * directory.
324      */
325     public File[] listFiles()
326     {
327         log.debug("Called (File[])listFiles() for " + this.getPath());
328 	try
329         {
330             CStyxFile[] files = this.file.getChildren();
331             if (files == null)
332             {
333                 return null;
334             }
335             FileWrapper[] wrappers = new FileWrapper[files.length];
336             for (int i = 0; i < files.length; i++)
337             {
338                 wrappers[i] = new FileWrapper(files[i]);
339             }
340             return wrappers;
341         }
342         catch(StyxException se)
343         {
344             log.error(se.getMessage());
345             return null;
346         }
347     }
348     
349     /***
350      * Returns an array of abstract pathnames denoting the files and
351      * directories in the directory denoted by this abstract pathname that
352      * satisfy the specified filter.
353      */
354     public File[] listFiles(FilenameFilter filter)
355     {
356         log.debug("Called (File[])listFiles(FilenameFilter) for " + this.getPath());
357         try
358         {
359             CStyxFile[] files = this.file.getChildren();
360             if (files == null)
361             {
362                 return null;
363             }
364             ArrayList v = new ArrayList();
365             for (int i = 0; i < files.length; i++)
366             {
367                 String name = files[i].getPath();
368                 if ((filter == null) || filter.accept(this, name))
369                 {
370                     v.add(new FileWrapper(files[i]));
371                 }
372             }
373             return (FileWrapper[])(v.toArray(new FileWrapper[0]));
374         }
375         catch(StyxException se)
376         {
377             log.error(se.getMessage());
378             return null;
379         }
380     }
381     
382     /***
383      * Returns an array of abstract pathnames denoting the files and
384      * directories in the directory denoted by this abstract pathname that
385      * satisfy the specified filter.
386      */
387     public File[] listFiles(FileFilter filter)
388     {
389         log.debug("Called (File[])listFiles(FileFilter) for " + this.getPath());
390         try
391         {
392             CStyxFile[] files = this.file.getChildren();
393             if (files == null)
394             {
395                 return null;
396             }
397             ArrayList v = new ArrayList();
398             for (int i = 0; i < files.length; i++)
399             {
400                 FileWrapper wrapper = new FileWrapper(files[i]);
401                 if ((filter == null) || filter.accept(wrapper))
402                 {
403                     v.add(wrapper);
404                 }
405             }
406             return (FileWrapper[])(v.toArray(new FileWrapper[0]));
407         }
408         catch(StyxException se)
409         {
410             log.error(se.getMessage());
411             return null;
412         }
413     }
414     
415     /***
416      * Lists available filesystem roots. At the moment this just returns a
417      * single-membered array of java.io.File with the member "/". So it is
418      * not connected to the root of the remote Styx filesystem. Is this 
419      * going to work? We can't get the root of the real remote filesystem because
420      * this is a static method.
421      */
422     public static File[] listRoots()
423     {
424         log.debug("Called FileWrapper.listRoots()");
425         return new File[]{new File("/")};
426     }
427     
428 }