1 // ======================================================================== 2 // Copyright 1996-2005 Mort Bay Consulting Pty. Ltd. 3 // ------------------------------------------------------------------------ 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // ======================================================================== 14 package org.mortbay.resource; 15 16 import java.io.File; 17 import java.io.FileOutputStream; 18 import java.io.FilterInputStream; 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.net.JarURLConnection; 22 import java.net.URL; 23 import java.util.jar.JarEntry; 24 import java.util.jar.JarInputStream; 25 26 import org.mortbay.log.Log; 27 import org.mortbay.util.IO; 28 29 30 /* ------------------------------------------------------------ */ 31 public class JarResource extends URLResource 32 { 33 34 protected transient JarURLConnection _jarConnection; 35 36 /* -------------------------------------------------------- */ JarResource(URL url)37 JarResource(URL url) 38 { 39 super(url,null); 40 } 41 42 /* ------------------------------------------------------------ */ JarResource(URL url, boolean useCaches)43 JarResource(URL url, boolean useCaches) 44 { 45 super(url, null, useCaches); 46 } 47 48 /* ------------------------------------------------------------ */ release()49 public synchronized void release() 50 { 51 _jarConnection=null; 52 super.release(); 53 } 54 55 /* ------------------------------------------------------------ */ checkConnection()56 protected boolean checkConnection() 57 { 58 super.checkConnection(); 59 try 60 { 61 if (_jarConnection!=_connection) 62 newConnection(); 63 } 64 catch(IOException e) 65 { 66 Log.ignore(e); 67 _jarConnection=null; 68 } 69 70 return _jarConnection!=null; 71 } 72 73 /* ------------------------------------------------------------ */ 74 /** 75 * @throws IOException Sub-classes of <code>JarResource</code> may throw an IOException (or subclass) 76 */ newConnection()77 protected void newConnection() throws IOException 78 { 79 _jarConnection=(JarURLConnection)_connection; 80 } 81 82 /* ------------------------------------------------------------ */ 83 /** 84 * Returns true if the respresenetd resource exists. 85 */ exists()86 public boolean exists() 87 { 88 if (_urlString.endsWith("!/")) 89 return checkConnection(); 90 else 91 return super.exists(); 92 } 93 94 /* ------------------------------------------------------------ */ getFile()95 public File getFile() 96 throws IOException 97 { 98 return null; 99 } 100 101 /* ------------------------------------------------------------ */ getInputStream()102 public InputStream getInputStream() 103 throws java.io.IOException 104 { 105 checkConnection(); 106 if (!_urlString.endsWith("!/")) 107 return new FilterInputStream(super.getInputStream()) 108 { 109 public void close() throws IOException {this.in=IO.getClosedStream();} 110 }; 111 112 URL url = new URL(_urlString.substring(4,_urlString.length()-2)); 113 InputStream is = url.openStream(); 114 return is; 115 } 116 117 /* ------------------------------------------------------------ */ 118 public static void extract(Resource resource, File directory, boolean deleteOnExit) 119 throws IOException 120 { 121 if(Log.isDebugEnabled())Log.debug("Extract "+resource+" to "+directory); 122 123 124 String urlString = resource.getURL().toExternalForm().trim(); 125 int endOfJarUrl = urlString.indexOf("!/"); 126 int startOfJarUrl = (endOfJarUrl >= 0?4:0); 127 128 if (endOfJarUrl < 0) 129 throw new IOException("Not a valid jar url: "+urlString); 130 131 URL jarFileURL = new URL(urlString.substring(startOfJarUrl, endOfJarUrl)); 132 String subEntryName = (endOfJarUrl+2 < urlString.length() ? urlString.substring(endOfJarUrl + 2) : null); 133 boolean subEntryIsDir = (subEntryName != null && subEntryName.endsWith("/")?true:false); 134 135 if (Log.isDebugEnabled()) Log.debug("Extracting entry = "+subEntryName+" from jar "+jarFileURL); 136 137 InputStream is = jarFileURL.openConnection().getInputStream(); 138 JarInputStream jin = new JarInputStream(is); 139 JarEntry entry; 140 boolean shouldExtract; 141 while((entry=jin.getNextJarEntry())!=null) 142 { 143 String entryName = entry.getName(); 144 145 if ((subEntryName != null) && (entryName.startsWith(subEntryName))) 146 { 147 //if there is a particular subEntry that we are looking for, only 148 //extract it. 149 if (subEntryIsDir) 150 { 151 //if it is a subdirectory we are looking for, then we 152 //are looking to extract its contents into the target 153 //directory. Remove the name of the subdirectory so 154 //that we don't wind up creating it too. 155 entryName = entryName.substring(subEntryName.length()); 156 if (!entryName.equals("")) 157 { 158 //the entry is 159 shouldExtract = true; 160 } 161 else 162 shouldExtract = false; 163 } 164 else 165 shouldExtract = true; 166 } 167 else if ((subEntryName != null) && (!entryName.startsWith(subEntryName))) 168 { 169 //there is a particular entry we are looking for, and this one 170 //isn't it 171 shouldExtract = false; 172 } 173 else 174 { 175 //we are extracting everything 176 shouldExtract = true; 177 } 178 179 180 if (!shouldExtract) 181 { 182 if (Log.isDebugEnabled()) Log.debug("Skipping entry: "+entryName); 183 continue; 184 } 185 186 187 File file=new File(directory,entryName); 188 if (entry.isDirectory()) 189 { 190 // Make directory 191 if (!file.exists()) 192 file.mkdirs(); 193 } 194 else 195 { 196 // make directory (some jars don't list dirs) 197 File dir = new File(file.getParent()); 198 if (!dir.exists()) 199 dir.mkdirs(); 200 201 // Make file 202 FileOutputStream fout = null; 203 try 204 { 205 fout = new FileOutputStream(file); 206 IO.copy(jin,fout); 207 } 208 finally 209 { 210 IO.close(fout); 211 } 212 213 // touch the file. 214 if (entry.getTime()>=0) 215 file.setLastModified(entry.getTime()); 216 } 217 if (deleteOnExit) 218 file.deleteOnExit(); 219 } 220 IO.close(jin); 221 } 222 223 /* ------------------------------------------------------------ */ 224 public void extract(File directory, boolean deleteOnExit) 225 throws IOException 226 { 227 extract(this,directory,deleteOnExit); 228 } 229 } 230