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     @Override
129     public Resource addPath(String path)
130         throws IOException,MalformedURLException
131     {
132         URLResource r=null;
133         String url=null;
134 
135         path = org.eclipse.jetty.util.URIUtil.canonicalPath(path);
136        
137         if ("/".equals(path))
138             return this;
139         else if (!isDirectory())
140         {
141             r=(FileResource)super.addPath(path);
142             url=r._urlString;
143         }
144         else
145         {
146             if (path==null)
147                 throw new MalformedURLException();   
148             
149             // treat all paths being added as relative
150             String rel=path;
151             if (path.startsWith("/"))
152                 rel = path.substring(1);
153             
154             url=URIUtil.addPaths(_urlString,URIUtil.encodePath(rel));
155             r=(URLResource)Resource.newResource(url);
156         }
157         
158         String encoded=URIUtil.encodePath(path);
159         int expected=r.toString().length()-encoded.length();
160         int index = r._urlString.lastIndexOf(encoded, expected);
161         
162         if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory()))
163         {
164             if (!(r instanceof BadResource))
165             {
166                 ((FileResource)r)._alias=new URL(url);
167                 ((FileResource)r)._aliasChecked=true;
168             }
169         }                             
170         return r;
171     }
172    
173     
174     /* ------------------------------------------------------------ */
175     @Override
176     public URL getAlias()
177     {
178         if (__checkAliases && !_aliasChecked)
179         {
180             try
181             {    
182                 String abs=_file.getAbsolutePath();
183                 String can=_file.getCanonicalPath();
184                 
185                 if (abs.length()!=can.length() || !abs.equals(can))
186                     _alias=new File(can).toURI().toURL();
187                 
188                 _aliasChecked=true;
189                 
190                 if (_alias!=null && Log.isDebugEnabled())
191                 {
192                     Log.debug("ALIAS abs="+abs);
193                     Log.debug("ALIAS can="+can);
194                 }
195             }
196             catch(Exception e)
197             {
198                 Log.warn(Log.EXCEPTION,e);
199                 return getURL();
200             }                
201         }
202         return _alias;
203     }
204     
205     /* -------------------------------------------------------- */
206     /**
207      * Returns true if the resource exists.
208      */
209     @Override
210     public boolean exists()
211     {
212         return _file.exists();
213     }
214         
215     /* -------------------------------------------------------- */
216     /**
217      * Returns the last modified time
218      */
219     @Override
220     public long lastModified()
221     {
222         return _file.lastModified();
223     }
224 
225     /* -------------------------------------------------------- */
226     /**
227      * Returns true if the respresenetd resource is a container/directory.
228      */
229     @Override
230     public boolean isDirectory()
231     {
232         return _file.isDirectory();
233     }
234 
235     /* --------------------------------------------------------- */
236     /**
237      * Return the length of the resource
238      */
239     @Override
240     public long length()
241     {
242         return _file.length();
243     }
244         
245 
246     /* --------------------------------------------------------- */
247     /**
248      * Returns the name of the resource
249      */
250     @Override
251     public String getName()
252     {
253         return _file.getAbsolutePath();
254     }
255         
256     /* ------------------------------------------------------------ */
257     /**
258      * Returns an File representing the given resource or NULL if this
259      * is not possible.
260      */
261     @Override
262     public File getFile()
263     {
264         return _file;
265     }
266         
267     /* --------------------------------------------------------- */
268     /**
269      * Returns an input stream to the resource
270      */
271     @Override
272     public InputStream getInputStream() throws IOException
273     {
274         return new FileInputStream(_file);
275     }
276         
277     /* --------------------------------------------------------- */
278     /**
279      * Returns an output stream to the resource
280      */
281     @Override
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     @Override
293     public boolean delete()
294         throws SecurityException
295     {
296         return _file.delete();
297     }
298 
299     /* --------------------------------------------------------- */
300     /**
301      * Rename the given resource
302      */
303     @Override
304     public boolean renameTo( Resource dest)
305         throws SecurityException
306     {
307         if( dest instanceof FileResource)
308             return _file.renameTo( ((FileResource)dest)._file);
309         else
310             return false;
311     }
312 
313     /* --------------------------------------------------------- */
314     /**
315      * Returns a list of resources contained in the given resource
316      */
317     @Override
318     public String[] list()
319     {
320         String[] list =_file.list();
321         if (list==null)
322             return null;
323         for (int i=list.length;i-->0;)
324         {
325             if (new File(_file,list[i]).isDirectory() &&
326                 !list[i].endsWith("/"))
327                 list[i]+="/";
328         }
329         return list;
330     }
331          
332     /* ------------------------------------------------------------ */
333     /** Encode according to this resource type.
334      * File URIs are encoded.
335      * @param uri URI to encode.
336      * @return The uri unchanged.
337      */
338     @Override
339     public String encode(String uri)
340     {
341         return uri;
342     }
343     
344     /* ------------------------------------------------------------ */
345     /** 
346      * @param o
347      * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource. 
348      */
349     @Override
350     public boolean equals( Object o)
351     {
352         if (this == o)
353             return true;
354 
355         if (null == o || ! (o instanceof FileResource))
356             return false;
357 
358         FileResource f=(FileResource)o;
359         return f._file == _file || (null != _file && _file.equals(f._file));
360     }
361 
362     /* ------------------------------------------------------------ */
363     /**
364      * @return the hashcode.
365      */
366     @Override
367     public int hashCode()
368     {
369        return null == _file ? super.hashCode() : _file.hashCode();
370     }
371     
372     /* ------------------------------------------------------------ */
373     @Override
374     public void copyTo(File destination)
375         throws IOException
376     {
377         if (isDirectory())
378         {
379             IO.copyDir(getFile(),destination);
380         }
381         else
382         {
383             if (destination.exists())
384                 throw new IllegalArgumentException(destination+" exists");
385             IO.copy(getFile(),destination);
386         }
387     }
388 }