2.6URLClassLoader源码解析

  1. /* 
  2.  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 
  3.  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 
  4.  * 
  5.  * 
  6.  * 
  7.  * 
  8.  * 
  9.  * 
  10.  * 
  11.  * 
  12.  * 
  13.  * 
  14.  * 
  15.  * 
  16.  * 
  17.  * 
  18.  * 
  19.  * 
  20.  * 
  21.  * 
  22.  * 
  23.  * 
  24.  */  
  25.   
  26. package java.net;  
  27.   
  28. import java.lang.reflect.Method;  
  29. import java.lang.reflect.Modifier;  
  30. import java.lang.ref.*;  
  31. import java.io.*;  
  32. import java.net.URL;  
  33. import java.net.URLConnection;  
  34. import java.net.URLStreamHandlerFactory;  
  35. import java.util.Enumeration;  
  36. import java.util.*;  
  37. import java.util.jar.Manifest;  
  38. import java.util.jar.JarFile;  
  39. import java.util.jar.Attributes;  
  40. import java.util.jar.Attributes.Name;  
  41. import java.security.CodeSigner;  
  42. import java.security.PrivilegedAction;  
  43. import java.security.PrivilegedExceptionAction;  
  44. import java.security.AccessController;  
  45. import java.security.AccessControlContext;  
  46. import java.security.SecureClassLoader;  
  47. import java.security.CodeSource;  
  48. import java.security.Permission;  
  49. import java.security.PermissionCollection;  
  50. import sun.misc.Resource;  
  51. import sun.misc.URLClassPath;  
  52. import sun.net.www.ParseUtil;  
  53. import sun.security.util.SecurityConstants;  
  54.   
  55. /** 
  56.  * This class loader is used to load classes and resources from a search 
  57.  * path of URLs referring to both JAR files and directories. Any URL that 
  58.  * ends with a '/' is assumed to refer to a directory. Otherwise, the URL 
  59.  * is assumed to refer to a JAR file which will be opened as needed. 
  60.  * <p> 
  61.  * The AccessControlContext of the thread that created the instance of 
  62.  * URLClassLoader will be used when subsequently loading classes and 
  63.  * resources. 
  64.  * <p> 
  65.  * The classes that are loaded are by default granted permission only to 
  66.  * access the URLs specified when the URLClassLoader was created. 
  67.  * 
  68.  * @author  David Connelly 
  69.  * @since   1.2 
  70.  */  
  71. public class URLClassLoader extends SecureClassLoader implements Closeable {  
  72.     /* The search path for classes and resources */  
  73.     private final URLClassPath ucp;  
  74.   
  75.     /* The context to be used when loading classes and resources */  
  76.     private final AccessControlContext acc;  
  77.   
  78.     /** 
  79.      * Constructs a new URLClassLoader for the given URLs. The URLs will be 
  80.      * searched in the order specified for classes and resources after first 
  81.      * searching in the specified parent class loader. Any URL that ends with 
  82.      * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed 
  83.      * to refer to a JAR file which will be downloaded and opened as needed. 
  84.      * 
  85.      * <p>If there is a security manager, this method first 
  86.      * calls the security manager's {@code checkCreateClassLoader} method 
  87.      * to ensure creation of a class loader is allowed. 
  88.      * 
  89.      * @param urls the URLs from which to load classes and resources 
  90.      * @param parent the parent class loader for delegation 
  91.      * @exception  SecurityException  if a security manager exists and its 
  92.      *             {@code checkCreateClassLoader} method doesn't allow 
  93.      *             creation of a class loader. 
  94.      * @see SecurityManager#checkCreateClassLoader 
  95.      */  
  96.     public URLClassLoader(URL[] urls, ClassLoader parent) {  
  97.         super(parent);  
  98.         // this is to make the stack depth consistent with 1.1  
  99.         SecurityManager security = System.getSecurityManager();  
  100.         if (security != null) {  
  101.             security.checkCreateClassLoader();  
  102.         }  
  103.         ucp = new URLClassPath(urls);  
  104.         this.acc = AccessController.getContext();  
  105.     }  
  106.   
  107.     URLClassLoader(URL[] urls, ClassLoader parent,  
  108.                    AccessControlContext acc) {  
  109.         super(parent);  
  110.         // this is to make the stack depth consistent with 1.1  
  111.         SecurityManager security = System.getSecurityManager();  
  112.         if (security != null) {  
  113.             security.checkCreateClassLoader();  
  114.         }  
  115.         ucp = new URLClassPath(urls);  
  116.         this.acc = acc;  
  117.     }  
  118.   
  119.     /** 
  120.      * Constructs a new URLClassLoader for the specified URLs using the 
  121.      * default delegation parent <code>ClassLoader</code>. The URLs will 
  122.      * be searched in the order specified for classes and resources after 
  123.      * first searching in the parent class loader. Any URL that ends with 
  124.      * a '/' is assumed to refer to a directory. Otherwise, the URL is 
  125.      * assumed to refer to a JAR file which will be downloaded and opened 
  126.      * as needed. 
  127.      * 
  128.      * <p>If there is a security manager, this method first 
  129.      * calls the security manager's <code>checkCreateClassLoader</code> method 
  130.      * to ensure creation of a class loader is allowed. 
  131.      * 
  132.      * @param urls the URLs from which to load classes and resources 
  133.      * 
  134.      * @exception  SecurityException  if a security manager exists and its 
  135.      *             <code>checkCreateClassLoader</code> method doesn't allow 
  136.      *             creation of a class loader. 
  137.      * @see SecurityManager#checkCreateClassLoader 
  138.      */  
  139.     public URLClassLoader(URL[] urls) {  
  140.         super();  
  141.         // this is to make the stack depth consistent with 1.1  
  142.         SecurityManager security = System.getSecurityManager();  
  143.         if (security != null) {  
  144.             security.checkCreateClassLoader();  
  145.         }  
  146.         ucp = new URLClassPath(urls);  
  147.         this.acc = AccessController.getContext();  
  148.     }  
  149.   
  150.     URLClassLoader(URL[] urls, AccessControlContext acc) {  
  151.         super();  
  152.         // this is to make the stack depth consistent with 1.1  
  153.         SecurityManager security = System.getSecurityManager();  
  154.         if (security != null) {  
  155.             security.checkCreateClassLoader();  
  156.         }  
  157.         ucp = new URLClassPath(urls);  
  158.         this.acc = acc;  
  159.     }  
  160.   
  161.     /** 
  162.      * Constructs a new URLClassLoader for the specified URLs, parent 
  163.      * class loader, and URLStreamHandlerFactory. The parent argument 
  164.      * will be used as the parent class loader for delegation. The 
  165.      * factory argument will be used as the stream handler factory to 
  166.      * obtain protocol handlers when creating new jar URLs. 
  167.      * 
  168.      * <p>If there is a security manager, this method first 
  169.      * calls the security manager's <code>checkCreateClassLoader</code> method 
  170.      * to ensure creation of a class loader is allowed. 
  171.      * 
  172.      * @param urls the URLs from which to load classes and resources 
  173.      * @param parent the parent class loader for delegation 
  174.      * @param factory the URLStreamHandlerFactory to use when creating URLs 
  175.      * 
  176.      * @exception  SecurityException  if a security manager exists and its 
  177.      *             <code>checkCreateClassLoader</code> method doesn't allow 
  178.      *             creation of a class loader. 
  179.      * @see SecurityManager#checkCreateClassLoader 
  180.      */  
  181.     public URLClassLoader(URL[] urls, ClassLoader parent,  
  182.                           URLStreamHandlerFactory factory) {  
  183.         super(parent);  
  184.         // this is to make the stack depth consistent with 1.1  
  185.         SecurityManager security = System.getSecurityManager();  
  186.         if (security != null) {  
  187.             security.checkCreateClassLoader();  
  188.         }  
  189.         ucp = new URLClassPath(urls, factory);  
  190.         acc = AccessController.getContext();  
  191.     }  
  192.   
  193.     /* A map (used as a set) to keep track of closeable local resources 
  194.      * (either JarFiles or FileInputStreams). We don't care about 
  195.      * Http resources since they don't need to be closed. 
  196.      * 
  197.      * If the resource is coming from a jar file 
  198.      * we keep a (weak) reference to the JarFile object which can 
  199.      * be closed if URLClassLoader.close() called. Due to jar file 
  200.      * caching there will typically be only one JarFile object 
  201.      * per underlying jar file. 
  202.      * 
  203.      * For file resources, which is probably a less common situation 
  204.      * we have to keep a weak reference to each stream. 
  205.      */  
  206.   
  207.     private WeakHashMap<Closeable,Void>  
  208.         closeables = new WeakHashMap<>();  
  209.   
  210.     /** 
  211.      * Returns an input stream for reading the specified resource. 
  212.      * If this loader is closed, then any resources opened by this method 
  213.      * will be closed. 
  214.      * 
  215.      * <p> The search order is described in the documentation for {@link 
  216.      * #getResource(String)}.  </p> 
  217.      * 
  218.      * @param  name 
  219.      *         The resource name 
  220.      * 
  221.      * @return  An input stream for reading the resource, or <tt>null</tt> 
  222.      *          if the resource could not be found 
  223.      * 
  224.      * @since  1.7 
  225.      */  
  226.     public InputStream getResourceAsStream(String name) {  
  227.         URL url = getResource(name);  
  228.         try {  
  229.             if (url == null) {  
  230.                 return null;  
  231.             }  
  232.             URLConnection urlc = url.openConnection();  
  233.             InputStream is = urlc.getInputStream();  
  234.             if (urlc instanceof JarURLConnection) {  
  235.                 JarURLConnection juc = (JarURLConnection)urlc;  
  236.                 JarFile jar = juc.getJarFile();  
  237.                 synchronized (closeables) {  
  238.                     if (!closeables.containsKey(jar)) {  
  239.                         closeables.put(jar, null);  
  240.                     }  
  241.                 }  
  242.             } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {  
  243.                 synchronized (closeables) {  
  244.                     closeables.put(is, null);  
  245.                 }  
  246.             }  
  247.             return is;  
  248.         } catch (IOException e) {  
  249.             return null;  
  250.         }  
  251.     }  
  252.   
  253.    /** 
  254.     * Closes this URLClassLoader, so that it can no longer be used to load 
  255.     * new classes or resources that are defined by this loader. 
  256.     * Classes and resources defined by any of this loader's parents in the 
  257.     * delegation hierarchy are still accessible. Also, any classes or resources 
  258.     * that are already loaded, are still accessible. 
  259.     * <p> 
  260.     * In the case of jar: and file: URLs, it also closes any files 
  261.     * that were opened by it. If another thread is loading a 
  262.     * class when the {@code close} method is invoked, then the result of 
  263.     * that load is undefined. 
  264.     * <p> 
  265.     * The method makes a best effort attempt to close all opened files, 
  266.     * by catching {@link IOException}s internally. Unchecked exceptions 
  267.     * and errors are not caught. Calling close on an already closed 
  268.     * loader has no effect. 
  269.     * <p> 
  270.     * @throws IOException if closing any file opened by this class loader 
  271.     * resulted in an IOException. Any such exceptions are caught internally. 
  272.     * If only one is caught, then it is re-thrown. If more than one exception 
  273.     * is caught, then the second and following exceptions are added 
  274.     * as suppressed exceptions of the first one caught, which is then re-thrown. 
  275.     * 
  276.     * @throws SecurityException if a security manager is set, and it denies 
  277.     *   {@link RuntimePermission}<tt>("closeClassLoader")</tt> 
  278.     * 
  279.     * @since 1.7 
  280.     */  
  281.     public void close() throws IOException {  
  282.         SecurityManager security = System.getSecurityManager();  
  283.         if (security != null) {  
  284.             security.checkPermission(new RuntimePermission("closeClassLoader"));  
  285.         }  
  286.         List<IOException> errors = ucp.closeLoaders();  
  287.   
  288.         // now close any remaining streams.  
  289.   
  290.         synchronized (closeables) {  
  291.             Set<Closeable> keys = closeables.keySet();  
  292.             for (Closeable c : keys) {  
  293.                 try {  
  294.                     c.close();  
  295.                 } catch (IOException ioex) {  
  296.                     errors.add(ioex);  
  297.                 }  
  298.             }  
  299.             closeables.clear();  
  300.         }  
  301.   
  302.         if (errors.isEmpty()) {  
  303.             return;  
  304.         }  
  305.   
  306.         IOException firstex = errors.remove(0);  
  307.   
  308.         // Suppress any remaining exceptions  
  309.   
  310.         for (IOException error: errors) {  
  311.             firstex.addSuppressed(error);  
  312.         }  
  313.         throw firstex;  
  314.     }  
  315.   
  316.     /** 
  317.      * Appends the specified URL to the list of URLs to search for 
  318.      * classes and resources. 
  319.      * <p> 
  320.      * If the URL specified is <code>null</code> or is already in the 
  321.      * list of URLs, or if this loader is closed, then invoking this 
  322.      * method has no effect. 
  323.      * 
  324.      * @param url the URL to be added to the search path of URLs 
  325.      */  
  326.     protected void addURL(URL url) {  
  327.         ucp.addURL(url);  
  328.     }  
  329.   
  330.     /** 
  331.      * Returns the search path of URLs for loading classes and resources. 
  332.      * This includes the original list of URLs specified to the constructor, 
  333.      * along with any URLs subsequently appended by the addURL() method. 
  334.      * @return the search path of URLs for loading classes and resources. 
  335.      */  
  336.     public URL[] getURLs() {  
  337.         return ucp.getURLs();  
  338.     }  
  339.   
  340.     /** 
  341.      * Finds and loads the class with the specified name from the URL search 
  342.      * path. Any URLs referring to JAR files are loaded and opened as needed 
  343.      * until the class is found. 
  344.      * 
  345.      * @param name the name of the class 
  346.      * @return the resulting class 
  347.      * @exception ClassNotFoundException if the class could not be found, 
  348.      *            or if the loader is closed. 
  349.      */  
  350.     protected Class<?> findClass(final String name)  
  351.          throws ClassNotFoundException  
  352.     {  
  353.         try {  
  354.             return AccessController.doPrivileged(  
  355.                 new PrivilegedExceptionAction<Class>() {  
  356.                     public Class run() throws ClassNotFoundException {  
  357.                         String path = name.replace('.''/').concat(".class");  
  358.                         Resource res = ucp.getResource(path, false);  
  359.                         if (res != null) {  
  360.                             try {  
  361.                                 return defineClass(name, res);  
  362.                             } catch (IOException e) {  
  363.                                 throw new ClassNotFoundException(name, e);  
  364.                             }  
  365.                         } else {  
  366.                             throw new ClassNotFoundException(name);  
  367.                         }  
  368.                     }  
  369.                 }, acc);  
  370.         } catch (java.security.PrivilegedActionException pae) {  
  371.             throw (ClassNotFoundException) pae.getException();  
  372.         }  
  373.     }  
  374.   
  375.     /* 
  376.      * Retrieve the package using the specified package name. 
  377.      * If non-null, verify the package using the specified code 
  378.      * source and manifest. 
  379.      */  
  380.     private Package getAndVerifyPackage(String pkgname,  
  381.                                         Manifest man, URL url) {  
  382.         Package pkg = getPackage(pkgname);  
  383.         if (pkg != null) {  
  384.             // Package found, so check package sealing.  
  385.             if (pkg.isSealed()) {  
  386.                 // Verify that code source URL is the same.  
  387.                 if (!pkg.isSealed(url)) {  
  388.                     throw new SecurityException(  
  389.                         "sealing violation: package " + pkgname + " is sealed");  
  390.                 }  
  391.             } else {  
  392.                 // Make sure we are not attempting to seal the package  
  393.                 // at this code source URL.  
  394.                 if ((man != null) && isSealed(pkgname, man)) {  
  395.                     throw new SecurityException(  
  396.                         "sealing violation: can't seal package " + pkgname +  
  397.                         ": already loaded");  
  398.                 }  
  399.             }  
  400.         }  
  401.         return pkg;  
  402.     }  
  403.   
  404.     /* 
  405.      * Defines a Class using the class bytes obtained from the specified 
  406.      * Resource. The resulting Class must be resolved before it can be 
  407.      * used. 
  408.      */  
  409.     private Class defineClass(String name, Resource res) throws IOException {  
  410.         long t0 = System.nanoTime();  
  411.         int i = name.lastIndexOf('.');  
  412.         URL url = res.getCodeSourceURL();  
  413.         if (i != -1) {  
  414.             String pkgname = name.substring(0, i);  
  415.             // Check if package already loaded.  
  416.             Manifest man = res.getManifest();  
  417.             if (getAndVerifyPackage(pkgname, man, url) == null) {  
  418.                 try {  
  419.                     if (man != null) {  
  420.                         definePackage(pkgname, man, url);  
  421.                     } else {  
  422.                         definePackage(pkgname, nullnullnullnullnullnullnull);  
  423.                     }  
  424.                 } catch (IllegalArgumentException iae) {  
  425.                     // parallel-capable class loaders: re-verify in case of a  
  426.                     // race condition  
  427.                     if (getAndVerifyPackage(pkgname, man, url) == null) {  
  428.                         // Should never happen  
  429.                         throw new AssertionError("Cannot find package " +  
  430.                                                  pkgname);  
  431.                     }  
  432.                 }  
  433.             }  
  434.         }  
  435.         // Now read the class bytes and define the class  
  436.         java.nio.ByteBuffer bb = res.getByteBuffer();  
  437.         if (bb != null) {  
  438.             // Use (direct) ByteBuffer:  
  439.             CodeSigner[] signers = res.getCodeSigners();  
  440.             CodeSource cs = new CodeSource(url, signers);  
  441.             sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);  
  442.             return defineClass(name, bb, cs);  
  443.         } else {  
  444.             byte[] b = res.getBytes();  
  445.             // must read certificates AFTER reading bytes.  
  446.             CodeSigner[] signers = res.getCodeSigners();  
  447.             CodeSource cs = new CodeSource(url, signers);  
  448.             sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);  
  449.             return defineClass(name, b, 0, b.length, cs);  
  450.         }  
  451.     }  
  452.   
  453.     /** 
  454.      * Defines a new package by name in this ClassLoader. The attributes 
  455.      * contained in the specified Manifest will be used to obtain package 
  456.      * version and sealing information. For sealed packages, the additional 
  457.      * URL specifies the code source URL from which the package was loaded. 
  458.      * 
  459.      * @param name  the package name 
  460.      * @param man   the Manifest containing package version and sealing 
  461.      *              information 
  462.      * @param url   the code source url for the package, or null if none 
  463.      * @exception   IllegalArgumentException if the package name duplicates 
  464.      *              an existing package either in this class loader or one 
  465.      *              of its ancestors 
  466.      * @return the newly defined Package object 
  467.      */  
  468.     protected Package definePackage(String name, Manifest man, URL url)  
  469.         throws IllegalArgumentException  
  470.     {  
  471.         String path = name.replace('.''/').concat("/");  
  472.         String specTitle = null, specVersion = null, specVendor = null;  
  473.         String implTitle = null, implVersion = null, implVendor = null;  
  474.         String sealed = null;  
  475.         URL sealBase = null;  
  476.   
  477.         Attributes attr = man.getAttributes(path);  
  478.         if (attr != null) {  
  479.             specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);  
  480.             specVersion = attr.getValue(Name.SPECIFICATION_VERSION);  
  481.             specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);  
  482.             implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);  
  483.             implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);  
  484.             implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);  
  485.             sealed      = attr.getValue(Name.SEALED);  
  486.         }  
  487.         attr = man.getMainAttributes();  
  488.         if (attr != null) {  
  489.             if (specTitle == null) {  
  490.                 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);  
  491.             }  
  492.             if (specVersion == null) {  
  493.                 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);  
  494.             }  
  495.             if (specVendor == null) {  
  496.                 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);  
  497.             }  
  498.             if (implTitle == null) {  
  499.                 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);  
  500.             }  
  501.             if (implVersion == null) {  
  502.                 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);  
  503.             }  
  504.             if (implVendor == null) {  
  505.                 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);  
  506.             }  
  507.             if (sealed == null) {  
  508.                 sealed = attr.getValue(Name.SEALED);  
  509.             }  
  510.         }  
  511.         if ("true".equalsIgnoreCase(sealed)) {  
  512.             sealBase = url;  
  513.         }  
  514.         return definePackage(name, specTitle, specVersion, specVendor,  
  515.                              implTitle, implVersion, implVendor, sealBase);  
  516.     }  
  517.   
  518.     /* 
  519.      * Returns true if the specified package name is sealed according to the 
  520.      * given manifest. 
  521.      */  
  522.     private boolean isSealed(String name, Manifest man) {  
  523.         String path = name.replace('.''/').concat("/");  
  524.         Attributes attr = man.getAttributes(path);  
  525.         String sealed = null;  
  526.         if (attr != null) {  
  527.             sealed = attr.getValue(Name.SEALED);  
  528.         }  
  529.         if (sealed == null) {  
  530.             if ((attr = man.getMainAttributes()) != null) {  
  531.                 sealed = attr.getValue(Name.SEALED);  
  532.             }  
  533.         }  
  534.         return "true".equalsIgnoreCase(sealed);  
  535.     }  
  536.   
  537.     /** 
  538.      * Finds the resource with the specified name on the URL search path. 
  539.      * 
  540.      * @param name the name of the resource 
  541.      * @return a <code>URL</code> for the resource, or <code>null</code> 
  542.      * if the resource could not be found, or if the loader is closed. 
  543.      */  
  544.     public URL findResource(final String name) {  
  545.         /* 
  546.          * The same restriction to finding classes applies to resources 
  547.          */  
  548.         URL url = AccessController.doPrivileged(  
  549.             new PrivilegedAction<URL>() {  
  550.                 public URL run() {  
  551.                     return ucp.findResource(name, true);  
  552.                 }  
  553.             }, acc);  
  554.   
  555.         return url != null ? ucp.checkURL(url) : null;  
  556.     }  
  557.   
  558.     /** 
  559.      * Returns an Enumeration of URLs representing all of the resources 
  560.      * on the URL search path having the specified name. 
  561.      * 
  562.      * @param name the resource name 
  563.      * @exception IOException if an I/O exception occurs 
  564.      * @return an <code>Enumeration</code> of <code>URL</code>s 
  565.      *         If the loader is closed, the Enumeration will be empty. 
  566.      */  
  567.     public Enumeration<URL> findResources(final String name)  
  568.         throws IOException  
  569.     {  
  570.         final Enumeration<URL> e = ucp.findResources(name, true);  
  571.   
  572.         return new Enumeration<URL>() {  
  573.             private URL url = null;  
  574.   
  575.             private boolean next() {  
  576.                 if (url != null) {  
  577.                     return true;  
  578.                 }  
  579.                 do {  
  580.                     URL u = AccessController.doPrivileged(  
  581.                         new PrivilegedAction<URL>() {  
  582.                             public URL run() {  
  583.                                 if (!e.hasMoreElements())  
  584.                                     return null;  
  585.                                 return e.nextElement();  
  586.                             }  
  587.                         }, acc);  
  588.                     if (u == null)  
  589.                         break;  
  590.                     url = ucp.checkURL(u);  
  591.                 } while (url == null);  
  592.                 return url != null;  
  593.             }  
  594.   
  595.             public URL nextElement() {  
  596.                 if (!next()) {  
  597.                     throw new NoSuchElementException();  
  598.                 }  
  599.                 URL u = url;  
  600.                 url = null;  
  601.                 return u;  
  602.             }  
  603.   
  604.             public boolean hasMoreElements() {  
  605.                 return next();  
  606.             }  
  607.         };  
  608.     }  
  609.   
  610.     /** 
  611.      * Returns the permissions for the given codesource object. 
  612.      * The implementation of this method first calls super.getPermissions 
  613.      * and then adds permissions based on the URL of the codesource. 
  614.      * <p> 
  615.      * If the protocol of this URL is "jar", then the permission granted 
  616.      * is based on the permission that is required by the URL of the Jar 
  617.      * file. 
  618.      * <p> 
  619.      * If the protocol is "file" and there is an authority component, then 
  620.      * permission to connect to and accept connections from that authority 
  621.      * may be granted. If the protocol is "file" 
  622.      * and the path specifies a file, then permission to read that 
  623.      * file is granted. If protocol is "file" and the path is 
  624.      * a directory, permission is granted to read all files 
  625.      * and (recursively) all files and subdirectories contained in 
  626.      * that directory. 
  627.      * <p> 
  628.      * If the protocol is not "file", then permission 
  629.      * to connect to and accept connections from the URL's host is granted. 
  630.      * @param codesource the codesource 
  631.      * @return the permissions granted to the codesource 
  632.      */  
  633.     protected PermissionCollection getPermissions(CodeSource codesource)  
  634.     {  
  635.         PermissionCollection perms = super.getPermissions(codesource);  
  636.   
  637.         URL url = codesource.getLocation();  
  638.   
  639.         Permission p;  
  640.         URLConnection urlConnection;  
  641.   
  642.         try {  
  643.             urlConnection = url.openConnection();  
  644.             p = urlConnection.getPermission();  
  645.         } catch (java.io.IOException ioe) {  
  646.             p = null;  
  647.             urlConnection = null;  
  648.         }  
  649.   
  650.         if (p instanceof FilePermission) {  
  651.             // if the permission has a separator char on the end,  
  652.             // it means the codebase is a directory, and we need  
  653.             // to add an additional permission to read recursively  
  654.             String path = p.getName();  
  655.             if (path.endsWith(File.separator)) {  
  656.                 path += "-";  
  657.                 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);  
  658.             }  
  659.         } else if ((p == null) && (url.getProtocol().equals("file"))) {  
  660.             String path = url.getFile().replace('/', File.separatorChar);  
  661.             path = ParseUtil.decode(path);  
  662.             if (path.endsWith(File.separator))  
  663.                 path += "-";  
  664.             p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);  
  665.         } else {  
  666.             /** 
  667.              * Not loading from a 'file:' URL so we want to give the class 
  668.              * permission to connect to and accept from the remote host 
  669.              * after we've made sure the host is the correct one and is valid. 
  670.              */  
  671.             URL locUrl = url;  
  672.             if (urlConnection instanceof JarURLConnection) {  
  673.                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();  
  674.             }  
  675.             String host = locUrl.getHost();  
  676.             if (host != null && (host.length() > 0))  
  677.                 p = new SocketPermission(host,  
  678.                                          SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);  
  679.         }  
  680.   
  681.         // make sure the person that created this class loader  
  682.         // would have this permission  
  683.   
  684.         if (p != null) {  
  685.             final SecurityManager sm = System.getSecurityManager();  
  686.             if (sm != null) {  
  687.                 final Permission fp = p;  
  688.                 AccessController.doPrivileged(new PrivilegedAction<Void>() {  
  689.                     public Void run() throws SecurityException {  
  690.                         sm.checkPermission(fp);  
  691.                         return null;  
  692.                     }  
  693.                 }, acc);  
  694.             }  
  695.             perms.add(p);  
  696.         }  
  697.         return perms;  
  698.     }  
  699.   
  700.     /** 
  701.      * Creates a new instance of URLClassLoader for the specified 
  702.      * URLs and parent class loader. If a security manager is 
  703.      * installed, the <code>loadClass</code> method of the URLClassLoader 
  704.      * returned by this method will invoke the 
  705.      * <code>SecurityManager.checkPackageAccess</code> method before 
  706.      * loading the class. 
  707.      * 
  708.      * @param urls the URLs to search for classes and resources 
  709.      * @param parent the parent class loader for delegation 
  710.      * @return the resulting class loader 
  711.      */  
  712.     public static URLClassLoader newInstance(final URL[] urls,  
  713.                                              final ClassLoader parent) {  
  714.         // Save the caller's context  
  715.         final AccessControlContext acc = AccessController.getContext();  
  716.         // Need a privileged block to create the class loader  
  717.         URLClassLoader ucl = AccessController.doPrivileged(  
  718.             new PrivilegedAction<URLClassLoader>() {  
  719.                 public URLClassLoader run() {  
  720.                     return new FactoryURLClassLoader(urls, parent, acc);  
  721.                 }  
  722.             });  
  723.         return ucl;  
  724.     }  
  725.   
  726.     /** 
  727.      * Creates a new instance of URLClassLoader for the specified 
  728.      * URLs and default parent class loader. If a security manager is 
  729.      * installed, the <code>loadClass</code> method of the URLClassLoader 
  730.      * returned by this method will invoke the 
  731.      * <code>SecurityManager.checkPackageAccess</code> before 
  732.      * loading the class. 
  733.      * 
  734.      * @param urls the URLs to search for classes and resources 
  735.      * @return the resulting class loader 
  736.      */  
  737.     public static URLClassLoader newInstance(final URL[] urls) {  
  738.         // Save the caller's context  
  739.         final AccessControlContext acc = AccessController.getContext();  
  740.         // Need a privileged block to create the class loader  
  741.         URLClassLoader ucl = AccessController.doPrivileged(  
  742.             new PrivilegedAction<URLClassLoader>() {  
  743.                 public URLClassLoader run() {  
  744.                     return new FactoryURLClassLoader(urls, acc);  
  745.                 }  
  746.             });  
  747.         return ucl;  
  748.     }  
  749.   
  750.     static {  
  751.         sun.misc.SharedSecrets.setJavaNetAccess (  
  752.             new sun.misc.JavaNetAccess() {  
  753.                 public URLClassPath getURLClassPath (URLClassLoader u) {  
  754.                     return u.ucp;  
  755.                 }  
  756.             }  
  757.         );  
  758.         ClassLoader.registerAsParallelCapable();  
  759.     }  
  760. }  
  761.   
  762. final class FactoryURLClassLoader extends URLClassLoader {  
  763.   
  764.     static {  
  765.         ClassLoader.registerAsParallelCapable();  
  766.     }  
  767.   
  768.     FactoryURLClassLoader(URL[] urls, ClassLoader parent,  
  769.                           AccessControlContext acc) {  
  770.         super(urls, parent, acc);  
  771.     }  
  772.   
  773.     FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {  
  774.         super(urls, acc);  
  775.     }  
  776.   
  777.     public final Class loadClass(String name, boolean resolve)  
  778.         throws ClassNotFoundException  
  779.     {  
  780.         // First check if we have permission to access the package. This  
  781.         // should go away once we've added support for exported packages.  
  782.         SecurityManager sm = System.getSecurityManager();  
  783.         if (sm != null) {  
  784.             int i = name.lastIndexOf('.');  
  785.             if (i != -1) {  
  786.                 sm.checkPackageAccess(name.substring(0, i));  
  787.             }  
  788.         }  
  789.         return super.loadClass(name, resolve);  
  790.     }  
  791. }  

猜你喜欢

转载自blog.csdn.net/qq_18048847/article/details/80350132