View Javadoc

1   // ========================================================================
2   // Copyright 1996-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  package org.mortbay.resource;
15  
16  import java.io.File;
17  import java.io.FileInputStream;
18  import java.io.FileOutputStream;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.OutputStream;
22  import java.net.MalformedURLException;
23  import java.net.URI;
24  import java.net.URISyntaxException;
25  import java.net.URL;
26  import java.net.URLConnection;
27  import java.security.Permission;
28  
29  import org.mortbay.log.Log;
30  import org.mortbay.util.StringUtil;
31  import org.mortbay.util.URIUtil;
32  
33  
34  /* ------------------------------------------------------------ */
35  /** File Resource.
36   *
37   * Handle resources of implied or explicit file type.
38   * This class can check for aliasing in the filesystem (eg case
39   * insensitivity).  By default this is turned on, or it can be controlled with the
40   * "org.mortbay.util.FileResource.checkAliases" system parameter.
41   *
42   * @author Greg Wilkins (gregw)
43   */
44  public class FileResource extends URLResource
45  {
46      private static boolean __checkAliases;
47      static
48      {
49          __checkAliases=
50              "true".equalsIgnoreCase
51              (System.getProperty("org.mortbay.util.FileResource.checkAliases","true"));
52   
53         if (__checkAliases)
54             Log.debug("Checking Resource aliases");
55         else
56             Log.warn("Resource alias checking is disabled");
57      }
58      
59      /* ------------------------------------------------------------ */
60      private File _file;
61      private transient URL _alias=null;
62      private transient boolean _aliasChecked=false;
63  
64      /* ------------------------------------------------------------------------------- */
65      /** setCheckAliases.
66       * @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
67       */
68      public static void setCheckAliases(boolean checkAliases)
69      {
70          __checkAliases=checkAliases;
71      }
72  
73      /* ------------------------------------------------------------------------------- */
74      /** getCheckAliases.
75       * @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
76       */
77      public static boolean getCheckAliases()
78      {
79          return __checkAliases;
80      }
81      
82      /* -------------------------------------------------------- */
83      public FileResource(URL url)
84          throws IOException, URISyntaxException
85      {
86          super(url,null);
87  
88          try
89          {
90              // Try standard API to convert URL to file.
91              _file =new File(new URI(url.toString()));
92          }
93          catch (Exception e)
94          {
95              Log.ignore(e);
96              try
97              {
98                  // Assume that File.toURL produced unencoded chars. So try
99                  // encoding them.
100                 String file_url="file:"+URIUtil.encodePath(url.toString().substring(5));           
101                 URI uri = new URI(file_url);
102                 if (uri.getAuthority()==null) 
103                     _file = new File(uri);
104                 else
105                     _file = new File("//"+uri.getAuthority()+URIUtil.decodePath(url.getFile()));
106             }
107             catch (Exception e2)
108             {
109                 Log.ignore(e2);
110 
111                 // Still can't get the file.  Doh! try good old hack!
112                 checkConnection();
113                 Permission perm = _connection.getPermission();
114                 _file = new File(perm==null?url.getFile():perm.getName());
115             }
116         }
117         if (_file.isDirectory())
118         {
119             if (!_urlString.endsWith("/"))
120                 _urlString=_urlString+"/";
121         }
122         else
123         {
124             if (_urlString.endsWith("/"))
125                 _urlString=_urlString.substring(0,_urlString.length()-1);
126         }
127             
128     }
129     
130     /* -------------------------------------------------------- */
131     FileResource(URL url, URLConnection connection, File file)
132     {
133         super(url,connection);
134         _file=file;
135         if (_file.isDirectory() && !_urlString.endsWith("/"))
136             _urlString=_urlString+"/";
137     }
138     
139     /* -------------------------------------------------------- */
140     public Resource addPath(String path)
141         throws IOException,MalformedURLException
142     {
143         URLResource r=null;
144         String url=null;
145 
146         path = org.mortbay.util.URIUtil.canonicalPath(path);
147         
148         if (!isDirectory())
149         {
150             r=(FileResource)super.addPath(path);
151             url=r._urlString;
152         }
153         else
154         {
155             if (path==null)
156                 throw new MalformedURLException();   
157             
158             // treat all paths being added as relative
159             String rel=path;
160             if (path.startsWith("/"))
161                 rel = path.substring(1);
162             
163             url=URIUtil.addPaths(_urlString,URIUtil.encodePath(rel));
164             r=(URLResource)Resource.newResource(url);
165         }
166         
167         String encoded=URIUtil.encodePath(path);
168         int expected=r.toString().length()-encoded.length();
169         int index = r._urlString.lastIndexOf(encoded, expected);
170         
171         if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory()))
172         {
173             if (!(r instanceof BadResource))
174             {
175                 ((FileResource)r)._alias=new URL(url);
176                 ((FileResource)r)._aliasChecked=true;
177             }
178         }                             
179         return r;
180     }
181    
182     
183     /* ------------------------------------------------------------ */
184     public URL getAlias()
185     {
186         if (__checkAliases && !_aliasChecked)
187         {
188             try
189             {    
190                 String abs=_file.getAbsolutePath();
191                 String can=_file.getCanonicalPath();
192                 
193                 if (abs.length()!=can.length() || !abs.equals(can))
194                     _alias=new File(can).toURI().toURL();
195                 
196                 _aliasChecked=true;
197                 
198                 if (_alias!=null && Log.isDebugEnabled())
199                 {
200                     Log.debug("ALIAS abs="+abs);
201                     Log.debug("ALIAS can="+can);
202                 }
203             }
204             catch(Exception e)
205             {
206                 Log.warn(Log.EXCEPTION,e);
207                 return getURL();
208             }                
209         }
210         return _alias;
211     }
212     
213     /* -------------------------------------------------------- */
214     /**
215      * Returns true if the resource exists.
216      */
217     public boolean exists()
218     {
219         return _file.exists();
220     }
221         
222     /* -------------------------------------------------------- */
223     /**
224      * Returns the last modified time
225      */
226     public long lastModified()
227     {
228         return _file.lastModified();
229     }
230 
231     /* -------------------------------------------------------- */
232     /**
233      * Returns true if the respresenetd resource is a container/directory.
234      */
235     public boolean isDirectory()
236     {
237         return _file.isDirectory();
238     }
239 
240     /* --------------------------------------------------------- */
241     /**
242      * Return the length of the resource
243      */
244     public long length()
245     {
246         return _file.length();
247     }
248         
249 
250     /* --------------------------------------------------------- */
251     /**
252      * Returns the name of the resource
253      */
254     public String getName()
255     {
256         return _file.getAbsolutePath();
257     }
258         
259     /* ------------------------------------------------------------ */
260     /**
261      * Returns an File representing the given resource or NULL if this
262      * is not possible.
263      */
264     public File getFile()
265     {
266         return _file;
267     }
268         
269     /* --------------------------------------------------------- */
270     /**
271      * Returns an input stream to the resource
272      */
273     public InputStream getInputStream() throws IOException
274     {
275         return new FileInputStream(_file);
276     }
277         
278     /* --------------------------------------------------------- */
279     /**
280      * Returns an output stream to the resource
281      */
282     public OutputStream getOutputStream()
283         throws java.io.IOException, SecurityException
284     {
285         return new FileOutputStream(_file);
286     }
287         
288     /* --------------------------------------------------------- */
289     /**
290      * Deletes the given resource
291      */
292     public boolean delete()
293         throws SecurityException
294     {
295         return _file.delete();
296     }
297 
298     /* --------------------------------------------------------- */
299     /**
300      * Rename the given resource
301      */
302     public boolean renameTo( Resource dest)
303         throws SecurityException
304     {
305         if( dest instanceof FileResource)
306             return _file.renameTo( ((FileResource)dest)._file);
307         else
308             return false;
309     }
310 
311     /* --------------------------------------------------------- */
312     /**
313      * Returns a list of resources contained in the given resource
314      */
315     public String[] list()
316     {
317         String[] list =_file.list();
318         if (list==null)
319             return null;
320         for (int i=list.length;i-->0;)
321         {
322             if (new File(_file,list[i]).isDirectory() &&
323                 !list[i].endsWith("/"))
324                 list[i]+="/";
325         }
326         return list;
327     }
328          
329     /* ------------------------------------------------------------ */
330     /** Encode according to this resource type.
331      * File URIs are encoded.
332      * @param uri URI to encode.
333      * @return The uri unchanged.
334      */
335     public String encode(String uri)
336     {
337         return uri;
338     }
339     
340     /* ------------------------------------------------------------ */
341     /** 
342      * @param o
343      * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource. 
344      */
345     public boolean equals( Object o)
346     {
347         if (this == o)
348             return true;
349 
350         if (null == o || ! (o instanceof FileResource))
351             return false;
352 
353         FileResource f=(FileResource)o;
354         return f._file == _file || (null != _file && _file.equals(f._file));
355     }
356 
357     /* ------------------------------------------------------------ */
358     /**
359      * @return the hashcode.
360      */
361     public int hashCode()
362     {
363        return null == _file ? super.hashCode() : _file.hashCode();
364     }
365 }