// ClassLoader.java - Define policies for loading Java classes.
/* Copyright (C) 1998, 1999  Cygnus Solutions
   This file is part of libgcj.
This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */
package java.lang;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Stack;
/**
 * The class ClassLoader is intended to be subclassed by
 * applications in order to describe new ways of loading classes,
 * such as over the network.
 *
 * @author  Kresten Krab Thorup
 */
public abstract class ClassLoader {
  static private ClassLoader system;
  private ClassLoader parent;
  public ClassLoader getParent ()
  {
    /* FIXME: security */
    return parent;
  }
    
  private static native ClassLoader getVMClassLoader0 ();
  static public ClassLoader getSystemClassLoader () {
    if (system == null)
      system = getVMClassLoader0 ();
    return system;
  }
  /**
   * Creates a ClassLoader with no parent.
   * @exception java.lang.SecurityException if not allowed
   */
  protected ClassLoader() 
  {
    this (null);
  }
  /**
   * Creates a ClassLoader with the given parent.   
   * The parent may be null.
   * The only thing this 
   * constructor does, is to call
   * checkCreateClassLoader on the current 
   * security manager. 
   * @exception java.lang.SecurityException if not allowed
   */
  protected ClassLoader(ClassLoader parent) 
  {
    SecurityManager security = System.getSecurityManager ();
    if (security != null)
      security.checkCreateClassLoader ();
    this.parent = parent;
  }
  /** 
   * Loads and link the class by the given name.
   * @param     name the name of the class.
   * @return    the class loaded.
   * @see       ClassLoader#loadClass(String,boolean)
   * @exception java.lang.ClassNotFoundException 
   */ 
  public Class loadClass(String name) 
    throws java.lang.ClassNotFoundException, java.lang.LinkageError
  { 
    return loadClass (name, false);
  }
  /** 
   * Loads the class by the given name.  The default implementation
   * will search for the class in the following order (similar to jdk 1.2)
   * 
findLoadedClass.
   *  parent.loadClass;
   *       otherwise findSystemClass.
   *  findClass.
   * link is true, resolveClass is then
   * called.   Normally, this need not be overridden; override
   * findClass instead.
   * @param     name the name of the class.
   * @param     link if the class should be linked.
   * @return    the class loaded.
   * @exception java.lang.ClassNotFoundException 
   * @deprecated 
   */ 
  protected Class loadClass(String name, boolean link)
    throws java.lang.ClassNotFoundException, java.lang.LinkageError
  {
    Class c = findLoadedClass (name);
    if (c == null)
      {
	try {
	  if (parent != null)
	    return parent.loadClass (name, link);
	  else
	    c = findSystemClass (name);
	} catch (ClassNotFoundException ex) {
	  /* ignore, we'll try findClass */;
	}
      }
    if (c == null)
      c = findClass (name);
    if (c == null)
      throw new ClassNotFoundException (name);
    if (link)
      resolveClass (c);
    return c;
  }
  /** Find a class.  This should be overridden by subclasses; the
   *  default implementation throws ClassNotFoundException.
   *
   * @param name Name of the class to find.
   * @return     The class found.
   * @exception  java.lang.ClassNotFoundException
   */
  protected Class findClass (String name)
    throws ClassNotFoundException
  {
    throw new ClassNotFoundException ();
  }
  /** 
   * Defines a class, given the class-data.  According to the JVM, this
   * method should not be used; instead use the variant of this method
   * in which the name of the class being defined is specified
   * explicitly.   
   * 
   * If the name of the class, as specified (implicitly) in the class
   * data, denotes a class which has already been loaded by this class
   * loader, an instance of
   * java.lang.ClassNotFoundException will be thrown.
   *
   * @param     data    bytes in class file format.
   * @param     off     offset to start interpreting data.
   * @param     len     length of data in class file.
   * @return    the class defined.
   * @exception java.lang.ClassNotFoundException 
   * @exception java.lang.LinkageError
   * @see ClassLoader#defineClass(String,byte[],int,int) */
  protected final Class defineClass(byte[] data, int off, int len) 
    throws java.lang.ClassNotFoundException, java.lang.LinkageError
  {
    return defineClass (null, data, off, len);
  }
  /** 
   * Defines a class, given the class-data.  This is preferable
   * over defineClass(byte[],off,len) since it is more
   * secure.  If the expected name does not match that of the class
   * file, ClassNotFoundException is thrown.  If
   * name denotes the name of an already loaded class, a
   * LinkageError is thrown.
   * 
* * FIXME: How do we assure that the class-file data is not being * modified, simultaneously with the class loader running!? If this * was done in some very clever way, it might break security. * Right now I am thinking that defineclass should make sure never to * read an element of this array more than once, and that that would * assure the ``immutable'' appearance. It is still to be determined * if this is in fact how defineClass operates. * * @param name the expected name. * @param data bytes in class file format. * @param off offset to start interpreting data. * @param len length of data in class file. * @return the class defined. * @exception java.lang.ClassNotFoundException * @exception java.lang.LinkageError */ protected final synchronized Class defineClass(String name, byte[] data, int off, int len) throws java.lang.ClassNotFoundException, java.lang.LinkageError { if (data==null || data.length < off+len || off<0 || len<0) throw new ClassFormatError ("arguments to defineClass " + "are meaningless"); // as per 5.3.5.1 if (name != null && findLoadedClass (name) != null) throw new java.lang.LinkageError ("class " + name + " already loaded"); try { // Since we're calling into native code here, // we better make sure that any generated // exception is to spec! return defineClass0 (name, data, off, len); } catch (java.lang.LinkageError x) { throw x; // rethrow } catch (java.lang.ClassNotFoundException x) { throw x; // rethrow } catch (java.lang.VirtualMachineError x) { throw x; // rethrow } catch (java.lang.Throwable x) { // This should never happen, or we are beyond spec. throw new InternalError ("Unexpected exception " + "while defining class " + name + ": " + x.toString ()); } } /** This is the entry point of defineClass into the native code */ private native Class defineClass0 (String name, byte[] data, int off, int len) throws java.lang.ClassNotFoundException, java.lang.LinkageError; /** This is called by defineClass0, once the "raw" and uninitialized * class object has been created, and handles exceptions generated * while actually defining the class (_Jv_DefineClass). defineClass0 * holds the lock on the new class object, so it needs to capture * these exceptions. */ private static Throwable defineClass1 (Class klass, byte[] data, int offset, int length) { try { defineClass2 (klass, data, offset, length); } catch (Throwable x) { return x; } return null; } /** This is just a wrapper for _Jv_DefineClass */ private static native void defineClass2 (Class klass, byte[] data, int offset, int length) throws Throwable; /** * Link the given class. This will bring the class to a state where * the class initializer can be run. Linking involves the following * steps: *
gcj-compiled classes, only the first step is
   * performed.  The compiler will have done the rest already.
   * * This is called by the system automatically, * as part of class initialization; there is no reason to ever call * this method directly. *
 
   * For historical reasons, this method has a name which is easily
   * misunderstood.  Java classes are never ``resolved''.  Classes are
   * linked; whereas method and field references are resolved.
   *
   * @param     clazz the class to link.
   * @exception java.lang.LinkageError
   */
  protected final void resolveClass(Class clazz)
    throws java.lang.LinkageError
  {
    resolveClass0(clazz);
  }
  static void resolveClass0(Class clazz)
    throws java.lang.LinkageError
  {
    synchronized (clazz)
      {
	try {
	  linkClass0 (clazz);
	} catch (Throwable x) {
	  markClassErrorState0 (clazz);
	  if (x instanceof Error)
	    throw (Error)x;
	  else    
	    throw new java.lang.InternalError
	      ("unexpected exception during linking: " + x);
	}
      }
  }
  /** Internal method.  Calls _Jv_PrepareClass and
   * _Jv_PrepareCompiledClass.  This is only called from resolveClass.  */ 
  private static native void linkClass0(Class clazz)
    throws java.lang.LinkageError;
  /** Internal method.  Marks the given clazz to be in an erroneous
   * state, and calls notifyAll() on the class object.  This should only
   * be called when the caller has the lock on the class object.  */
  private static native void markClassErrorState0(Class clazz);
  /** 
   * Returns a class found in a system-specific way, typically
   * via the java.class.path system property.  Loads the 
   * class if necessary.
   *
   * @param     name the class to resolve.
   * @return    the class loaded.
   * @exception java.lang.LinkageError 
   * @exception java.lang.ClassNotFoundException 
   */
  protected Class findSystemClass(String name) 
    throws java.lang.ClassNotFoundException, java.lang.LinkageError
  {
    return getSystemClassLoader ().loadClass (name);
  }
  /*
   * Does currently nothing.
   */ 
  protected final void setSigners(Class claz, Object[] signers) {
    /* claz.setSigners (signers); */
  }
  /**
   * If a class named name was previously loaded using
   * this ClassLoader, then it is returned.  Otherwise
   * it returns null.  (Unlike the JDK this is native,
   * since we implement the class table internally.)
   * @param     name  class to find.
   * @return    the class loaded, or null.
   */ 
  protected native Class findLoadedClass(String name);
  public static final InputStream getSystemResourceAsStream(String name) {
    return system.getResourceAsStream (name);
  }
  public static final URL getSystemResource(String name) {
    return system.getResource (name);
  }
  /**
   *   Return an InputStream representing the resource name.  
   *   This is essentially like 
   *   getResource(name).openStream(), except
   *   it masks out any IOException and returns null on failure.
   * @param   name  resource to load
   * @return  an InputStream, or null
   * @see     java.lang.ClassLoader#getResource(String)
   * @see     java.io.InputStream
   */
  public InputStream getResourceAsStream(String name) 
  {
    try {
      URL res = getResource (name);
      if (res == null) return null;
      return res.openStream ();
    } catch (java.io.IOException x) {
       return null;
     }
  }
 
  /**
   * Return an java.io.URL representing the resouce name.  
   * The default implementation just returns null.
   * @param   name  resource to load
   * @return  a URL, or null if there is no such resource.
   * @see     java.lang.ClassLoader#getResourceAsBytes(String)
   * @see     java.lang.ClassLoader#getResourceAsStream(String)
   * @see     java.io.URL
   */
  public URL getResource(String name) {
    return null;
  }
}