View Javadoc

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