View Javadoc

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