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