comparison src/org/eclipse/jetty/util/resource/JarFileResource.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 8e9db0bbf4f9
comparison
equal deleted inserted replaced
801:6a21393191c1 802:3428c60d7cfc
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.net.JarURLConnection;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.util.ArrayList;
27 import java.util.Enumeration;
28 import java.util.List;
29 import java.util.jar.JarEntry;
30 import java.util.jar.JarFile;
31
32 import org.eclipse.jetty.util.log.Log;
33 import org.eclipse.jetty.util.log.Logger;
34
35 /* ------------------------------------------------------------ */
36 class JarFileResource extends JarResource
37 {
38 private static final Logger LOG = Log.getLogger(JarFileResource.class);
39 private JarFile _jarFile;
40 private File _file;
41 private String[] _list;
42 private JarEntry _entry;
43 private boolean _directory;
44 private String _jarUrl;
45 private String _path;
46 private boolean _exists;
47
48 /* -------------------------------------------------------- */
49 JarFileResource(URL url)
50 {
51 super(url);
52 }
53
54 /* ------------------------------------------------------------ */
55 JarFileResource(URL url, boolean useCaches)
56 {
57 super(url, useCaches);
58 }
59
60
61 /* ------------------------------------------------------------ */
62 @Override
63 public synchronized void release()
64 {
65 _list=null;
66 _entry=null;
67 _file=null;
68 //if the jvm is not doing url caching, then the JarFiles will not be cached either,
69 //and so they are safe to close
70 if (!getUseCaches())
71 {
72 if ( _jarFile != null )
73 {
74 try
75 {
76 LOG.debug("Closing JarFile "+_jarFile.getName());
77 _jarFile.close();
78 }
79 catch ( IOException ioe )
80 {
81 LOG.ignore(ioe);
82 }
83 }
84 }
85 _jarFile=null;
86 super.release();
87 }
88
89 /* ------------------------------------------------------------ */
90 @Override
91 protected boolean checkConnection()
92 {
93 try
94 {
95 super.checkConnection();
96 }
97 finally
98 {
99 if (_jarConnection==null)
100 {
101 _entry=null;
102 _file=null;
103 _jarFile=null;
104 _list=null;
105 }
106 }
107 return _jarFile!=null;
108 }
109
110
111 /* ------------------------------------------------------------ */
112 @Override
113 protected synchronized void newConnection()
114 throws IOException
115 {
116 super.newConnection();
117
118 _entry=null;
119 _file=null;
120 _jarFile=null;
121 _list=null;
122
123 int sep = _urlString.indexOf("!/");
124 _jarUrl=_urlString.substring(0,sep+2);
125 _path=_urlString.substring(sep+2);
126 if (_path.length()==0)
127 _path=null;
128 _jarFile=_jarConnection.getJarFile();
129 _file=new File(_jarFile.getName());
130 }
131
132
133 /* ------------------------------------------------------------ */
134 /**
135 * Returns true if the represented resource exists.
136 */
137 @Override
138 public boolean exists()
139 {
140 if (_exists)
141 return true;
142
143 if (_urlString.endsWith("!/"))
144 {
145
146 String file_url=_urlString.substring(4,_urlString.length()-2);
147 try{return newResource(file_url).exists();}
148 catch(Exception e) {LOG.ignore(e); return false;}
149 }
150
151 boolean check=checkConnection();
152
153 // Is this a root URL?
154 if (_jarUrl!=null && _path==null)
155 {
156 // Then if it exists it is a directory
157 _directory=check;
158 return true;
159 }
160 else
161 {
162 // Can we find a file for it?
163 JarFile jarFile=null;
164 if (check)
165 // Yes
166 jarFile=_jarFile;
167 else
168 {
169 // No - so lets look if the root entry exists.
170 try
171 {
172 JarURLConnection c=(JarURLConnection)((new URL(_jarUrl)).openConnection());
173 c.setUseCaches(getUseCaches());
174 jarFile=c.getJarFile();
175 }
176 catch(Exception e)
177 {
178 LOG.ignore(e);
179 }
180 }
181
182 // Do we need to look more closely?
183 if (jarFile!=null && _entry==null && !_directory)
184 {
185 // OK - we have a JarFile, lets look at the entries for our path
186 Enumeration<JarEntry> e=jarFile.entries();
187 while(e.hasMoreElements())
188 {
189 JarEntry entry = (JarEntry) e.nextElement();
190 String name=entry.getName().replace('\\','/');
191
192 // Do we have a match
193 if (name.equals(_path))
194 {
195 _entry=entry;
196 // Is the match a directory
197 _directory=_path.endsWith("/");
198 break;
199 }
200 else if (_path.endsWith("/"))
201 {
202 if (name.startsWith(_path))
203 {
204 _directory=true;
205 break;
206 }
207 }
208 else if (name.startsWith(_path) && name.length()>_path.length() && name.charAt(_path.length())=='/')
209 {
210 _directory=true;
211 break;
212 }
213 }
214
215 if (_directory && !_urlString.endsWith("/"))
216 {
217 _urlString+="/";
218 try
219 {
220 _url=new URL(_urlString);
221 }
222 catch(MalformedURLException ex)
223 {
224 LOG.warn(ex);
225 }
226 }
227 }
228 }
229
230 _exists= ( _directory || _entry!=null);
231 return _exists;
232 }
233
234
235 /* ------------------------------------------------------------ */
236 /**
237 * Returns true if the represented resource is a container/directory.
238 * If the resource is not a file, resources ending with "/" are
239 * considered directories.
240 */
241 @Override
242 public boolean isDirectory()
243 {
244 return _urlString.endsWith("/") || exists() && _directory;
245 }
246
247 /* ------------------------------------------------------------ */
248 /**
249 * Returns the last modified time
250 */
251 @Override
252 public long lastModified()
253 {
254 if (checkConnection() && _file!=null)
255 {
256 if (exists() && _entry!=null)
257 return _entry.getTime();
258 return _file.lastModified();
259 }
260 return -1;
261 }
262
263 /* ------------------------------------------------------------ */
264 @Override
265 public synchronized String[] list()
266 {
267 if (isDirectory() && _list==null)
268 {
269 List<String> list = null;
270 try
271 {
272 list = listEntries();
273 }
274 catch (Exception e)
275 {
276 //Sun's JarURLConnection impl for jar: protocol will close a JarFile in its connect() method if
277 //useCaches == false (eg someone called URLConnection with defaultUseCaches==true).
278 //As their sun.net.www.protocol.jar package caches JarFiles and/or connections, we can wind up in
279 //the situation where the JarFile we have remembered in our _jarFile member has actually been closed
280 //by other code.
281 //So, do one retry to drop a connection and get a fresh JarFile
282 LOG.warn("Retrying list:"+e);
283 LOG.debug(e);
284 release();
285 list = listEntries();
286 }
287
288 if (list != null)
289 {
290 _list=new String[list.size()];
291 list.toArray(_list);
292 }
293 }
294 return _list;
295 }
296
297
298 /* ------------------------------------------------------------ */
299 private List<String> listEntries ()
300 {
301 checkConnection();
302
303 ArrayList<String> list = new ArrayList<String>(32);
304 JarFile jarFile=_jarFile;
305 if(jarFile==null)
306 {
307 try
308 {
309 JarURLConnection jc=(JarURLConnection)((new URL(_jarUrl)).openConnection());
310 jc.setUseCaches(getUseCaches());
311 jarFile=jc.getJarFile();
312 }
313 catch(Exception e)
314 {
315
316 e.printStackTrace();
317 LOG.ignore(e);
318 }
319 }
320
321 Enumeration<JarEntry> e=jarFile.entries();
322 String dir=_urlString.substring(_urlString.indexOf("!/")+2);
323 while(e.hasMoreElements())
324 {
325 JarEntry entry = e.nextElement();
326 String name=entry.getName().replace('\\','/');
327 if(!name.startsWith(dir) || name.length()==dir.length())
328 {
329 continue;
330 }
331 String listName=name.substring(dir.length());
332 int dash=listName.indexOf('/');
333 if (dash>=0)
334 {
335 //when listing jar:file urls, you get back one
336 //entry for the dir itself, which we ignore
337 if (dash==0 && listName.length()==1)
338 continue;
339 //when listing jar:file urls, all files and
340 //subdirs have a leading /, which we remove
341 if (dash==0)
342 listName=listName.substring(dash+1, listName.length());
343 else
344 listName=listName.substring(0,dash+1);
345
346 if (list.contains(listName))
347 continue;
348 }
349
350 list.add(listName);
351 }
352
353 return list;
354 }
355
356
357
358
359
360 /* ------------------------------------------------------------ */
361 /**
362 * Return the length of the resource
363 */
364 @Override
365 public long length()
366 {
367 if (isDirectory())
368 return -1;
369
370 if (_entry!=null)
371 return _entry.getSize();
372
373 return -1;
374 }
375
376 /* ------------------------------------------------------------ */
377 /** Encode according to this resource type.
378 * File URIs are not encoded.
379 * @param uri URI to encode.
380 * @return The uri unchanged.
381 */
382 @Override
383 public String encode(String uri)
384 {
385 return uri;
386 }
387
388
389 /**
390 * Take a Resource that possibly might use URLConnection caching
391 * and turn it into one that doesn't.
392 * @param resource
393 * @return the non-caching resource
394 */
395 public static Resource getNonCachingResource (Resource resource)
396 {
397 if (!(resource instanceof JarFileResource))
398 return resource;
399
400 JarFileResource oldResource = (JarFileResource)resource;
401
402 JarFileResource newResource = new JarFileResource(oldResource.getURL(), false);
403 return newResource;
404
405 }
406
407 /**
408 * Check if this jar:file: resource is contained in the
409 * named resource. Eg <code>jar:file:///a/b/c/foo.jar!/x.html</code> isContainedIn <code>file:///a/b/c/foo.jar</code>
410 * @param resource
411 * @return true if resource is contained in the named resource
412 * @throws MalformedURLException
413 */
414 @Override
415 public boolean isContainedIn (Resource resource)
416 throws MalformedURLException
417 {
418 String string = _urlString;
419 int index = string.indexOf("!/");
420 if (index > 0)
421 string = string.substring(0,index);
422 if (string.startsWith("jar:"))
423 string = string.substring(4);
424 URL url = new URL(string);
425 return url.sameFile(resource.getURL());
426 }
427 }
428
429
430
431
432
433
434
435