jdk/src/share/classes/sun/misc/ClassLoaderUtil.java
changeset 22982 9b9414a0aa64
parent 22981 e3195924b412
child 22983 dcf263874c96
equal deleted inserted replaced
22981:e3195924b412 22982:9b9414a0aa64
     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 }