java.lang.ClassLoader

package java.lang;

import java.io.InputStream;
import java.io.IOException;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.CodeSource;
import java.security.Policy;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import java.util.Map;
import java.util.Vector;
import sun.misc.ClassFileTransformer;
import sun.misc.CompoundEnumeration;
import sun.misc.Resource;
import sun.misc.URLClassPath;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;

/**
 *
 * ClassLoader负责加载类或资源,当前类是抽象类,具体实现装载类功能的类需要继承它
 *
 * 表示数组的Class类对象不是由ClassLoader生成,数组的getClassLoader()方法会
 * 返回元素类型的ClassLoader
 *
 * 当装载一个类时,他会转交到父ClassLoader,而父ClassLoader转交到其上层
 * 直到bootstrap ClassLoader,如果转载则返回,否则在此级抛出异常,在此级
 * 的异常处理类中使用本级findClass方法装载类,如果装载则返回,否则将异常抛出
 * 由下级截获,并调用下级的findClass方法,装载成功则返回,否自继续抛出,如此
 * 反复,如果整个ClassLoader链中都无法装载此类,则将异常抛出到调用loadClass方法
 * 的外层,使用这种方式实现ClassLoader的链式装载,先由最顶层装载,然后再有相应
 * 的下级装载,如果我自定义一个java.lang.String类则无论他的内容怎样,String类
 * 的效果始终不便,这是因为ClassLoader的链式加载机制,因为String首先由bootstrap
 * 的ClassLoader装载了标准的String类,而自定义的String类不会被装载,也不会起作用,
 * 实际上这中机制也起到了安全的作用
 *
 * 调用顺序,loadClass->findClass->defineClass,继承的ClassLoader应实现
 * findClass方法
 *
 * ClassLoader不仅可以装载文件类型(*.class)的类,也可通过装载byte数组中的数据装载
 * 类,比如从网络下载类的字节流进而load进一个类,如果了解Class文件的结构,甚至可以
 * 以编程的方式动态生成类,Proxy类实现了动态生成代理类的字节数组,进而生成了代理类,
 * 但是sun只提供动态生成代理类,并没有提供更复杂的动态生成类的能力
 *
 * comment by liqiang
 *
 */
public abstract class ClassLoader {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    //表示初始化
    private boolean initialized = false;

    //ClassLoader的装载链的父级
    private ClassLoader parent;

    private Hashtable package2certs = new Hashtable(11);

    java.security.cert.Certificate[] nocerts;

    //表示此ClassLoader装载过得类,当ClassLoader被垃圾回收了,他装载过的类也被回收
    //这个对象便于在ClassLoader回收时,回收起装载过的类
    private Vector classes = new Vector();

    private Set domains = new HashSet();

    //装载过的类,加入到classes,这个方法是由虚拟机调用
    void addClass(Class c) {
        classes.addElement(c);
    }

    private HashMap packages = new HashMap();

    //通过一个父级的ClassLoader来构造一个新的ClassLoader
    protected ClassLoader(ClassLoader parent) {
    //安全检查 
 SecurityManager security = System.getSecurityManager();
 if (security != null) {
     security.checkCreateClassLoader();
 }
 
 this.parent = parent;
 initialized = true;
    }

    //构造函数
    protected ClassLoader() {
 //安全检查
    SecurityManager security = System.getSecurityManager();
 if (security != null) {
     security.checkCreateClassLoader();
 }
 
 //使用SystemClassLoader作为父ClassLoader
 this.parent = getSystemClassLoader();
 initialized = true;
    }

    /**
     *
     * 通过类名装载类
     *
     */
    public Class loadClass(String name) throws ClassNotFoundException {
 return loadClass(name, false);
    }

    /**
     *
     * 通过类名装载类
     * @param  name 类名
     *
     * @param  resolve 是否做链接
     *
     */
    protected synchronized Class loadClass(String name, boolean resolve)
 throws ClassNotFoundException
    {
 //查看此类是否已经被装载
 Class c = findLoadedClass(name);
 
 if (c == null) {//如果没有装载
  //使用代理方式由父类装载,这样会一直达到顶层(bootstrap ClassLoader)
  //然后由bootstrap装载,如果bootstrap ClassLoader没有找到此类,则抛出
  //ClassNotFoundException,然后由其下层ClassLoader截获此异常,调用此
  //ClassLoader的findClass方法装载此类,如果此层ClassLoader无法装载此类
  //则抛出异常,由下层ClassLoader装载,如此反复,如果当前的ClassLoader,也无法
  //装载此类则向外抛出异常,注意这种方式实现了,从顶层开始装载,依次向下的方式.
  //所以如果定义了一个java.lang.String类则它不会被装载,因为类装载是先从
  //bootstrap的ClassLoader装载的,它装载的是系统类
     try {
  if (parent != null) {
   //如果有父类装载器,则使用父类装载器装载此类
      c = parent.loadClass(name, false);
  } else {
   //没有父类装载器(表示此ClassLoader是bootstrapClassLoader)
   //则使用bootstrap的方式装载
      c = findBootstrapClass0(name);
  }
     } catch (ClassNotFoundException e) {
      //由父级(当前ClassLoader非bootstrap)
      //或bootstrap ClassLoader(当前ClassLoader是bootstrap)装载不到,
      //则调用当前类的findClass方法,如果找不到则继续抛出异常,由下级处理
         c = findClass(name);
     }
 }
 
 if (resolve) {
  //如果链接此类,则做链接操作
     resolveClass(c);
 }
 
 //返回装载的类的类对象
 return c;
    }

