src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java

Mon, 14 Sep 2009 17:13:00 -0700

author
jjg
date
Mon, 14 Sep 2009 17:13:00 -0700
changeset 407
f8be8bf150c3
parent 372
7dbb79875a63
permissions
-rw-r--r--

6881317: regression: NPE in CloseableURLClassLoader
Reviewed-by: darcy

jjg@372 1 /*
jjg@372 2 * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
jjg@372 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@372 4 *
jjg@372 5 * This code is free software; you can redistribute it and/or modify it
jjg@372 6 * under the terms of the GNU General Public License version 2 only, as
jjg@372 7 * published by the Free Software Foundation. Sun designates this
jjg@372 8 * particular file as subject to the "Classpath" exception as provided
jjg@372 9 * by Sun in the LICENSE file that accompanied this code.
jjg@372 10 *
jjg@372 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@372 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@372 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@372 14 * version 2 for more details (a copy is included in the LICENSE file that
jjg@372 15 * accompanied this code).
jjg@372 16 *
jjg@372 17 * You should have received a copy of the GNU General Public License version
jjg@372 18 * 2 along with this work; if not, write to the Free Software Foundation,
jjg@372 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@372 20 *
jjg@372 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
jjg@372 22 * CA 95054 USA or visit www.sun.com if you need additional information or
jjg@372 23 * have any questions.
jjg@372 24 */
jjg@372 25
jjg@372 26 package com.sun.tools.javac.file;
jjg@372 27
jjg@372 28 import java.io.Closeable;
jjg@372 29 import java.io.IOException;
jjg@372 30 import java.lang.reflect.Field;
jjg@372 31 import java.net.URL;
jjg@372 32 import java.net.URLClassLoader;
jjg@372 33 import java.util.ArrayList;
jjg@372 34 import java.util.jar.JarFile;
jjg@372 35
jjg@372 36 /**
jjg@372 37 * A URLClassLoader that also implements Closeable.
jjg@372 38 * Reflection is used to access internal data structures in the URLClassLoader,
jjg@372 39 * since no public API exists for this purpose. Therefore this code is somewhat
jjg@372 40 * fragile. Caveat emptor.
jjg@372 41 * @throws Error if the internal data structures are not as expected.
jjg@372 42 *
jjg@372 43 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
jjg@372 44 * you write code that depends on this, you do so at your own risk.
jjg@372 45 * This code and its internal interfaces are subject to change or
jjg@372 46 * deletion without notice.</b>
jjg@372 47 */
jjg@372 48 class CloseableURLClassLoader
jjg@372 49 extends URLClassLoader implements Closeable {
jjg@372 50 CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
jjg@372 51 super(urls, parent);
jjg@372 52 try {
jjg@372 53 getLoaders(); //proactive check that URLClassLoader is as expected
jjg@372 54 } catch (Throwable t) {
jjg@372 55 throw new Error("cannot create CloseableURLClassLoader", t);
jjg@372 56 }
jjg@372 57 }
jjg@372 58
jjg@372 59 /**
jjg@372 60 * Close any jar files that may have been opened by the class loader.
jjg@372 61 * Reflection is used to access the jar files in the URLClassLoader's
jjg@372 62 * internal data structures.
jjg@372 63 * @throws java.io.IOException if the jar files cannot be found for any
jjg@372 64 * reson, or if closing the jar file itself causes an IOException.
jjg@372 65 */
jjg@372 66 public void close() throws IOException {
jjg@372 67 try {
jjg@372 68 for (Object l: getLoaders()) {
jjg@372 69 if (l.getClass().getName().equals("sun.misc.URLClassPath$JarLoader")) {
jjg@372 70 Field jarField = l.getClass().getDeclaredField("jar");
jjg@372 71 JarFile jar = (JarFile) getField(l, jarField);
jjg@407 72 if (jar != null) {
jjg@407 73 //System.err.println("CloseableURLClassLoader: closing " + jar);
jjg@407 74 jar.close();
jjg@407 75 }
jjg@372 76 }
jjg@372 77 }
jjg@372 78 } catch (Throwable t) {
jjg@372 79 IOException e = new IOException("cannot close class loader");
jjg@372 80 e.initCause(t);
jjg@372 81 throw e;
jjg@372 82 }
jjg@372 83 }
jjg@372 84
jjg@372 85 private ArrayList<?> getLoaders()
jjg@372 86 throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException
jjg@372 87 {
jjg@372 88 Field ucpField = URLClassLoader.class.getDeclaredField("ucp");
jjg@372 89 Object urlClassPath = getField(this, ucpField);
jjg@372 90 if (urlClassPath == null)
jjg@372 91 throw new AssertionError("urlClassPath not set in URLClassLoader");
jjg@372 92 Field loadersField = urlClassPath.getClass().getDeclaredField("loaders");
jjg@372 93 return (ArrayList<?>) getField(urlClassPath, loadersField);
jjg@372 94 }
jjg@372 95
jjg@372 96 private Object getField(Object o, Field f)
jjg@372 97 throws IllegalArgumentException, IllegalAccessException {
jjg@372 98 boolean prev = f.isAccessible();
jjg@372 99 try {
jjg@372 100 f.setAccessible(true);
jjg@372 101 return f.get(o);
jjg@372 102 } finally {
jjg@372 103 f.setAccessible(prev);
jjg@372 104 }
jjg@372 105 }
jjg@372 106
jjg@372 107 }

mercurial