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