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      private JarFile _jarFile;
31      private File _file;
32      private String[] _list;
33      private JarEntry _entry;
34      private boolean _directory;
35      private String _jarUrl;
36      private String _path;
37      private boolean _exists;
38      
39      /* -------------------------------------------------------- */
40      JarFileResource(URL url)
41      {
42          super(url);
43      }
44      
45      /* ------------------------------------------------------------ */
46      JarFileResource(URL url, boolean useCaches)
47      {
48          super(url, useCaches);
49      }
50     
51  
52      /* ------------------------------------------------------------ */
53      @Override
54      public synchronized void release()
55      {
56          _list=null;
57          _entry=null;
58          _file=null;
59          _jarFile=null;
60          super.release();
61      }
62      
63      /* ------------------------------------------------------------ */
64      @Override
65      protected boolean checkConnection()
66      {
67          try
68          {
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 synchronized 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                 if (_directory && !_urlString.endsWith("/"))
190                 {
191                     _urlString+="/";
192                     try
193                     {
194                         _url=new URL(_urlString);
195                     }
196                     catch(MalformedURLException ex)
197                     {
198                         Log.warn(ex);
199                     }
200                 }
201             }
202         }    
203         
204         _exists= ( _directory || _entry!=null);
205         return _exists;
206     }
207 
208     
209     /* ------------------------------------------------------------ */
210     /**
211      * Returns true if the represented resource is a container/directory.
212      * If the resource is not a file, resources ending with "/" are
213      * considered directories.
214      */
215     @Override
216     public boolean isDirectory()
217     {
218         return _urlString.endsWith("/") || exists() && _directory;
219     }
220     
221     /* ------------------------------------------------------------ */
222     /**
223      * Returns the last modified time
224      */
225     @Override
226     public long lastModified()
227     {
228         if (checkConnection() && _file!=null)
229             return _file.lastModified();
230         return -1;
231     }
232 
233     /* ------------------------------------------------------------ */
234     @Override
235     public synchronized String[] list()
236     {
237         
238         if(isDirectory() && _list==null)
239         {
240             ArrayList list = new ArrayList(32);
241 
242             checkConnection();
243             
244             JarFile jarFile=_jarFile;
245             if(jarFile==null)
246             {
247                 try
248                 {
249                     JarURLConnection jc=(JarURLConnection)((new URL(_jarUrl)).openConnection());
250                     jc.setUseCaches(getUseCaches());
251                     jarFile=jc.getJarFile();
252                 }
253                 catch(Exception e)
254                 {
255                      Log.ignore(e);
256                 }
257             }
258             
259             Enumeration e=jarFile.entries();
260             String dir=_urlString.substring(_urlString.indexOf("!/")+2);
261             while(e.hasMoreElements())
262             {
263                 
264                 JarEntry entry = (JarEntry) e.nextElement();               
265                 String name=entry.getName().replace('\\','/');               
266                 if(!name.startsWith(dir) || name.length()==dir.length())
267                 {
268                     continue;
269                 }
270                 String listName=name.substring(dir.length());               
271                 int dash=listName.indexOf('/');
272                 if (dash>=0)
273                 {
274                     //when listing jar:file urls, you get back one
275                     //entry for the dir itself, which we ignore
276                     if (dash==0 && listName.length()==1)
277                         continue;
278                     //when listing jar:file urls, all files and
279                     //subdirs have a leading /, which we remove
280                     if (dash==0)
281                         listName=listName.substring(dash+1, listName.length());
282                     else
283                         listName=listName.substring(0,dash+1);
284                     
285                     if (list.contains(listName))
286                         continue;
287                 }
288                 
289                 list.add(listName);
290             }
291             
292             _list=new String[list.size()];
293             list.toArray(_list);
294         }
295         return _list;
296     }
297     
298     /* ------------------------------------------------------------ */
299     /**
300      * Return the length of the resource
301      */
302     @Override
303     public long length()
304     {
305         if (isDirectory())
306             return -1;
307 
308         if (_entry!=null)
309             return _entry.getSize();
310         
311         return -1;
312     }
313     
314     /* ------------------------------------------------------------ */
315     /** Encode according to this resource type.
316      * File URIs are not encoded.
317      * @param uri URI to encode.
318      * @return The uri unchanged.
319      */
320     @Override
321     public String encode(String uri)
322     {
323         return uri;
324     }
325 
326     
327     /**
328      * Take a Resource that possibly might use URLConnection caching
329      * and turn it into one that doesn't.
330      * @param resource
331      * @return the non-caching resource
332      */
333     public static Resource getNonCachingResource (Resource resource)
334     {
335         if (!(resource instanceof JarFileResource))
336             return resource;
337         
338         JarFileResource oldResource = (JarFileResource)resource;
339         
340         JarFileResource newResource = new JarFileResource(oldResource.getURL(), false);
341         return newResource;
342         
343     }
344     
345     /**
346      * Check if this jar:file: resource is contained in the
347      * named resource. Eg <code>jar:file:///a/b/c/foo.jar!/x.html</code> isContainedIn <code>file:///a/b/c/foo.jar</code>
348      * @param resource
349      * @return true if resource is contained in the named resource
350      * @throws MalformedURLException
351      */
352     @Override
353     public boolean isContainedIn (Resource resource) 
354     throws MalformedURLException
355     {
356         String string = _urlString;
357         int index = string.indexOf("!/");
358         if (index > 0)
359             string = string.substring(0,index);
360         if (string.startsWith("jar:"))
361             string = string.substring(4);
362         URL url = new URL(string);
363         return url.sameFile(resource.getURL());     
364     }
365 }
366 
367 
368 
369 
370 
371 
372 
373