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