1 /* 2 * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.misc; 27 28 /** 29 * Provides utility functions related to URLClassLoaders or subclasses of it. 30 * 31 * W A R N I N G 32 * 33 * This class uses undocumented, unpublished, private data structures inside 34 * java.net.URLClassLoader and sun.misc.URLClassPath. Use with extreme caution. 35 * 36 * @author tjquinn 37 */ 38 39 40 import java.io.IOException; 41 import java.net.URLClassLoader; 42 import java.util.*; 43 import java.util.jar.JarFile; 44 45 public class ClassLoaderUtil { 46 47 /** 48 * Releases resources held by a URLClassLoader. A new classloader must 49 * be created before the underlying resources can be accessed again. 50 * @param classLoader the instance of URLClassLoader (or a subclass) 51 */ 52 public static void releaseLoader(URLClassLoader classLoader) { 53 releaseLoader(classLoader, null); 54 } 55 56 /** 57 * Releases resources held by a URLClassLoader. Notably, close the jars 58 * opened by the loader. Initializes and updates the List of 59 * jars that have been successfully closed. 60 * <p> 61 * @param classLoader the instance of URLClassLoader (or a subclass) 62 * @param jarsClosed a List of Strings that will contain the names of jars 63 * successfully closed; can be null if the caller does not need the information returned 64 * @return a List of IOExceptions reporting jars that failed to close; null 65 * indicates that an error other than an IOException occurred attempting to 66 * release the loader; empty indicates a successful release; non-empty 67 * indicates at least one error attempting to close an open jar. 68 */ 69 public static List<IOException> releaseLoader(URLClassLoader classLoader, List<String> jarsClosed) { 70 71 List<IOException> ioExceptions = new LinkedList<IOException>(); 72 73 try { 74 /* Records all IOExceptions thrown while closing jar files. */ 75 76 if (jarsClosed != null) { 77 jarsClosed.clear(); 78 } 79 80 URLClassPath ucp = SharedSecrets.getJavaNetAccess() 81 .getURLClassPath(classLoader); 82 ArrayList<?> loaders = ucp.loaders; 83 Stack<?> urls = ucp.urls; 84 HashMap<?,?> lmap = ucp.lmap; 85 86 /* 87 *The urls variable in the URLClassPath object holds URLs that have not yet 88 *been used to resolve a resource or load a class and, therefore, do 89 *not yet have a loader associated with them. Clear the stack so any 90 *future requests that might incorrectly reach the loader cannot be 91 *resolved and cannot open a jar file after we think we've closed 92 *them all. 93 */ 94 synchronized(urls) { 95 urls.clear(); 96 } 97 98 /* 99 *Also clear the map of URLs to loaders so the class loader cannot use 100 *previously-opened jar files - they are about to be closed. 101 */ 102 synchronized(lmap) { 103 lmap.clear(); 104 } 105 106 /* 107 *The URLClassPath object's path variable records the list of all URLs that are on 108 *the URLClassPath's class path. Leave that unchanged. This might 109 *help someone trying to debug why a released class loader is still used. 110 *Because the stack and lmap are now clear, code that incorrectly uses a 111 *the released class loader will trigger an exception if the 112 *class or resource would have been resolved by the class 113 *loader (and no other) if it had not been released. 114 * 115 *The list of URLs might provide some hints to the person as to where 116 *in the code the class loader was set up, which might in turn suggest 117 *where in the code the class loader needs to stop being used. 118 *The URLClassPath does not use the path variable to open new jar 119 *files - it uses the urls Stack for that - so leaving the path variable 120 *will not by itself allow the class loader to continue handling requests. 121 */ 122 123 /* 124 *For each loader, close the jar file associated with that loader. 125 * 126 *The URLClassPath's use of loaders is sync-ed on the entire URLClassPath 127 *object. 128 */ 129 synchronized (ucp) { 130 for (Object o : loaders) { 131 if (o != null) { 132 /* 133 *If the loader is a JarLoader inner class and its jarFile 134 *field is non-null then try to close that jar file. Add 135 *it to the list of closed files if successful. 136 */ 137 if (o instanceof URLClassPath.JarLoader) { 138 URLClassPath.JarLoader jl = (URLClassPath.JarLoader)o; 139 JarFile jarFile = jl.getJarFile(); 140 try { 141 if (jarFile != null) { 142 jarFile.close(); 143 if (jarsClosed != null) { 144 jarsClosed.add(jarFile.getName()); 145 } 146 } 147 } catch (IOException ioe) { 148 /* 149 *Wrap the IOException to identify which jar 150 *could not be closed and add it to the list 151 *of IOExceptions to be returned to the caller. 152 */ 153 String jarFileName = (jarFile == null) ? "filename not available":jarFile.getName(); 154 String msg = "Error closing JAR file: " + jarFileName; 155 IOException newIOE = new IOException(msg); 156 newIOE.initCause(ioe); 157 ioExceptions.add(newIOE); 158 } 159 } 160 } 161 } 162 /* 163 *Now clear the loaders ArrayList. 164 */ 165 loaders.clear(); 166 } 167 } catch (Throwable t) { 168 throw new RuntimeException (t); 169 } 170 return ioExceptions; 171 } 172 }