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.URIUtil;
29  import org.eclipse.jetty.util.log.Log;
30  
31  
32  /* ------------------------------------------------------------ */
33  /** File Resource.
34   *
35   * Handle resources of implied or explicit file type.
36   * This class can check for aliasing in the filesystem (eg case
37   * insensitivity).  By default this is turned on, or it can be controlled with the
38   * "org.eclipse.jetty.util.FileResource.checkAliases" system parameter.
39   *
40   * 
41   */
42  public class FileResource extends URLResource
43  {
44      private static boolean __checkAliases;
45      static
46      {
47          __checkAliases=
48              "true".equalsIgnoreCase
49              (System.getProperty("org.eclipse.jetty.util.FileResource.checkAliases","true"));
50   
51         if (__checkAliases)
52             Log.debug("Checking Resource aliases");
53         else
54             Log.warn("Resource alias checking is disabled");
55      }
56      
57      /* ------------------------------------------------------------ */
58      private File _file;
59      private transient URL _alias=null;
60      private transient boolean _aliasChecked=false;
61  
62      /* ------------------------------------------------------------------------------- */
63      /** setCheckAliases.
64       * @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
65       */
66      public static void setCheckAliases(boolean checkAliases)
67      {
68          __checkAliases=checkAliases;
69      }
70  
71      /* ------------------------------------------------------------------------------- */
72      /** getCheckAliases.
73       * @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
74       */
75      public static boolean getCheckAliases()
76      {
77          return __checkAliases;
78      }
79      
80      /* -------------------------------------------------------- */
81      public FileResource(URL url)
82          throws IOException, URISyntaxException
83      {
84          super(url,null);
85  
86          try
87          {
88              // Try standard API to convert URL to file.
89              _file =new File(new URI(url.toString()));
90          }
91          catch (Exception e)
92          {
93              Log.ignore(e);
94              try
95              {
96                  // Assume that File.toURL produced unencoded chars. So try
97                  // encoding them.
98                  String file_url="file:"+URIUtil.encodePath(url.toString().substring(5));           
99                  URI uri = new URI(file_url);
100                 if (uri.getAuthority()==null) 
101                     _file = new File(uri);
102                 else
103                     _file = new File("//"+uri.getAuthority()+URIUtil.decodePath(url.getFile()));
104             }
105             catch (Exception e2)
106             {
107                 Log.ignore(e2);
108 
109                 // Still can't get the file.  Doh! try good old hack!
110                 checkConnection();
111                 Permission perm = _connection.getPermission();
112                 _file = new File(perm==null?url.getFile():perm.getName());
113             }
114         }
115         if (_file.isDirectory())
116         {
117             if (!_urlString.endsWith("/"))
118                 _urlString=_urlString+"/";
119         }
120         else
121         {
122             if (_urlString.endsWith("/"))
123                 _urlString=_urlString.substring(0,_urlString.length()-1);
124         }
125             
126     }
127     
128     /* -------------------------------------------------------- */
129     FileResource(URL url, URLConnection connection, File file)
130     {
131         super(url,connection);
132         _file=file;
133         if (_file.isDirectory() && !_urlString.endsWith("/"))
134             _urlString=_urlString+"/";
135     }
136     
137     /* -------------------------------------------------------- */
138     public Resource addPath(String path)
139         throws IOException,MalformedURLException
140     {
141         URLResource r=null;
142         String url=null;
143 
144         path = org.eclipse.jetty.util.URIUtil.canonicalPath(path);
145        
146         if ("/".equals(path))
147             return this;
148         else 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 }