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.IOException;
17  import java.net.JarURLConnection;
18  import java.net.MalformedURLException;
19  import java.net.URL;
20  import java.util.ArrayList;
21  import java.util.Enumeration;
22  import java.util.jar.JarEntry;
23  import java.util.jar.JarFile;
24  
25  import org.eclipse.jetty.util.log.Log;
26  
27  /* ------------------------------------------------------------ */
28  class JarFileResource extends JarResource
29  {
30      
31      transient JarFile _jarFile;
32      transient File _file;
33      transient String[] _list;
34      transient JarEntry _entry;
35      transient boolean _directory;
36      transient String _jarUrl;
37      transient String _path;
38      transient boolean _exists;
39  
40      
41      /* -------------------------------------------------------- */
42      JarFileResource(URL url)
43      {
44          super(url);
45      }
46      
47      JarFileResource(URL url, boolean useCaches)
48      {
49          super(url, useCaches);
50      }
51     
52  
53      /* ------------------------------------------------------------ */
54      @Override
55      public synchronized void release()
56      {
57          _list=null;
58          _entry=null;
59          _file=null;
60          _jarFile=null;
61          super.release();
62      }
63      
64      /* ------------------------------------------------------------ */
65      @Override
66      protected boolean checkConnection()
67      {
68          try{
69              super.checkConnection();
70          }
71          finally
72          {
73              if (_jarConnection==null)
74              {
75                  _entry=null;
76                  _file=null;
77                  _jarFile=null;
78                  _list=null;
79              }
80          }
81          return _jarFile!=null;
82      }
83  
84  
85      /* ------------------------------------------------------------ */
86      @Override
87      protected void newConnection()
88          throws IOException
89      {
90          super.newConnection();
91          
92          _entry=null;
93          _file=null;
94          _jarFile=null;
95          _list=null;
96          
97          int sep = _urlString.indexOf("!/");
98          _jarUrl=_urlString.substring(0,sep+2);
99          _path=_urlString.substring(sep+2);
100         if (_path.length()==0)
101             _path=null;   
102         _jarFile=_jarConnection.getJarFile();
103         _file=new File(_jarFile.getName());
104     }
105     
106     
107     /* ------------------------------------------------------------ */
108     /**
109      * Returns true if the respresenetd resource exists.
110      */
111     @Override
112     public boolean exists()
113     {
114         if (_exists)
115             return true;
116 
117         if (_urlString.endsWith("!/"))
118         {
119             
120             String file_url=_urlString.substring(4,_urlString.length()-2);
121             try{return newResource(file_url).exists();}
122             catch(Exception e) {Log.ignore(e); return false;}
123         }
124         
125         boolean check=checkConnection();
126         
127         // Is this a root URL?
128         if (_jarUrl!=null && _path==null)
129         {
130             // Then if it exists it is a directory
131             _directory=check;
132             return true;
133         }
134         else 
135         {
136             // Can we find a file for it?
137             JarFile jarFile=null;
138             if (check)
139                 // Yes
140                 jarFile=_jarFile;
141             else
142             {
143                 // No - so lets look if the root entry exists.
144                 try
145                 {
146                     JarURLConnection c=(JarURLConnection)((new URL(_jarUrl)).openConnection());
147                     c.setUseCaches(getUseCaches());
148                     jarFile=c.getJarFile();
149                 }
150                 catch(Exception e)
151                 {
152                        Log.ignore(e);
153                 }
154             }
155 
156             // Do we need to look more closely?
157             if (jarFile!=null && _entry==null && !_directory)
158             {
159                 // OK - we have a JarFile, lets look at the entries for our path
160                 Enumeration e=jarFile.entries();
161                 while(e.hasMoreElements())
162                 {
163                     JarEntry entry = (JarEntry) e.nextElement();
164                     String name=entry.getName().replace('\\','/');
165                     
166                     // Do we have a match
167                     if (name.equals(_path))
168                     {
169                         _entry=entry;
170                         // Is the match a directory
171                         _directory=_path.endsWith("/");
172                         break;
173                     }
174                     else if (_path.endsWith("/"))
175                     {
176                         if (name.startsWith(_path))
177                         {
178                             _directory=true;
179                             break;
180                         }
181                     }
182                     else if (name.startsWith(_path) && name.length()>_path.length() && name.charAt(_path.length())=='/')
183                     {
184                         _directory=true;
185                         break;
186                     }
187                 }
188             }
189         }    
190         
191         _exists= ( _directory || _entry!=null);
192         return _exists;
193     }
194 
195     
196     /* ------------------------------------------------------------ */
197     /**
198      * Returns true if the represented resource is a container/directory.
199      * If the resource is not a file, resources ending with "/" are
200      * considered directories.
201      */
202     @Override
203     public boolean isDirectory()
204     {
205         return _urlString.endsWith("/") || exists() && _directory;
206     }
207     
208     /* ------------------------------------------------------------ */
209     /**
210      * Returns the last modified time
211      */
212     @Override
213     public long lastModified()
214     {
215         if (checkConnection() && _file!=null)
216             return _file.lastModified();
217         return -1;
218     }
219 
220     /* ------------------------------------------------------------ */
221     @Override
222     public synchronized String[] list()
223     {
224         
225         if(isDirectory() && _list==null)
226         {
227             ArrayList list = new ArrayList(32);
228 
229             checkConnection();
230             
231             JarFile jarFile=_jarFile;
232             if(jarFile==null)
233             {
234                 try
235                 {
236                     JarURLConnection jc=(JarURLConnection)((new URL(_jarUrl)).openConnection());
237                     jc.setUseCaches(getUseCaches());
238                     jarFile=jc.getJarFile();
239                 }
240                 catch(Exception e)
241                 {
242                      Log.ignore(e);
243                 }
244             }
245             
246             Enumeration e=jarFile.entries();
247             String dir=_urlString.substring(_urlString.indexOf("!/")+2);
248             while(e.hasMoreElements())
249             {
250                 
251                 JarEntry entry = (JarEntry) e.nextElement();               
252                 String name=entry.getName().replace('\\','/');               
253                 if(!name.startsWith(dir) || name.length()==dir.length())
254                 {
255                     continue;
256                 }
257                 String listName=name.substring(dir.length());               
258                 int dash=listName.indexOf('/');
259                 if (dash>=0)
260                 {
261                     //when listing jar:file urls, you get back one
262                     //entry for the dir itself, which we ignore
263                     if (dash==0 && listName.length()==1)
264                         continue;
265                     //when listing jar:file urls, all files and
266                     //subdirs have a leading /, which we remove
267                     if (dash==0)
268                         listName=listName.substring(dash+1, listName.length());
269                     else
270                         listName=listName.substring(0,dash+1);
271                     
272                     if (list.contains(listName))
273                         continue;
274                 }
275                 
276                 list.add(listName);
277             }
278             
279             _list=new String[list.size()];
280             list.toArray(_list);
281         }
282         return _list;
283     }
284     
285     /* ------------------------------------------------------------ */
286     /**
287      * Return the length of the resource
288      */
289     @Override
290     public long length()
291     {
292         if (isDirectory())
293             return -1;
294 
295         if (_entry!=null)
296             return _entry.getSize();
297         
298         return -1;
299     }
300     
301     /* ------------------------------------------------------------ */
302     /** Encode according to this resource type.
303      * File URIs are not encoded.
304      * @param uri URI to encode.
305      * @return The uri unchanged.
306      */
307     @Override
308     public String encode(String uri)
309     {
310         return uri;
311     }
312 
313     
314     /**
315      * Take a Resource that possibly might use URLConnection caching
316      * and turn it into one that doesn't.
317      * @param resource
318      * @return the non-caching resource
319      */
320     public static Resource getNonCachingResource (Resource resource)
321     {
322         if (!(resource instanceof JarFileResource))
323             return resource;
324         
325         JarFileResource oldResource = (JarFileResource)resource;
326         
327         JarFileResource newResource = new JarFileResource(oldResource.getURL(), false);
328         return newResource;
329         
330     }
331     
332     /**
333      * Check if this jar:file: resource is contained in the
334      * named resource. Eg <code>jar:file:///a/b/c/foo.jar!/x.html</code> isContainedIn <code>file:///a/b/c/foo.jar</code>
335      * @param resource
336      * @return true if resource is contained in the named resource
337      * @throws MalformedURLException
338      */
339     @Override
340     public boolean isContainedIn (Resource resource) 
341     throws MalformedURLException
342     {
343         String string = _urlString;
344         int index = string.indexOf("!/");
345         if (index > 0)
346             string = string.substring(0,index);
347         if (string.startsWith("jar:"))
348             string = string.substring(4);
349         URL url = new URL(string);
350         return url.sameFile(resource.getURL());     
351     }
352 }
353 
354 
355 
356 
357 
358 
359 
360