| /* |
| * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.misc; |
| |
| /** |
| * Provides utility functions related to URLClassLoaders or subclasses of it. |
| * |
| * W A R N I N G |
| * |
| * This class uses undocumented, unpublished, private data structures inside |
| * java.net.URLClassLoader and sun.misc.URLClassPath. Use with extreme caution. |
| * |
| * @author tjquinn |
| */ |
| |
| |
| import java.io.IOException; |
| import java.net.URLClassLoader; |
| import java.util.*; |
| import java.util.jar.JarFile; |
| |
| public class ClassLoaderUtil { |
| |
| /** |
| * Releases resources held by a URLClassLoader. A new classloader must |
| * be created before the underlying resources can be accessed again. |
| * @param classLoader the instance of URLClassLoader (or a subclass) |
| */ |
| public static void releaseLoader(URLClassLoader classLoader) { |
| releaseLoader(classLoader, null); |
| } |
| |
| /** |
| * Releases resources held by a URLClassLoader. Notably, close the jars |
| * opened by the loader. Initializes and updates the List of |
| * jars that have been successfully closed. |
| * <p> |
| * @param classLoader the instance of URLClassLoader (or a subclass) |
| * @param jarsClosed a List of Strings that will contain the names of jars |
| * successfully closed; can be null if the caller does not need the information returned |
| * @return a List of IOExceptions reporting jars that failed to close; null |
| * indicates that an error other than an IOException occurred attempting to |
| * release the loader; empty indicates a successful release; non-empty |
| * indicates at least one error attempting to close an open jar. |
| */ |
| public static List<IOException> releaseLoader(URLClassLoader classLoader, List<String> jarsClosed) { |
| |
| List<IOException> ioExceptions = new LinkedList<IOException>(); |
| |
| try { |
| /* Records all IOExceptions thrown while closing jar files. */ |
| |
| if (jarsClosed != null) { |
| jarsClosed.clear(); |
| } |
| |
| URLClassPath ucp = SharedSecrets.getJavaNetAccess() |
| .getURLClassPath(classLoader); |
| ArrayList loaders = ucp.loaders; |
| Stack urls = ucp.urls; |
| HashMap lmap = ucp.lmap; |
| |
| /* |
| *The urls variable in the URLClassPath object holds URLs that have not yet |
| *been used to resolve a resource or load a class and, therefore, do |
| *not yet have a loader associated with them. Clear the stack so any |
| *future requests that might incorrectly reach the loader cannot be |
| *resolved and cannot open a jar file after we think we've closed |
| *them all. |
| */ |
| synchronized(urls) { |
| urls.clear(); |
| } |
| |
| /* |
| *Also clear the map of URLs to loaders so the class loader cannot use |
| *previously-opened jar files - they are about to be closed. |
| */ |
| synchronized(lmap) { |
| lmap.clear(); |
| } |
| |
| /* |
| *The URLClassPath object's path variable records the list of all URLs that are on |
| *the URLClassPath's class path. Leave that unchanged. This might |
| *help someone trying to debug why a released class loader is still used. |
| *Because the stack and lmap are now clear, code that incorrectly uses a |
| *the released class loader will trigger an exception if the |
| *class or resource would have been resolved by the class |
| *loader (and no other) if it had not been released. |
| * |
| *The list of URLs might provide some hints to the person as to where |
| *in the code the class loader was set up, which might in turn suggest |
| *where in the code the class loader needs to stop being used. |
| *The URLClassPath does not use the path variable to open new jar |
| *files - it uses the urls Stack for that - so leaving the path variable |
| *will not by itself allow the class loader to continue handling requests. |
| */ |
| |
| /* |
| *For each loader, close the jar file associated with that loader. |
| * |
| *The URLClassPath's use of loaders is sync-ed on the entire URLClassPath |
| *object. |
| */ |
| synchronized (ucp) { |
| for (Object o : loaders) { |
| if (o != null) { |
| /* |
| *If the loader is a JarLoader inner class and its jarFile |
| *field is non-null then try to close that jar file. Add |
| *it to the list of closed files if successful. |
| */ |
| if (o instanceof URLClassPath.JarLoader) { |
| URLClassPath.JarLoader jl = (URLClassPath.JarLoader)o; |
| JarFile jarFile = jl.getJarFile(); |
| try { |
| if (jarFile != null) { |
| jarFile.close(); |
| if (jarsClosed != null) { |
| jarsClosed.add(jarFile.getName()); |
| } |
| } |
| } catch (IOException ioe) { |
| /* |
| *Wrap the IOException to identify which jar |
| *could not be closed and add it to the list |
| *of IOExceptions to be returned to the caller. |
| */ |
| String jarFileName = (jarFile == null) ? "filename not available":jarFile.getName(); |
| String msg = "Error closing JAR file: " + jarFileName; |
| IOException newIOE = new IOException(msg); |
| newIOE.initCause(ioe); |
| ioExceptions.add(newIOE); |
| } |
| } |
| } |
| } |
| /* |
| *Now clear the loaders ArrayList. |
| */ |
| loaders.clear(); |
| } |
| } catch (Throwable t) { |
| throw new RuntimeException (t); |
| } |
| return ioExceptions; |
| } |
| } |