    //此方法由虚拟机调用,用来装载制定名称的类
    private synchronized Class loadClassInternal(String name)
 throws ClassNotFoundException
    {
 return loadClass(name);
    }

    private void checkPackageAccess(Class cls, ProtectionDomain pd) {
 final SecurityManager sm = System.getSecurityManager();
 
 if (sm != null) {
     final String name = cls.getName();
            final int i = name.lastIndexOf('.');
           
     if (i != -1) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Object run() {
          sm.checkPackageAccess(name.substring(0, i));
          return null;
                    }
                }, new AccessControlContext(new ProtectionDomain[] {pd}));
     }
 }
 
 domains.add(pd);
    }

    /**
     *
     * 查找指定名字的类,子类应重写此方法而不是loadClass方法
     *
     */
    protected Class findClass(String name) throws ClassNotFoundException {
 throw new ClassNotFoundException(name);
    }

    /**
     *
     * 通过一个byte数组生成Class对象
     *
     * @param  b 一个byte数组,表示装载类所需的数据
     * @param  off 起始位置
     * @param  len 数据长度
     *
     * @throws  ClassFormatError 如果数组不满足Class格式
     *
     * @deprecated  被defineClass(String, byte[], int, int)方法代替
     *
     */
    protected final Class defineClass(byte[] b, int off, int len)
 throws ClassFormatError
    {
 return defineClass(null, b, off, len, null);
    }

    /**
     *
     * 通过一个byte数组生成Class对象
     *
     * @param  name 希望装载的class名,如果不知道名称,则name为null,使用"."而不要使用"/"做分隔符
     *     且不要带.class后缀
     * @param  b 一个数组,包括装载类的数据
     * @param  off 起始位置
     * @param  len 数据的长度
     *
     * @throws  ClassFormatError 数据内容不符合class格式     
     *
     */
    protected final Class defineClass(String name, byte[] b, int off, int len)
 throws ClassFormatError
    {
 return defineClass(name, b, off, len, null);
    }

    /**
     * 通过一个byte数组生成Class对象
     *
     */
    protected final Class defineClass(String name, byte[] b, int off, int len,
          ProtectionDomain protectionDomain)
 throws ClassFormatError
    {
    //判断此ClassLoader是否被初始化 
 check();
  //类名以"java."开头抛出异常
        if ((name != null) && name.startsWith("java.")) {
            throw new SecurityException("Prohibited package name: " +
                                        name.substring(0, name.lastIndexOf('.')));
        }
       
 if (protectionDomain == null) {
     protectionDomain = getDefaultDomain();
 }

 if (name != null)
     checkCerts(name, protectionDomain.getCodeSource());

 Class c = null;

 try {
   //类名不符抛出异常
            if (!checkName(name, false))
              throw new NoClassDefFoundError("Illegal name: " + name);
           
        //装载此类  
     c = defineClass0(name, b, off, len, protectionDomain);
 } catch (ClassFormatError cfe) {
  //如果格式不符,转换格式,并重新装载类
  //获得格式转换对象
     Object[] transformers = ClassFileTransformer.getTransformers();

     for (int i = 0; transformers != null && i < transformers.length; i++) {
  try {
      //通过转换对象做格式转换
      byte[] tb = ((ClassFileTransformer) transformers[i]).transform(b, off, len);
      //重新装载此类
      c = defineClass0(name, tb, 0, tb.length, protectionDomain);
      //如果装载成功(没有抛出异常),则退出循环
      break;
  } catch (ClassFormatError cfe2) {
   //如果当前转换对象转换后还不能装载成功,则尝试下一个转换对象
  }
     }

     //如果没有装载成功,则重新抛出ClassFormatError
     if (c == null)
  throw cfe;
 }

 if (protectionDomain.getCodeSource() != null) {
     java.security.cert.Certificate certs[] =
  protectionDomain.getCodeSource().getCertificates();
     if (certs != null)
  setSigners(c, certs);
 }
 
 return c;
    }

    //通过byte装载类的本地数组
    private native Class defineClass0(String name, byte[] b, int off, int len,
 ProtectionDomain pd);

    //判断表示类的名字是否符合规格
    private boolean checkName(String name, boolean allowArrayClass) {
      if ((name == null) || (name.length() == 0))//如果名字为nul,或名字长度为0则符合
          return true;
      //如果名字中包含"/"则不符合
      if (name.indexOf('/') != -1)
          return false;     
      //不可为数组且名字以"["大头则不符合
      if (!allowArrayClass && (name.charAt(0) == '['))
          return false;
     
      return true;
    }

    private synchronized void checkCerts(String name, CodeSource cs) {
 int i = name.lastIndexOf('.');
 String pname = (i == -1) ? "" : name.substring(0, i);
 java.security.cert.Certificate[] pcerts =
     (java.security.cert.Certificate[]) package2certs.get(pname);
        if (pcerts == null) {
     if (cs != null) {
  pcerts = cs.getCertificates();
     }
     if (pcerts == null) {
  if (nocerts == null)
      nocerts = new java.security.cert.Certificate[0];
  pcerts = nocerts;
     }
     package2certs.put(pname, pcerts);
 } else {
     java.security.cert.Certificate[] certs = null;
     if (cs != null) {
  certs = cs.getCertificates();
     }

     if (!compareCerts(pcerts, certs)) {
  throw new SecurityException("class /""+ name +
         "/"'s signer information does not match signer information of other classes in the same package");
     }
 }
    }

    private boolean compareCerts(java.security.cert.Certificate[] pcerts,
     java.security.cert.Certificate[] certs)
    {
 if ((certs == null) || (certs.length == 0)) {
     return pcerts.length == 0;
 }

 if (certs.length != pcerts.length)
     return false;

 boolean match;
 for (int i = 0; i < certs.length; i++) {
     match = false;
     for (int j = 0; j < pcerts.length; j++) {
  if (certs[i].equals(pcerts[j])) {
      match = true;
      break;
  }
     }
     if (!match) return false;
 }

 for (int i = 0; i < pcerts.length; i++) {
     match = false;
     for (int j = 0; j < certs.length; j++) {
  if (pcerts[i].equals(certs[j])) {
      match = true;
      break;
  }
     }
     if (!match) return false;
 }

 return true;
    }

    /**
     *
     * 链接Class,如果此类已经链接则直接返回
     * @param  c 将被链接的类
     *
     */
    protected final void resolveClass(Class c) {
    //判断此ClassLoader是否被初始化
 check();
 
 //链接此类
 resolveClass0(c);
    }

    //链接此类的本地方法
    private native void resolveClass0(Class c);

    /**
     *
     * 通过SystemClassLoader装载类
     *
     */
    protected final Class findSystemClass(String name)
 throws ClassNotFoundException
    {
    //判断此ClassLoader是否被初始化 
 check();
 
 ClassLoader system = getSystemClassLoader();
 if (system == null) {
            if (!checkName(name, true))
              throw new ClassNotFoundException(name);

     return findBootstrapClass(name);
 }
 return system.loadClass(name);
    }


    private Class findBootstrapClass0(String name)
 throws ClassNotFoundException {
    //检查此ClassLoader是否被初始化
 check();
  //检查此名
        if (!checkName(name, true))
          throw new ClassNotFoundException(name);

    //使用bootstrap方式装载类
 return findBootstrapClass(name);
    }

    //使用bootstrap方式装载类的本地方法
    private native Class findBootstrapClass(String name)
 throws ClassNotFoundException;

    //判断此ClassLoader是否被初始化
    private void check() {
 if (!initialized) {
     throw new SecurityException("ClassLoader object not initialized");
 }
    }

    /**
     *
     * 通过类名返回已装载的类的类对象,如果没有找到则返回null
     *
     */
    protected final Class findLoadedClass(String name) {
      //判断此ClassLoader是否被初始化
      check();
      //判断名字是否符合
      if (!checkName(name, true))
          return null;
     
      //通过名字查找已装载类的本地方方法
      return findLoadedClass0(name);
    }

    //通过名字查找已装载类的本地方方法
    private native final Class findLoadedClass0(String name);


    /**
     * Sets the signers of a class.  This should be invoked after defining a
     * class.  </p>
     *
     * @param  c
     *         The <tt>Class</tt> object
     *
     * @param  signers
     *         The signers for the class
     *
     * @since  1.1
     */
    protected final void setSigners(Class c, Object[] signers) {
        check();
 c.setSigners(signers);
    }


    // -- Resource --

    /**
     * Finds the resource with the given name.  A resource is some data
     * (images, audio, text, etc) that can be accessed by class code in a way
     * that is independent of the location of the code.
     *
     * <p> The name of a resource is a '<tt>/</tt>'-separated path name that
     * identifies the resource.
     *
     * <p> This method will first search the parent class loader for the
     * resource; if the parent is <tt>null</tt> the path of the class loader
     * built-in to the virtual machine is searched.  That failing, this method
     * will invoke {@link #findResource(String)} to find the resource.  </p>
     *
     * @param  name
     *         The resource name
     *
     * @return  A <tt>URL</tt> object for reading the resource, or
     *          <tt>null</tt> if the resource could not be found or the invoker
     *          doesn't have adequate  privileges to get the resource.
     *
     * @since  1.1
     */
    public URL getResource(String name) {
 URL url;
 if (parent != null) {
     url = parent.getResource(name);
 } else {
     url = getBootstrapResource(name);
 }
 if (url == null) {
     url = findResource(name);
 }
 return url;
    }

    /**
     * Finds all the resources with the given name. A resource is some data
     * (images, audio, text, etc) that can be accessed by class code in a way
     * that is independent of the location of the code.
     *
     * <p>The name of a resource is a <tt>/</tt>-separated path name that
     * identifies the resource.
     *
     * <p> The search order is described in the documentation for {@link
     * #getResource(String)}.  </p>
     *
     * @param  name
     *         The resource name
     *
     * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
     *          the resource.  If no resources could  be found, the enumeration
     *          will be empty.  Resources that the class loader doesn't have
     *          access to will not be in the enumeration.
     *
     * @throws  IOException
     *          If I/O errors occur
     *
     * @see  #findResources(String)
     *
     * @since  1.2
     */
    public final Enumeration getResources(String name) throws IOException {
 Enumeration[] tmp = new Enumeration[2];
 if (parent != null) {
     tmp[0] = parent.getResources(name);
 } else {
     tmp[0] = getBootstrapResources(name);
 }
 tmp[1] = findResources(name);

 return new CompoundEnumeration(tmp);
    }

    /**
     * Finds the resource with the given name. Class loader implementations
     * should override this method to specify where to find resources.  </p>
     *
     * @param  name
     *         The resource name
     *
     * @return  A <tt>URL</tt> object for reading the resource, or
     *          <tt>null</tt> if the resource could not be found
     *
     * @since  1.2
     */
    protected URL findResource(String name) {
 return null;
    }

    /**
     * Returns an enumeration of {@link java.net.URL <tt>URL</tt>} objects
     * representing all the resources with the given name. Class loader
     * implementations should override this method to specify where to load
     * resources from.  </p>
     *
     * @param  name
     *         The resource name
     *
     * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
     *          the resources
     *
     * @throws  IOException
     *          If I/O errors occur
     *
     * @since  1.2
     */
    protected Enumeration findResources(String name) throws IOException {
 return new CompoundEnumeration(new Enumeration[0]);
    }

    /**
     * Find a resource of the specified name from the search path used to load
     * classes.  This method locates the resource through the system class
     * loader (see {@link #getSystemClassLoader()}).  </p>
     *
     * @param  name
     *         The resource name
     *
     * @return  A {@link java.net.URL <tt>URL</tt>} object for reading the
     *          resource, or <tt>null</tt> if the resource could not be found
     *
     * @since  1.1
     */
    public static URL getSystemResource(String name) {
 ClassLoader system = getSystemClassLoader();
 if (system == null) {
     return getBootstrapResource(name);
 }
 return system.getResource(name);
    }

    /**
     * Finds all resources of the specified name from the search path used to
     * load classes.  The resources thus found are returned as an
     * {@link java.util.Enumeration <tt>Enumeration</tt>} of {@link
     * java.net.URL <tt>URL</tt>} objects.
     *
     * <p> The search order is described in the documentation for {@link
     * #getSystemResource(String)}.  </p>
     *
     * @param  name
     *         The resource name
     *
     * @return  An enumeration of resource {@link java.net.URL <tt>URL</tt>}
     *          objects
     *
     * @throws  IOException
     *          If I/O errors occur

     * @since  1.2
     */
    public static Enumeration getSystemResources(String name)
 throws IOException
    {
 ClassLoader system = getSystemClassLoader();
 if (system == null) {
     return getBootstrapResources(name);
 }
 return system.getResources(name);
    }

    /**
     * Find resources from the VM's built-in classloader.
     */
    private static URL getBootstrapResource(String name) {
 URLClassPath ucp = getBootstrapClassPath();
 Resource res = ucp.getResource(name);
 return res != null ? res.getURL() : null;
    }

    /**
     * Find resources from the VM's built-in classloader.
     */
    private static Enumeration getBootstrapResources(String name)
 throws IOException
    {
 final Enumeration e = getBootstrapClassPath().getResources(name);
 return new Enumeration () {
     public Object nextElement() {
  return ((Resource)e.nextElement()).getURL();
     }
     public boolean hasMoreElements() {
  return e.hasMoreElements();
     }
 };
    }

    // Returns the URLClassPath that is used for finding system resources.
    static URLClassPath getBootstrapClassPath() {
 if (bootstrapClassPath == null) {
     bootstrapClassPath = sun.misc.Launcher.getBootstrapClassPath();
 }
 return bootstrapClassPath;
    }

    private static URLClassPath bootstrapClassPath;

    /**
     * Returns an input stream for reading the specified resource.
     *
     * <p> The search order is described in the documentation for {@link
     * #getResource(String)}.  </p>
     *
     * @param  name
     *         The resource name
     *
     * @return  An input stream for reading the resource, or <tt>null</tt>
     *          if the resource could not be found
     *
     * @since  1.1
     */
    public InputStream getResourceAsStream(String name) {
 URL url = getResource(name);
 try {
     return url != null ? url.openStream() : null;
 } catch (IOException e) {
     return null;
 }
    }

    /**
     * Open for reading, a resource of the specified name from the search path
     * used to load classes.  This method locates the resource through the
     * system class loader (see {@link #getSystemClassLoader()}).  </p>
     *
     * @param  name
     *         The resource name
     *
     * @return  An input stream for reading the resource, or <tt>null</tt>
     *          if the resource could not be found
     *
     * @since  1.1
     */
    public static InputStream getSystemResourceAsStream(String name) {
 URL url = getSystemResource(name);
 try {
     return url != null ? url.openStream() : null;
 } catch (IOException e) {
     return null;
 }
    }


    // -- Hierarchy --

    /**
     *
     * 获得父ClassLoader
     *
     */
    public final ClassLoader getParent() {
 if (parent == null)
     return null;
 SecurityManager sm = System.getSecurityManager();
 if (sm != null) {
     ClassLoader ccl = getCallerClassLoader();
     if (ccl != null && !isAncestor(ccl)) {
  sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
     }
 }
 return parent;
    }

    /**
     *
     * 获得SystemClassLoader
     *
     */
    public static ClassLoader getSystemClassLoader() {
 initSystemClassLoader();
 if (scl == null) {
     return null;
 }
 SecurityManager sm = System.getSecurityManager();
 if (sm != null) {
     ClassLoader ccl = getCallerClassLoader();
     if (ccl != null && ccl != scl && !scl.isAncestor(ccl)) {
  sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
     }
 }
 return scl;
    }

    //初始化System ClassLoader
    private static synchronized void initSystemClassLoader() {
 if (!sclSet) {//如果标志位显示没有被设置
     if (scl != null)//如果System ClassLoader对象已被设置
  throw new IllegalStateException("recursive invocation");
    
            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
           
     if (l != null) {
      
  Throwable oops = null;
  scl = l.getClassLoader();
  
         try {
      PrivilegedExceptionAction a;
      //向scl设置System ClassLoader
      a = new SystemClassLoaderAction(scl);
                    scl = (ClassLoader) AccessController.doPrivileged(a);
         } catch (PrivilegedActionException pae) {
      oops = pae.getCause();
             if (oops instanceof InvocationTargetException) {
          oops = oops.getCause();
      }
         }
        
  if (oops != null) {//如果有错误
      if (oops instanceof Error) {
   throw (Error) oops;
      } else {
          // wrap the exception
          throw new Error(oops);
      }
  }
  
     }
    
     //标志为已设置
     sclSet = true;
 }
    }

    //判断cl是否是当前ClassLoader的父级ClassLoader
    boolean isAncestor(ClassLoader cl) {
 ClassLoader acl = this;
 
 do {
  //迭代当前对象的所有祖先ClassLoader,直到bootstrap ClassLoader
  //判断是否有与cl相等的ClassLoader
  
     acl = acl.parent;
     if (cl == acl) {
  return true;
     }
 } while (acl != null);
 
 //如果当前的所有父级ClassLoader种没有此对象,
 //表明此对象不是当前对象的父级ClassLoader
 return false;
    }

    //返回调用者的ClassLoader
    static ClassLoader getCallerClassLoader() {
        //获得调用对象
        Class caller = Reflection.getCallerClass(3);
        //调用对象为null表示由虚拟机调用
        if (caller == null) {
            return null;
        }
       
        //返回调用者的ClassLoader
        return caller.getClassLoader0();
    }

    //表示System ClassLoader
    private static ClassLoader scl;

    //标志scl是否已被设置为System ClassLoader
    private static boolean sclSet;


    // -- Package --

    /**
     * Defines a package by name in this <tt>ClassLoader</tt>.  This allows
     * class loaders to define the packages for their classes. Packages must
     * be created before the class is defined, and package names must be
     * unique within a class loader and cannot be redefined or changed once
     * created.  </p>
     *
     * @param  name
     *         The package name
     *
     * @param  specTitle
     *         The specification title
     *
     * @param  specVersion
     *         The specification version
     *
     * @param  specVendor
     *         The specification vendor
     *
     * @param  implTitle
     *         The implementation title
     *
     * @param  implVersion
     *         The implementation version
     *
     * @param  implVendor
     *         The implementation vendor
     *
     * @param  sealBase
     *         If not <tt>null</tt>, then this package is sealed with
     *         respect to the given code source {@link java.net.URL
     *         <tt>URL</tt>}  object.  Otherwise, the package is not sealed.
     *
     * @return  The newly defined <tt>Package</tt> object
     *
     * @throws  IllegalArgumentException
     *          If package name duplicates an existing package either in this
     *          class loader or one of its ancestors
     *
     * @since  1.2
     */
    protected Package definePackage(String name, String specTitle,
        String specVersion, String specVendor,
        String implTitle, String implVersion,
        String implVendor, URL sealBase)
 throws IllegalArgumentException
    {
 synchronized (packages) {
     Package pkg = getPackage(name);
     if (pkg != null) {
  throw new IllegalArgumentException(name);
     }
     pkg = new Package(name, specTitle, specVersion, specVendor,
         implTitle, implVersion, implVendor,
         sealBase);
     packages.put(name, pkg);
     return pkg;
 }
    }

    /**
     * Returns a <tt>Package</tt> that has been defined by this class loader
     * or any of its ancestors.  </p>
     *
     * @param  name
     *         The package name
     *
     * @return  The <tt>Package</tt> corresponding to the given name, or
     *          <tt>null</tt> if not found
     *
     * @since  1.2
     */
    protected Package getPackage(String name) {
 synchronized (packages) {
     Package pkg = (Package)packages.get(name);
     if (pkg == null) {
  if (parent != null) {
      pkg = parent.getPackage(name);
  } else {
      pkg = Package.getSystemPackage(name);
  }
  if (pkg != null) {
      packages.put(name, pkg);
  }
     }
     return pkg;
 }
    }

    /**
     * Returns all of the <tt>Packages</tt> defined by this class loader and
     * its ancestors.  </p>
     *
     * @return  The array of <tt>Package</tt> objects defined by this
     *          <tt>ClassLoader</tt>
     *
     * @since  1.2
     */
    protected Package[] getPackages() {
 Map map;
 synchronized (packages) {
     map = (Map)packages.clone();
 }
 Package[] pkgs;
 if (parent != null) {
     pkgs = parent.getPackages();
 } else {
     pkgs = Package.getSystemPackages();
 }
 if (pkgs != null) {
     for (int i = 0; i < pkgs.length; i++) {
                String pkgName = pkgs[i].getName();
                if (map.get(pkgName) == null) {
                    map.put(pkgName, pkgs[i]);
                }
     }
 }
 return (Package[])map.values().toArray(new Package[map.size()]);
    }


    // -- Native library access --

    /**
     * Returns the absolute path name of a native library.  The VM invokes this
     * method to locate the native libraries that belong to classes loaded with
     * this class loader. If this method returns <tt>null</tt>, the VM
     * searches the library along the path specified as the
     * "<tt>java.library.path</tt>" property.  </p>
     *
     * @param  libname
     *         The library name
     *
     * @return  The absolute path of the native library
     *
     * @see  System#loadLibrary(String)
     * @see  System#mapLibraryName(String)
     *
     * @since  1.2
     */
    protected String findLibrary(String libname) {
        return null;
    }

    /**
     * The inner class NativeLibrary denotes a loaded native library instance.
     * Every classloader contains a vector of loaded native libraries in the
     * private field <tt>nativeLibraries</tt>.  The native libraries loaded
     * into the system are entered into the <tt>systemNativeLibraries</tt>
     * vector.
     *
     * <p> Every native library reuqires a particular version of JNI. This is
     * denoted by the private <tt>jniVersion</tt> field.  This field is set by
     * the VM when it loads the library, and used by the VM to pass the correct
     * version of JNI to the native methods.  </p>
     *
     * @version  1.171 05/06/04
     * @see      ClassLoader
     * @since    1.2
     */
    static class NativeLibrary {
 // opaque handle to native library, used in native code.
        long handle;
        // the version of JNI environment the native library requires.
        private int jniVersion;
        // the class from which the library is loaded, also indicates
 // the loader this native library belongs.
        private Class fromClass;
        // the canonicalized name of the native library.
        String name;

        native void load(String name);
        native long find(String name);
        native void unload();

        public NativeLibrary(Class fromClass, String name) {
            this.name = name;
     this.fromClass = fromClass;
 }

        protected void finalize() {
     synchronized (loadedLibraryNames) {
         if (fromClass.getClassLoader() != null && handle != 0) {
      /* remove the native library name */
      int size = loadedLibraryNames.size();
      for (int i = 0; i < size; i++) {
          if (name.equals(loadedLibraryNames.elementAt(i))) {
       loadedLibraryNames.removeElementAt(i);
       break;
   }
      }
      /* unload the library. */
      ClassLoader.nativeLibraryContext.push(this);
      try {
   unload();
      } finally {
          ClassLoader.nativeLibraryContext.pop();
      }
  }
     }
 }
        // Invoked in the VM to determine the context class in
 // JNI_Load/JNI_Unload
        static Class getFromClass() {
            return ((NativeLibrary)
      (ClassLoader.nativeLibraryContext.peek())).fromClass;
 }
    }

    // The "default" domain. Set as the default ProtectionDomain on newly
    // created classses.
    private ProtectionDomain defaultDomain = null;

    // Returns (and initializes) the default domain.
    private synchronized ProtectionDomain getDefaultDomain() {
 if (defaultDomain == null) {
     CodeSource cs = new CodeSource(null, null);
     defaultDomain = new ProtectionDomain(cs, null, this, null);
 }
 
 return defaultDomain;
    }

    // All native library names we've loaded.
    private static Vector loadedLibraryNames = new Vector();
    // Native libraries belonging to system classes.
    private static Vector systemNativeLibraries = new Vector();
    // Native libraries associated with the class loader.
    private Vector nativeLibraries = new Vector();

    // native libraries being loaded/unloaded.
    private static Stack nativeLibraryContext = new Stack();

    // The paths searched for libraries
    static private String usr_paths[];
    static private String sys_paths[];

    private static String[] initializePath(String propname) {
        String ldpath = System.getProperty(propname, "");
 String ps = File.pathSeparator;
 int ldlen = ldpath.length();
 int i, j, n;
 // Count the separators in the path
 i = ldpath.indexOf(ps);
 n = 0;
 while (i >= 0) {
     n++;
     i = ldpath.indexOf(ps, i + 1);
 }

 // allocate the array of paths - n :'s = n + 1 path elements
 String[] paths = new String[n + 1];

 // Fill the array with paths from the ldpath
 n = i = 0;
 j = ldpath.indexOf(ps);
 while (j >= 0) {
     if (j - i > 0) {
         paths[n++] = ldpath.substring(i, j);
     } else if (j - i == 0) {
         paths[n++] = ".";
     }
     i = j + 1;
     j = ldpath.indexOf(ps, i);
 }
 paths[n] = ldpath.substring(i, ldlen);
 return paths;
    }

    // Invoked in the java.lang.Runtime class to implement load and loadLibrary.
    static void loadLibrary(Class fromClass, String name,
       boolean isAbsolute) {
        ClassLoader loader =
     (fromClass == null) ? null : fromClass.getClassLoader();
        if (sys_paths == null) {
     usr_paths = initializePath("java.library.path");
     sys_paths = initializePath("sun.boot.library.path");
        }
        if (isAbsolute) {
     if (loadLibrary0(fromClass, new File(name))) {
         return;
     }
     throw new UnsatisfiedLinkError("Can't load library: " + name);
 }
 if (loader != null) {
     String libfilename = loader.findLibrary(name);
     if (libfilename != null) {
         File libfile = new File(libfilename);
         if (!libfile.isAbsolute()) {
      throw new UnsatisfiedLinkError(
    "ClassLoader.findLibrary failed to return an absolute path: " + libfilename);
  }
  if (loadLibrary0(fromClass, libfile)) {
      return;
  }
  throw new UnsatisfiedLinkError("Can't load " + libfilename);
     }
 }
 for (int i = 0 ; i < sys_paths.length ; i++) {
     File libfile = new File(sys_paths[i], System.mapLibraryName(name));
     if (loadLibrary0(fromClass, libfile)) {
         return;
     }
 }
 if (loader != null) {
     for (int i = 0 ; i < usr_paths.length ; i++) {
         File libfile = new File(usr_paths[i],
     System.mapLibraryName(name));
  if (loadLibrary0(fromClass, libfile)) {
      return;
  }
     }
 }
 // Oops, it failed
        throw new UnsatisfiedLinkError("no " + name + " in java.library.path");
    }

    private static boolean loadLibrary0(Class fromClass, final File file) {
 Boolean exists = (Boolean)
     AccessController.doPrivileged(new PrivilegedAction() {
  public Object run() {
      return new Boolean(file.exists());
  }
     });
 if (!exists.booleanValue()) {
     return false;
 }
        String name;
 try {
     name = file.getCanonicalPath();
 } catch (IOException e) {
     return false;
 }
        ClassLoader loader =
     (fromClass == null) ? null : fromClass.getClassLoader();
        Vector libs =
     loader != null ? loader.nativeLibraries : systemNativeLibraries;
 synchronized (libs) {
     int size = libs.size();
     for (int i = 0; i < size; i++) {
         NativeLibrary lib = (NativeLibrary)libs.elementAt(i);
  if (name.equals(lib.name)) {
      return true;
  }
     }

     synchronized (loadedLibraryNames) {
         if (loadedLibraryNames.contains(name)) {
      throw new UnsatisfiedLinkError
          ("Native Library " +
    name +
    " already loaded in another classloader");
  }
  /* If the library is being loaded (must be by the same thread,
   * because Runtime.load and Runtime.loadLibrary are
   * synchronous). The reason is can occur is that the JNI_OnLoad
   * function can cause another loadLibrary invocation.
   *
   * Thus we can use a static stack to hold the list of libraries
   * we are loading.
   *
   * If there is a pending load operation for the library, we
   * immediately return success; otherwise, we raise
   * UnsatisfiedLinkError.
   */
  int n = nativeLibraryContext.size();
  for (int i = 0; i < n; i++) {
      NativeLibrary lib = (NativeLibrary)
          nativeLibraryContext.elementAt(i);
      if (name.equals(lib.name)) {
          if (loader == lib.fromClass.getClassLoader()) {
       return true;
   } else {
       throw new UnsatisfiedLinkError
           ("Native Library " +
     name +
     " is being loaded in another classloader");
   }
      }
  }
  NativeLibrary lib = new NativeLibrary(fromClass, name);
  nativeLibraryContext.push(lib);
  try {
      lib.load(name);
  } finally {
      nativeLibraryContext.pop();
  }
  if (lib.handle != 0) {
      loadedLibraryNames.addElement(name);
      libs.addElement(lib);
      return true;
  }
  return false;
     }
 }
    }

    // Invoked in the VM class linking code.
    static long findNative(ClassLoader loader, String name) {
        Vector libs =
     loader != null ? loader.nativeLibraries : systemNativeLibraries;
 synchronized (libs) {
     int size = libs.size();
     for (int i = 0; i < size; i++) {
         NativeLibrary lib = (NativeLibrary)libs.elementAt(i);
  long entry = lib.find(name);
  if (entry != 0)
      return entry;
     }
 }
 return 0;
    }


    // -- Assertion management --

    // The default toggle for assertion checking.
    private boolean defaultAssertionStatus = false;

    // Maps String packageName to Boolean package default assertion status Note
    // that the default package is placed under a null map key.  If this field
    // is null then we are delegating assertion status queries to the VM, i.e.,
    // none of this ClassLoader's assertion status modification methods have
    // been invoked.
    private Map packageAssertionStatus = null;

    // Maps String fullyQualifiedClassName to Boolean assertionStatus If this
    // field is null then we are delegating assertion status queries to the VM,
    // i.e., none of this ClassLoader's assertion status modification methods
    // have been invoked.
    Map classAssertionStatus = null;

    /**
     * Sets the default assertion status for this class loader.  This setting
     * determines whether classes loaded by this class loader and initialized
     * in the future will have assertions enabled or disabled by default.
     * This setting may be overridden on a per-package or per-class basis by
     * invoking {@link #setPackageAssertionStatus(String, boolean)} or {@link
     * #setClassAssertionStatus(String, boolean)}.  </p>
     *
     * @param  enabled
     *         <tt>true</tt> if classes loaded by this class loader will
     *         henceforth have assertions enabled by default, <tt>false</tt>
     *         if they will have assertions disabled by default.
     *
     * @since  1.4
     */
    public synchronized void setDefaultAssertionStatus(boolean enabled) {
        if (classAssertionStatus == null)
            initializeJavaAssertionMaps();

        defaultAssertionStatus = enabled;
    }

    /**
     * Sets the package default assertion status for the named package.  The
     * package default assertion status determines the assertion status for
     * classes initialized in the future that belong to the named package or
     * any of its "subpackages".
     *
     * <p> A subpackage of a package named p is any package whose name begins
     * with "<tt>p.</tt>".  For example, <tt>javax.swing.text</tt> is a
     * subpackage of <tt>javax.swing</tt>, and both <tt>java.util</tt> and
     * <tt>java.lang.reflect</tt> are subpackages of <tt>java</tt>.
     *
     * <p> In the event that multiple package defaults apply to a given class,
     * the package default pertaining to the most specific package takes
     * precedence over the others.  For example, if <tt>javax.lang</tt> and
     * <tt>javax.lang.reflect</tt> both have package defaults associated with
     * them, the latter package default applies to classes in
     * <tt>javax.lang.reflect</tt>.
     *
     * <p> Package defaults take precedence over the class loader's default
     * assertion status, and may be overridden on a per-class basis by invoking
     * {@link #setClassAssertionStatus(String, boolean)}.  </p>
     *
     * @param  packageName
     *         The name of the package whose package default assertion status
     *         is to be set. A <tt>null</tt> value indicates the unnamed
     *         package that is "current" (<a *
     *         href="http://java.sun.com/docs/books/jls/">Java Language
     *         Specification</a>, section 7.4.2).
     *
     * @param  enabled
     *         <tt>true</tt> if classes loaded by this classloader and
     *         belonging to the named package or any of its subpackages will
     *         have assertions enabled by default, <tt>false</tt> if they will
     *         have assertions disabled by default.
     *
     * @since  1.4
     */
    public synchronized void setPackageAssertionStatus(String packageName,
                                                       boolean enabled)
    {
        if (packageAssertionStatus == null)
            initializeJavaAssertionMaps();

        packageAssertionStatus.put(packageName, Boolean.valueOf(enabled));
    }

    /**
     * Sets the desired assertion status for the named top-level class in this
     * class loader and any nested classes contained therein.  This setting
     * takes precedence over the class loader's default assertion status, and
     * over any applicable per-package default.  This method has no effect if
     * the named class has already been initialized.  (Once a class is
     * initialized, its assertion status cannot change.)
     *
     * <p> If the named class is not a top-level class, this invocation will
     * have no effect on the actual assertion status of any class, and its
     * return value is undefined.  </p>
     *
     * @param  className
     *         The fully qualified class name of the top-level class whose
     *         assertion status is to be set.
     *
     * @param  enabled
     *         <tt>true</tt> if the named class is to have assertions
     *         enabled when (and if) it is initialized, <tt>false</tt> if the
     *         class is to have assertions disabled.
     *
     * @since  1.4
     */
    public synchronized void setClassAssertionStatus(String className,
                                                     boolean enabled)
    {
        if (classAssertionStatus == null)
            initializeJavaAssertionMaps();

        classAssertionStatus.put(className, Boolean.valueOf(enabled));
    }

    /**
     * Sets the default assertion status for this class loader to
     * <tt>false</tt> and discards any package defaults or class assertion
     * status settings associated with the class loader.  This method is
     * provided so that class loaders can be made to ignore any command line or
     * persistent assertion status settings and "start with a clean slate."
     * </p>
     *
     * @since  1.4
     */
    public synchronized void clearAssertionStatus() {
        /*
         * Whether or not "Java assertion maps" are initialized, set
         * them to empty maps, effectively ignoring any present settings.
         */
        classAssertionStatus = new HashMap();
        packageAssertionStatus = new HashMap();

        defaultAssertionStatus = false;
    }

    /**
     * Returns the assertion status that would be assigned to the specified
     * class if it were to be initialized at the time this method is invoked.
     * If the named class has had its assertion status set, the most recent
     * setting will be returned; otherwise, if any package default assertion
     * status pertains to this class, the most recent setting for the most
     * specific pertinent package default assertion status is returned;
     * otherwise, this class loader's default assertion status is returned.
     * </p>
     *
     * @param  className
     *         The fully qualified class name of the class whose desired
     *         assertion status is being queried.
     *
     * @return  The desired assertion status of the specified class.
     *
     * @see  #setClassAssertionStatus(String, boolean)
     * @see  #setPackageAssertionStatus(String, boolean)
     * @see  #setDefaultAssertionStatus(boolean)
     *
     * @since  1.4
     */
    synchronized boolean desiredAssertionStatus(String className) {
        Boolean result;

        // assert classAssertionStatus   != null;
        // assert packageAssertionStatus != null;

        // Check for a class entry
        result = (Boolean)classAssertionStatus.get(className);
        if (result != null)
            return result.booleanValue();

        // Check for most specific package entry
        int dotIndex = className.lastIndexOf(".");
        if (dotIndex < 0) { // default package
            result = (Boolean)packageAssertionStatus.get(null);
            if (result != null)
                return result.booleanValue();
        }
        while(dotIndex > 0) {
            className = className.substring(0, dotIndex);
            result = (Boolean)packageAssertionStatus.get(className);
            if (result != null)
                return result.booleanValue();
            dotIndex = className.lastIndexOf(".", dotIndex-1);
        }

        // Return the classloader default
        return defaultAssertionStatus;
    }

    // Set up the assertions with information provided by the VM.
    private void initializeJavaAssertionMaps() {
        // assert Thread.holdsLock(this);

        classAssertionStatus = new HashMap();
        packageAssertionStatus = new HashMap();
        AssertionStatusDirectives directives = retrieveDirectives();

        for(int i = 0; i < directives.classes.length; i++)
            classAssertionStatus.put(directives.classes[i],
                              Boolean.valueOf(directives.classEnabled[i]));

        for(int i = 0; i < directives.packages.length; i++)
            packageAssertionStatus.put(directives.packages[i],
                              Boolean.valueOf(directives.packageEnabled[i]));

        defaultAssertionStatus = directives.deflt;
    }

    // Retrieves the assertion directives from the VM.
    private static native AssertionStatusDirectives retrieveDirectives();
}

class SystemClassLoaderAction implements PrivilegedExceptionAction {
    private ClassLoader parent;

    SystemClassLoaderAction(ClassLoader parent) {
 this.parent = parent;
    }

    public Object run() throws Exception {
 ClassLoader sys;
 Constructor ctor;
 Class c;
 Class cp[] = { ClassLoader.class };
 Object params[] = { parent };

        String cls = System.getProperty("java.system.class.loader");
 if (cls == null) {
     return parent;
 }

 c = Class.forName(cls, true, parent);
 ctor = c.getDeclaredConstructor(cp);
 sys = (ClassLoader) ctor.newInstance(params);
 Thread.currentThread().setContextClassLoader(sys);
 return sys;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值