View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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.IOException;
24  import java.io.InputStream;
25  import java.net.MalformedURLException;
26  import java.net.URI;
27  import java.net.URISyntaxException;
28  import java.net.URL;
29  import java.net.URLConnection;
30  import java.nio.channels.FileChannel;
31  import java.nio.channels.ReadableByteChannel;
32  import java.nio.file.StandardOpenOption;
33  import java.security.Permission;
34  
35  import org.eclipse.jetty.util.IO;
36  import org.eclipse.jetty.util.URIUtil;
37  import org.eclipse.jetty.util.log.Log;
38  import org.eclipse.jetty.util.log.Logger;
39  
40  
41  /* ------------------------------------------------------------ */
42  /** File Resource.
43   *
44   * Handle resources of implied or explicit file type.
45   * This class can check for aliasing in the filesystem (eg case
46   * insensitivity).  By default this is turned on, or it can be controlled 
47   * by calling the static method @see FileResource#setCheckAliases(boolean)
48   * 
49   * @deprecated Use {@link PathResource}
50   */
51  @Deprecated
52  public class FileResource extends Resource
53  {
54      private static final Logger LOG = Log.getLogger(FileResource.class);
55  
56      /* ------------------------------------------------------------ */
57      private final File _file;
58      private final String _uri;
59      private final URI _alias;
60      
61      /* -------------------------------------------------------- */
62      public FileResource(URL url)
63          throws IOException, URISyntaxException
64      {
65          File file;
66          try
67          {
68              // Try standard API to convert URL to file.
69              file =new File(url.toURI());
70          }
71          catch (URISyntaxException e) 
72          {
73              throw e;
74          }
75          catch (Exception e)
76          {
77              if (!url.toString().startsWith("file:"))
78                  throw new IllegalArgumentException("!file:");
79              
80              LOG.ignore(e);
81              try
82              {
83                  // Assume that File.toURL produced unencoded chars. So try encoding them.
84                  String file_url="file:"+URIUtil.encodePath(url.toString().substring(5));           
85                  URI uri = new URI(file_url);
86                  if (uri.getAuthority()==null) 
87                      file = new File(uri);
88                  else
89                      file = new File("//"+uri.getAuthority()+URIUtil.decodePath(url.getFile()));
90              }
91              catch (Exception e2)
92              {
93                  LOG.ignore(e2);
94                  // Still can't get the file.  Doh! try good old hack!
95                  URLConnection connection=url.openConnection();
96                  Permission perm = connection.getPermission();
97                  file = new File(perm==null?url.getFile():perm.getName());
98              }
99          }
100         
101         _file=file;
102         _uri=normalizeURI(_file,url.toURI());
103         _alias=checkFileAlias(_file);
104     }
105 
106     /* -------------------------------------------------------- */
107     public FileResource(URI uri)
108     {
109         File file=new File(uri);
110         _file=file;
111         URI file_uri=_file.toURI();
112         _uri=normalizeURI(_file,uri);
113 
114         // Is it a URI alias?
115         if (!URIUtil.equalsIgnoreEncodings(_uri,file_uri.toString()))
116             _alias=_file.toURI();
117         else
118             _alias=checkFileAlias(_file);
119     }
120 
121     /* -------------------------------------------------------- */
122     public FileResource(File file)
123     {
124         _file=file;
125         _uri=normalizeURI(_file,_file.toURI());
126         _alias=checkFileAlias(_file);
127     }
128 
129     /* -------------------------------------------------------- */
130     private static String normalizeURI(File file, URI uri)
131     {
132         String u =uri.toASCIIString();
133         if (file.isDirectory())
134         {
135             if(!u.endsWith("/"))
136                 u+="/";
137         } 
138         else if (file.exists() && u.endsWith("/"))
139             u=u.substring(0,u.length()-1);
140         return u;
141     }
142 
143     /* -------------------------------------------------------- */
144     private static URI checkFileAlias(File file)
145     {
146         try
147         {
148             String abs=file.getAbsolutePath();
149             String can=file.getCanonicalPath();
150 
151             if (!abs.equals(can))
152             {
153                 if (LOG.isDebugEnabled())
154                     LOG.debug("ALIAS abs={} can={}",abs,can);
155 
156                 URI alias=new File(can).toURI();
157                 // Have to encode the path as File.toURI does not!
158                 String uri="file://"+URIUtil.encodePath(alias.getPath());
159                 return new URI(uri);
160             }
161         }
162         catch(Exception e)
163         {
164             LOG.warn("bad alias for {}: {}",file,e.toString());
165             LOG.debug(e);
166             try
167             {
168                 return new URI("http://eclipse.org/bad/canonical/alias");
169             }
170             catch(Exception e2)
171             {
172                 LOG.ignore(e2);
173                 throw new RuntimeException(e);
174             }
175         }
176 
177         return null;
178     }
179     
180     /* -------------------------------------------------------- */
181     @Override
182     public Resource addPath(String path)
183         throws IOException, MalformedURLException
184     {
185         path = org.eclipse.jetty.util.URIUtil.canonicalPath(path);
186 
187         if (path==null)
188             throw new MalformedURLException();   
189         
190         if ("/".equals(path))
191             return this;
192         
193         path=URIUtil.encodePath(path);
194         // The encoded path should be a suffix of the resource (give or take a directory / )
195         URI uri;
196         try
197         {
198             if (_file.isDirectory())
199             {
200                 // treat all paths being added as relative
201                 uri=new URI(URIUtil.addPaths(_uri,path));
202             }
203             else
204             {
205                 uri=new URI(_uri+path);
206             }
207         }
208         catch (final URISyntaxException e)
209         {
210             throw new MalformedURLException(e.getMessage())
211             {
212                 {
213                     initCause(e);
214                 }
215             };
216         }
217 
218         return new FileResource(uri);
219     }
220    
221     
222     /* ------------------------------------------------------------ */
223     @Override
224     public URI getAlias()
225     {
226         return _alias;
227     }
228     
229     /* -------------------------------------------------------- */
230     /**
231      * Returns true if the resource exists.
232      */
233     @Override
234     public boolean exists()
235     {
236         return _file.exists();
237     }
238         
239     /* -------------------------------------------------------- */
240     /**
241      * Returns the last modified time
242      */
243     @Override
244     public long lastModified()
245     {
246         return _file.lastModified();
247     }
248 
249     /* -------------------------------------------------------- */
250     /**
251      * Returns true if the resource is a container/directory.
252      */
253     @Override
254     public boolean isDirectory()
255     {
256         return _file.exists() && _file.isDirectory() || _uri.endsWith("/");
257     }
258 
259     /* --------------------------------------------------------- */
260     /**
261      * Return the length of the resource
262      */
263     @Override
264     public long length()
265     {
266         return _file.length();
267     }
268         
269 
270     /* --------------------------------------------------------- */
271     /**
272      * Returns the name of the resource
273      */
274     @Override
275     public String getName()
276     {
277         return _file.getAbsolutePath();
278     }
279         
280     /* ------------------------------------------------------------ */
281     /**
282      * Returns an File representing the given resource or NULL if this
283      * is not possible.
284      */
285     @Override
286     public File getFile()
287     {
288         return _file;
289     }
290         
291     /* --------------------------------------------------------- */
292     /**
293      * Returns an input stream to the resource
294      */
295     @Override
296     public InputStream getInputStream() throws IOException
297     {
298         return new FileInputStream(_file);
299     }
300 
301     /* ------------------------------------------------------------ */
302     @Override
303     public ReadableByteChannel getReadableByteChannel() throws IOException
304     {
305         return FileChannel.open(_file.toPath(),StandardOpenOption.READ);
306     }
307         
308     /* --------------------------------------------------------- */
309     /**
310      * Deletes the given resource
311      */
312     @Override
313     public boolean delete()
314         throws SecurityException
315     {
316         return _file.delete();
317     }
318 
319     /* --------------------------------------------------------- */
320     /**
321      * Rename the given resource
322      */
323     @Override
324     public boolean renameTo( Resource dest)
325         throws SecurityException
326     {
327         if( dest instanceof FileResource)
328             return _file.renameTo( ((FileResource)dest)._file);
329         else
330             return false;
331     }
332 
333     /* --------------------------------------------------------- */
334     /**
335      * Returns a list of resources contained in the given resource
336      */
337     @Override
338     public String[] list()
339     {
340         String[] list =_file.list();
341         if (list==null)
342             return null;
343         for (int i=list.length;i-->0;)
344         {
345             if (new File(_file,list[i]).isDirectory() &&
346                 !list[i].endsWith("/"))
347                 list[i]+="/";
348         }
349         return list;
350     }
351     
352     /* ------------------------------------------------------------ */
353     /** 
354      * @param o the object to compare against this instance
355      * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource. 
356      */
357     @Override
358     public boolean equals( Object o)
359     {
360         if (this == o)
361             return true;
362 
363         if (null == o || ! (o instanceof FileResource))
364             return false;
365 
366         FileResource f=(FileResource)o;
367         return f._file == _file || (null != _file && _file.equals(f._file));
368     }
369 
370     /* ------------------------------------------------------------ */
371     /**
372      * @return the hashcode.
373      */
374     @Override
375     public int hashCode()
376     {
377        return null == _file ? super.hashCode() : _file.hashCode();
378     }
379     
380     /* ------------------------------------------------------------ */
381     @Override
382     public void copyTo(File destination)
383         throws IOException
384     {
385         if (isDirectory())
386         {
387             IO.copyDir(getFile(),destination);
388         }
389         else
390         {
391             if (destination.exists())
392                 throw new IllegalArgumentException(destination+" exists");
393             IO.copy(getFile(),destination);
394         }
395     }
396 
397     @Override
398     public boolean isContainedIn(Resource r) throws MalformedURLException
399     {
400         return false;
401     }
402 
403     @Override
404     public void close()
405     {
406     }
407 
408     @Override
409     public URL getURL()
410     {
411         try
412         {
413             return new URL(_uri);
414         }
415         catch (MalformedURLException e)
416         {
417             throw new IllegalStateException(e);
418         }
419     }
420     
421     @Override
422     public URI getURI()
423     {
424         return _file.toURI();
425     }
426 
427     @Override
428     public String toString()
429     {
430         return _uri;
431     }
432 
433 }