001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.deployment.util; 018 019 import java.io.BufferedOutputStream; 020 import java.io.File; 021 import java.io.FileInputStream; 022 import java.io.FileNotFoundException; 023 import java.io.FileOutputStream; 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.io.InputStreamReader; 027 import java.io.OutputStream; 028 import java.io.Reader; 029 import java.io.Writer; 030 import java.net.MalformedURLException; 031 import java.net.URL; 032 import java.util.ArrayList; 033 import java.util.Collection; 034 import java.util.Collections; 035 import java.util.Enumeration; 036 import java.util.jar.JarEntry; 037 import java.util.jar.JarFile; 038 import java.util.jar.JarOutputStream; 039 import java.util.jar.Manifest; 040 import java.util.zip.ZipEntry; 041 import java.util.zip.ZipFile; 042 043 /** 044 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 045 */ 046 public final class DeploymentUtil { 047 private DeploymentUtil() { 048 } 049 050 public static final File DUMMY_JAR_FILE; 051 private static final boolean jarUrlRewrite; 052 static { 053 jarUrlRewrite = new Boolean(System.getProperty("org.apache.geronimo.deployment.util.DeploymentUtil.jarUrlRewrite", "false")); 054 try { 055 DUMMY_JAR_FILE = DeploymentUtil.createTempFile(); 056 new JarOutputStream(new FileOutputStream(DeploymentUtil.DUMMY_JAR_FILE), new Manifest()).close(); 057 } catch (IOException e) { 058 throw new ExceptionInInitializerError(e); 059 } 060 } 061 062 // be careful to clean up the temp directory 063 public static File createTempDir() throws IOException { 064 File tempDir = File.createTempFile("geronimo-deploymentUtil", ".tmpdir"); 065 tempDir.delete(); 066 tempDir.mkdirs(); 067 return tempDir; 068 } 069 070 // be careful to clean up the temp file... we tell the vm to delete this on exit 071 // but VMs can't be trusted to acutally delete the file 072 public static File createTempFile() throws IOException { 073 File tempFile = File.createTempFile("geronimo-deploymentUtil", ".tmpdir"); 074 tempFile.deleteOnExit(); 075 return tempFile; 076 } 077 078 // be careful to clean up the temp file... we tell the vm to delete this on exit 079 // but VMs can't be trusted to acutally delete the file 080 private static File createTempFile(String extension) throws IOException { 081 File tempFile = File.createTempFile("geronimo-deploymentUtil", extension == null? ".tmpdir": extension); 082 tempFile.deleteOnExit(); 083 return tempFile; 084 } 085 086 087 public static void copyFile(File source, File destination) throws IOException { 088 File destinationDir = destination.getParentFile(); 089 if (!destinationDir.exists() && !destinationDir.mkdirs()) { 090 throw new java.io.IOException("Cannot create directory : " + destinationDir); 091 } 092 093 InputStream in = null; 094 OutputStream out = null; 095 try { 096 in = new FileInputStream(source); 097 out = new FileOutputStream(destination); 098 writeAll(in, out); 099 } finally { 100 close(in); 101 close(out); 102 } 103 } 104 105 private static void writeAll(InputStream in, OutputStream out) throws IOException { 106 byte[] buffer = new byte[4096]; 107 int count; 108 while ((count = in.read(buffer)) > 0) { 109 out.write(buffer, 0, count); 110 } 111 out.flush(); 112 } 113 public static File toTempFile(JarFile jarFile, String path) throws IOException { 114 return toTempFile(createJarURL(jarFile, path)); 115 } 116 117 public static File toTempFile(URL url) throws IOException { 118 InputStream in = null; 119 OutputStream out = null; 120 JarFile jarFile = null; 121 try { 122 if(url.getProtocol().equalsIgnoreCase("jar")) { 123 // url.openStream() locks the jar file and does not release the lock even after the stream is closed. 124 // This problem is avoided by using JarFile APIs. 125 File file = new File(url.getFile().substring(5, url.getFile().indexOf("!/"))); 126 String path = url.getFile().substring(url.getFile().indexOf("!/")+2); 127 jarFile = new JarFile(file); 128 JarEntry jarEntry = jarFile.getJarEntry(path); 129 if(jarEntry != null) { 130 in = jarFile.getInputStream(jarEntry); 131 } else { 132 throw new FileNotFoundException("JarEntry "+path+" not found in "+file); 133 } 134 } else { 135 in = url.openStream(); 136 } 137 int index = url.getPath().lastIndexOf("."); 138 String extension = null; 139 if (index > 0) { 140 extension = url.getPath().substring(index); 141 } 142 File tempFile = createTempFile(extension); 143 144 out = new FileOutputStream(tempFile); 145 146 writeAll(in, out); 147 return tempFile; 148 } finally { 149 close(out); 150 close(in); 151 close(jarFile); 152 } 153 } 154 155 public static String readAll(URL url) throws IOException { 156 Reader reader = null; 157 JarFile jarFile = null; 158 try { 159 if(url.getProtocol().equalsIgnoreCase("jar")) { 160 // url.openStream() locks the jar file and does not release the lock even after the stream is closed. 161 // This problem is avoided by using JarFile APIs. 162 File file = new File(url.getFile().substring(5, url.getFile().indexOf("!/"))); 163 String path = url.getFile().substring(url.getFile().indexOf("!/")+2); 164 jarFile = new JarFile(file); 165 JarEntry jarEntry = jarFile.getJarEntry(path); 166 if(jarEntry != null) { 167 reader = new InputStreamReader(jarFile.getInputStream(jarEntry)); 168 } else { 169 throw new FileNotFoundException("JarEntry "+path+" not found in "+file); 170 } 171 } else { 172 reader = new InputStreamReader(url.openStream()); 173 } 174 char[] buffer = new char[4000]; 175 StringBuffer out = new StringBuffer(); 176 for(int count = reader.read(buffer); count >= 0; count = reader.read(buffer)) { 177 out.append(buffer, 0, count); 178 } 179 return out.toString(); 180 } finally { 181 close(reader); 182 close(jarFile); 183 } 184 } 185 186 public static File toFile(JarFile jarFile) throws IOException { 187 if (jarFile instanceof UnpackedJarFile) { 188 return ((UnpackedJarFile) jarFile).getBaseDir(); 189 } else { 190 throw new IOException("jarFile is not a directory"); 191 } 192 } 193 194 // be careful with this method as it can leave a temp lying around 195 public static File toFile(JarFile jarFile, String path) throws IOException { 196 if (jarFile instanceof UnpackedJarFile) { 197 File baseDir = ((UnpackedJarFile) jarFile).getBaseDir(); 198 File file = new File(baseDir, path); 199 if (!file.isFile()) { 200 throw new IOException("No such file: " + file.getAbsolutePath()); 201 } 202 return file; 203 } else { 204 String urlString = "jar:" + new File(jarFile.getName()).toURL() + "!/" + path; 205 return toTempFile(new URL(urlString)); 206 } 207 } 208 209 public static URL createJarURL(JarFile jarFile, String path) throws MalformedURLException { 210 if (jarFile instanceof NestedJarFile) { 211 NestedJarFile nestedJar = (NestedJarFile) jarFile; 212 if (nestedJar.isUnpacked()) { 213 JarFile baseJar = nestedJar.getBaseJar(); 214 String basePath = nestedJar.getBasePath(); 215 if (baseJar instanceof UnpackedJarFile) { 216 File baseDir = ((UnpackedJarFile) baseJar).getBaseDir(); 217 baseDir = new File(baseDir, basePath); 218 return new File(baseDir, path).toURL(); 219 } 220 } 221 } 222 223 if (jarFile instanceof UnpackedJarFile) { 224 File baseDir = ((UnpackedJarFile) jarFile).getBaseDir(); 225 return new File(baseDir, path).toURL(); 226 } else { 227 String urlString = "jar:" + new File(jarFile.getName()).toURL() + "!/" + path; 228 if(jarUrlRewrite) { 229 // To prevent the lockout of archive, instead of returning a jar url, write the content to a 230 // temp file and return the url of that file. 231 File tempFile = null; 232 try { 233 tempFile = toTempFile(new URL(urlString)); 234 } catch (IOException e) { 235 // The JarEntry does not exist! 236 // Return url of a file that does not exist. 237 try { 238 tempFile = createTempFile(); 239 tempFile.delete(); 240 } catch (IOException ignored) { 241 } 242 } 243 return tempFile.toURL(); 244 } else { 245 return new URL(urlString); 246 } 247 } 248 } 249 250 public static JarFile createJarFile(File jarFile) throws IOException { 251 if (jarFile.isDirectory()) { 252 return new UnpackedJarFile(jarFile); 253 } else { 254 return new JarFile(jarFile); 255 } 256 } 257 258 public static void copyToPackedJar(JarFile inputJar, File outputFile) throws IOException { 259 if (inputJar.getClass() == JarFile.class) { 260 // this is a plain old jar... nothign special 261 copyFile(new File(inputJar.getName()), outputFile); 262 } else if (inputJar instanceof NestedJarFile && ((NestedJarFile)inputJar).isPacked()) { 263 NestedJarFile nestedJarFile = (NestedJarFile)inputJar; 264 JarFile baseJar = nestedJarFile.getBaseJar(); 265 String basePath = nestedJarFile.getBasePath(); 266 if (baseJar instanceof UnpackedJarFile) { 267 // our target jar is just a file in upacked jar (a plain old directory)... now 268 // we just need to find where it is and copy it to the outptu 269 copyFile(((UnpackedJarFile)baseJar).getFile(basePath), outputFile); 270 } else { 271 // out target is just a plain old jar file directly accessabel from the file system 272 copyFile(new File(baseJar.getName()), outputFile); 273 } 274 } else { 275 // copy out the module contents to a standalone jar file (entry by entry) 276 JarOutputStream out = null; 277 try { 278 out = new JarOutputStream(new FileOutputStream(outputFile)); 279 byte[] buffer = new byte[4096]; 280 Enumeration entries = inputJar.entries(); 281 while (entries.hasMoreElements()) { 282 ZipEntry entry = (ZipEntry) entries.nextElement(); 283 InputStream in = inputJar.getInputStream(entry); 284 try { 285 out.putNextEntry(new ZipEntry(entry.getName())); 286 try { 287 int count; 288 while ((count = in.read(buffer)) > 0) { 289 out.write(buffer, 0, count); 290 } 291 } finally { 292 out.closeEntry(); 293 } 294 } finally { 295 close(in); 296 } 297 } 298 } finally { 299 close(out); 300 } 301 } 302 } 303 304 public static void jarDirectory(File sourceDirecotry, File destinationFile) throws IOException { 305 JarFile inputJar = new UnpackedJarFile(sourceDirecotry); 306 try { 307 copyToPackedJar(inputJar, destinationFile); 308 } finally { 309 close(inputJar); 310 } 311 } 312 313 private static void createDirectory(File dir) throws IOException { 314 if (dir != null && !dir.exists()) { 315 boolean success = dir.mkdirs(); 316 if (!success) { 317 throw new IOException("Cannot create directory " + dir.getAbsolutePath()); 318 } 319 } 320 } 321 322 public static void unzipToDirectory(ZipFile zipFile, File destDir) throws IOException { 323 Enumeration entries = zipFile.entries(); 324 try { 325 while (entries.hasMoreElements()) { 326 ZipEntry entry = (ZipEntry) entries.nextElement(); 327 if (entry.isDirectory()) { 328 File dir = new File(destDir, entry.getName()); 329 createDirectory(dir); 330 } else { 331 File file = new File(destDir, entry.getName()); 332 createDirectory(file.getParentFile()); 333 OutputStream out = null; 334 InputStream in = null; 335 try { 336 out = new BufferedOutputStream(new FileOutputStream(file)); 337 in = zipFile.getInputStream(entry); 338 writeAll(in, out); 339 } finally { 340 if (null != out) { 341 out.close(); 342 } 343 if (null != in) { 344 in.close(); 345 } 346 } 347 } 348 } 349 } finally { 350 zipFile.close(); 351 } 352 } 353 354 355 public static boolean recursiveDelete(File root, Collection<String> unableToDeleteCollection) { 356 if (root == null) { 357 return true; 358 } 359 360 if (root.isDirectory()) { 361 File[] files = root.listFiles(); 362 if (files != null) { 363 for (int i = 0; i < files.length; i++) { 364 File file = files[i]; 365 if (file.isDirectory()) { 366 recursiveDelete(file, unableToDeleteCollection); 367 } else { 368 if (!file.delete() && unableToDeleteCollection != null) { 369 unableToDeleteCollection.add(file.getAbsolutePath()); 370 } 371 } 372 // help out the GC of file handles by nulling the references 373 files[i] = null; 374 } 375 } 376 } 377 boolean rootDeleteStatus; 378 if (!(rootDeleteStatus = root.delete()) && unableToDeleteCollection != null) 379 unableToDeleteCollection.add(root.getAbsolutePath()); 380 381 return rootDeleteStatus; 382 } 383 384 public static boolean recursiveDelete(File root) { 385 return recursiveDelete(root, null); 386 } 387 388 public static Collection<File> listRecursiveFiles(File file) { 389 Collection<File> list = new ArrayList<File>(); 390 listRecursiveFiles(file, list); 391 return Collections.unmodifiableCollection(list); 392 } 393 394 public static void listRecursiveFiles(File file, Collection<File> collection) { 395 File[] files = file.listFiles(); 396 if ( null == files ) { 397 return; 398 } 399 for (File file1 : files) { 400 collection.add(file1); 401 if (file1.isDirectory()) { 402 listRecursiveFiles(file1, collection); 403 } 404 } 405 } 406 407 public static void flush(OutputStream thing) { 408 if (thing != null) { 409 try { 410 thing.flush(); 411 } catch(Exception ignored) { 412 } 413 } 414 } 415 416 public static void flush(Writer thing) { 417 if (thing != null) { 418 try { 419 thing.flush(); 420 } catch(Exception ignored) { 421 } 422 } 423 } 424 425 public static void close(JarFile thing) { 426 if (thing != null) { 427 try { 428 thing.close(); 429 } catch(Exception ignored) { 430 } 431 } 432 } 433 434 public static void close(InputStream thing) { 435 if (thing != null) { 436 try { 437 thing.close(); 438 } catch(Exception ignored) { 439 } 440 } 441 } 442 443 public static void close(OutputStream thing) { 444 if (thing != null) { 445 try { 446 thing.close(); 447 } catch(Exception ignored) { 448 } 449 } 450 } 451 452 public static void close(Reader thing) { 453 if (thing != null) { 454 try { 455 thing.close(); 456 } catch(Exception ignored) { 457 } 458 } 459 } 460 461 public static void close(Writer thing) { 462 if (thing != null) { 463 try { 464 thing.close(); 465 } catch(Exception ignored) { 466 } 467 } 468 } 469 470 public static final class EmptyInputStream extends InputStream { 471 public int read() { 472 return -1; 473 } 474 475 public int read(byte b[]) { 476 return -1; 477 } 478 479 public int read(byte b[], int off, int len) { 480 return -1; 481 } 482 483 public long skip(long n) { 484 return 0; 485 } 486 487 public int available() { 488 return 0; 489 } 490 491 public void close() { 492 } 493 494 public synchronized void mark(int readlimit) { 495 } 496 497 public synchronized void reset() { 498 } 499 500 public boolean markSupported() { 501 return false; 502 } 503 } 504 }