2 // ========================================================================
3 // Copyright (c) 1995-2014 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.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.util.resource;
22 import java.io.FileInputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.net.MalformedURLException;
27 import java.net.URISyntaxException;
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;
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;
41 /* ------------------------------------------------------------ */
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)
50 public class FileResource extends Resource
52 private static final Logger LOG = Log.getLogger(FileResource.class);
54 /* ------------------------------------------------------------ */
55 private final File _file;
56 private final String _uri;
57 private final URI _alias;
59 /* -------------------------------------------------------- */
60 public FileResource(URL url)
61 throws IOException, URISyntaxException
66 // Try standard API to convert URL to file.
67 file =new File(url.toURI());
69 catch (URISyntaxException e)
75 if (!url.toString().startsWith("file:"))
76 throw new IllegalArgumentException("!file:");
81 // Assume that File.toURL produced unencoded chars. So try encoding them.
82 String file_url="file:"+URIUtil.encodePath(url.toString().substring(5));
83 URI uri = new URI(file_url);
84 if (uri.getAuthority()==null)
87 file = new File("//"+uri.getAuthority()+URIUtil.decodePath(url.getFile()));
92 // Still can't get the file. Doh! try good old hack!
93 URLConnection connection=url.openConnection();
94 Permission perm = connection.getPermission();
95 file = new File(perm==null?url.getFile():perm.getName());
100 _uri=normalizeURI(_file,url.toURI());
101 _alias=checkAlias(_file);
104 /* -------------------------------------------------------- */
105 public FileResource(URI uri)
107 File file=new File(uri);
109 URI file_uri=_file.toURI();
110 _uri=normalizeURI(_file,uri);
112 if (!_uri.equals(file_uri.toString()))
114 // URI and File URI are different. Is it just an encoding difference?
115 if (!file_uri.toString().equals(URIUtil.decodePath(uri.toString())))
116 _alias=_file.toURI();
118 _alias=checkAlias(_file);
121 _alias=checkAlias(_file);
124 /* -------------------------------------------------------- */
125 FileResource(File file)
128 _uri=normalizeURI(_file,_file.toURI());
129 _alias=checkAlias(_file);
132 /* -------------------------------------------------------- */
133 private static String normalizeURI(File file, URI uri)
135 String u =uri.toASCIIString();
136 if (file.isDirectory())
141 else if (file.exists() && u.endsWith("/"))
142 u=u.substring(0,u.length()-1);
146 /* -------------------------------------------------------- */
147 private static URI checkAlias(File file)
151 String abs=file.getAbsolutePath();
152 String can=file.getCanonicalPath();
154 if (!abs.equals(can))
156 LOG.debug("ALIAS abs={} can={}",abs,can);
158 URI alias=new File(can).toURI();
159 // Have to encode the path as File.toURI does not!
160 return new URI("file://"+URIUtil.encodePath(alias.getPath()));
165 LOG.warn("bad alias for {}: {}",file,e.toString());
169 return new URI("http://eclipse.org/bad/canonical/alias");
174 throw new RuntimeException(e);
181 /* -------------------------------------------------------- */
183 public Resource addPath(String path)
184 throws IOException,MalformedURLException
186 path = org.eclipse.jetty.util.URIUtil.canonicalPath(path);
189 throw new MalformedURLException();
191 if ("/".equals(path))
194 path=URIUtil.encodePath(path);
195 // The encoded path should be a suffix of the resource (give or take a directory / )
199 if (_file.isDirectory())
201 // treat all paths being added as relative
202 uri=new URI(URIUtil.addPaths(_uri,path));
206 uri=new URI(_uri+path);
209 catch(final URISyntaxException e)
211 throw new MalformedURLException(){{initCause(e);}};
214 return new FileResource(uri);
218 /* ------------------------------------------------------------ */
220 public URI getAlias()
225 /* -------------------------------------------------------- */
227 * Returns true if the resource exists.
230 public boolean exists()
232 return _file.exists();
235 /* -------------------------------------------------------- */
237 * Returns the last modified time
240 public long lastModified()
242 return _file.lastModified();
245 /* -------------------------------------------------------- */
247 * Returns true if the resource is a container/directory.
250 public boolean isDirectory()
252 return _file.exists() && _file.isDirectory() || _uri.endsWith("/");
255 /* --------------------------------------------------------- */
257 * Return the length of the resource
262 return _file.length();
266 /* --------------------------------------------------------- */
268 * Returns the name of the resource
271 public String getName()
273 return _file.getAbsolutePath();
276 /* ------------------------------------------------------------ */
278 * Returns an File representing the given resource or NULL if this
282 public File getFile()
287 /* --------------------------------------------------------- */
289 * Returns an input stream to the resource
292 public InputStream getInputStream() throws IOException
294 return new FileInputStream(_file);
297 /* ------------------------------------------------------------ */
299 public ReadableByteChannel getReadableByteChannel() throws IOException
301 return FileChannel.open(_file.toPath(),StandardOpenOption.READ);
304 /* --------------------------------------------------------- */
306 * Deletes the given resource
309 public boolean delete()
310 throws SecurityException
312 return _file.delete();
315 /* --------------------------------------------------------- */
317 * Rename the given resource
320 public boolean renameTo( Resource dest)
321 throws SecurityException
323 if( dest instanceof FileResource)
324 return _file.renameTo( ((FileResource)dest)._file);
329 /* --------------------------------------------------------- */
331 * Returns a list of resources contained in the given resource
334 public String[] list()
336 String[] list =_file.list();
339 for (int i=list.length;i-->0;)
341 if (new File(_file,list[i]).isDirectory() &&
342 !list[i].endsWith("/"))
348 /* ------------------------------------------------------------ */
351 * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource.
354 public boolean equals( Object o)
359 if (null == o || ! (o instanceof FileResource))
362 FileResource f=(FileResource)o;
363 return f._file == _file || (null != _file && _file.equals(f._file));
366 /* ------------------------------------------------------------ */
368 * @return the hashcode.
371 public int hashCode()
373 return null == _file ? super.hashCode() : _file.hashCode();
376 /* ------------------------------------------------------------ */
378 public void copyTo(File destination)
383 IO.copyDir(getFile(),destination);
387 if (destination.exists())
388 throw new IllegalArgumentException(destination+" exists");
389 IO.copy(getFile(),destination);
394 public boolean isContainedIn(Resource r) throws MalformedURLException
409 return new URL(_uri);
411 catch (MalformedURLException e)
413 throw new IllegalStateException(e);
420 return _file.toURI();
424 public String toString()