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