View Javadoc

1   //
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.
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.IOException;
23  import java.io.InputStream;
24  import java.net.MalformedURLException;
25  import java.net.URI;
26  import java.net.URISyntaxException;
27  import java.net.URL;
28  import java.nio.channels.FileChannel;
29  import java.nio.channels.ReadableByteChannel;
30  import java.nio.file.DirectoryIteratorException;
31  import java.nio.file.DirectoryStream;
32  import java.nio.file.Files;
33  import java.nio.file.InvalidPathException;
34  import java.nio.file.LinkOption;
35  import java.nio.file.Path;
36  import java.nio.file.StandardCopyOption;
37  import java.nio.file.StandardOpenOption;
38  import java.nio.file.attribute.FileTime;
39  import java.util.ArrayList;
40  import java.util.List;
41  
42  import org.eclipse.jetty.util.log.Log;
43  import org.eclipse.jetty.util.log.Logger;
44  
45  /**
46   * Java NIO Path equivalent of FileResource.
47   */
48  public class PathResource extends Resource
49  {
50      private static final Logger LOG = Log.getLogger(PathResource.class);
51  
52      private final Path path;
53      private final URI uri;
54      private LinkOption linkOptions[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
55  
56      public PathResource(File file)
57      {
58          this(file.toPath());
59      }
60  
61      public PathResource(Path path)
62      {
63          this.path = path;
64          this.uri = this.path.toUri();
65      }
66  
67      public PathResource(URI uri) throws IOException
68      {
69          if (!uri.isAbsolute())
70          {
71              throw new IllegalArgumentException("not an absolute uri");
72          }
73  
74          if (!uri.getScheme().equalsIgnoreCase("file"))
75          {
76              throw new IllegalArgumentException("not file: scheme");
77          }
78  
79          Path path;
80          try
81          {
82              path = new File(uri).toPath();
83          }
84          catch (InvalidPathException e)
85          {
86              throw e;
87          }
88          catch (IllegalArgumentException e)
89          {
90              throw e;
91          }
92          catch (Exception e)
93          {
94              LOG.ignore(e);
95              throw new IOException("Unable to build Path from: " + uri,e);
96          }
97  
98          this.path = path;
99          this.uri = path.toUri();
100     }
101 
102     public PathResource(URL url) throws IOException, URISyntaxException
103     {
104         this(url.toURI());
105     }
106 
107     @Override
108     public Resource addPath(String apath) throws IOException, MalformedURLException
109     {
110         return new PathResource(this.path.resolve(apath));
111     }
112 
113     @Override
114     public void close()
115     {
116         // not applicable for FileSytem / Path
117     }
118 
119     @Override
120     public boolean delete() throws SecurityException
121     {
122         try
123         {
124             return Files.deleteIfExists(path);
125         }
126         catch (IOException e)
127         {
128             LOG.ignore(e);
129             return false;
130         }
131     }
132 
133     @Override
134     public boolean equals(Object obj)
135     {
136         if (this == obj)
137         {
138             return true;
139         }
140         if (obj == null)
141         {
142             return false;
143         }
144         if (getClass() != obj.getClass())
145         {
146             return false;
147         }
148         PathResource other = (PathResource)obj;
149         if (path == null)
150         {
151             if (other.path != null)
152             {
153                 return false;
154             }
155         }
156         else if (!path.equals(other.path))
157         {
158             return false;
159         }
160         return true;
161     }
162 
163     @Override
164     public boolean exists()
165     {
166         return Files.exists(path,linkOptions);
167     }
168 
169     @Override
170     public File getFile() throws IOException
171     {
172         return path.toFile();
173     }
174 
175     public boolean getFollowLinks()
176     {
177         return (linkOptions != null) && (linkOptions.length > 0) && (linkOptions[0] == LinkOption.NOFOLLOW_LINKS);
178     }
179 
180     @Override
181     public InputStream getInputStream() throws IOException
182     {
183         return Files.newInputStream(path,StandardOpenOption.READ);
184     }
185 
186     @Override
187     public String getName()
188     {
189         return path.toAbsolutePath().toString();
190     }
191 
192     @Override
193     public ReadableByteChannel getReadableByteChannel() throws IOException
194     {
195         return FileChannel.open(path,StandardOpenOption.READ);
196     }
197 
198     @Override
199     public URI getURI()
200     {
201         return this.uri;
202     }
203 
204     @Override
205     public URL getURL()
206     {
207         try
208         {
209             return path.toUri().toURL();
210         }
211         catch (MalformedURLException e)
212         {
213             return null;
214         }
215     }
216 
217     @Override
218     public int hashCode()
219     {
220         final int prime = 31;
221         int result = 1;
222         result = (prime * result) + ((path == null)?0:path.hashCode());
223         return result;
224     }
225 
226     @Override
227     public boolean isContainedIn(Resource r) throws MalformedURLException
228     {
229         // not applicable for FileSystem / path
230         return false;
231     }
232 
233     @Override
234     public boolean isDirectory()
235     {
236         return Files.isDirectory(path,linkOptions);
237     }
238 
239     @Override
240     public long lastModified()
241     {
242         try
243         {
244             FileTime ft = Files.getLastModifiedTime(path,linkOptions);
245             return ft.toMillis();
246         }
247         catch (IOException e)
248         {
249             LOG.ignore(e);
250             return 0;
251         }
252     }
253 
254     @Override
255     public long length()
256     {
257         try
258         {
259             return Files.size(path);
260         }
261         catch (IOException e)
262         {
263             // in case of error, use File.length logic of 0L
264             return 0L;
265         }
266     }
267 
268     @Override
269     public URI getAlias()
270     {
271         if (Files.isSymbolicLink(path))
272         {
273             try
274             {
275                 return path.toRealPath().toUri();
276             }
277             catch (IOException e)
278             {
279                 LOG.debug(e);
280                 return null;
281             }
282         }
283         else
284         {
285             return null;
286         }
287     }
288 
289     @Override
290     public String[] list()
291     {
292         try (DirectoryStream<Path> dir = Files.newDirectoryStream(path))
293         {
294             List<String> entries = new ArrayList<>();
295             for (Path entry : dir)
296             {
297                 String name = entry.getFileName().toString();
298 
299                 if (Files.isDirectory(entry))
300                 {
301                     name += "/";
302                 }
303 
304                 entries.add(name);
305             }
306             int size = entries.size();
307             return entries.toArray(new String[size]);
308         }
309         catch (DirectoryIteratorException e)
310         {
311             LOG.debug(e);
312         }
313         catch (IOException e)
314         {
315             LOG.debug(e);
316         }
317         return null;
318     }
319 
320     @Override
321     public boolean renameTo(Resource dest) throws SecurityException
322     {
323         if (dest instanceof PathResource)
324         {
325             PathResource destRes = (PathResource)dest;
326             try
327             {
328                 Path result = Files.move(path,destRes.path,StandardCopyOption.ATOMIC_MOVE);
329                 return Files.exists(result,linkOptions);
330             }
331             catch (IOException e)
332             {
333                 LOG.ignore(e);
334                 return false;
335             }
336         }
337         else
338         {
339             return false;
340         }
341     }
342 
343     public void setFollowLinks(boolean followLinks)
344     {
345         if (followLinks)
346         {
347             linkOptions = new LinkOption[0];
348         }
349         else
350         {
351             linkOptions = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
352         }
353     }
354 }