OSDN Git Service

2007-04-02 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / ClassLoader.java
index 2621281..4682dbb 100644 (file)
@@ -1,5 +1,5 @@
 /* ClassLoader.java -- responsible for loading classes into the VM
-   Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -15,8 +15,8 @@ General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Classpath; see the file COPYING.  If not, write to the
-Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 USA.
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
 
 Linking this library statically or dynamically with other modules is
 making a combined work based on this library.  Thus, the terms and
@@ -38,12 +38,15 @@ exception statement from your version. */
 
 package java.lang;
 
+import gnu.classpath.SystemProperties;
+import gnu.classpath.VMStackWalker;
 import gnu.java.util.DoubleEnumeration;
 import gnu.java.util.EmptyEnumeration;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.nio.ByteBuffer;
 import java.security.CodeSource;
 import java.security.PermissionCollection;
 import java.security.Policy;
@@ -52,6 +55,9 @@ import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
 
+import java.util.concurrent.ConcurrentHashMap;
+import java.lang.annotation.Annotation;
+
 /**
  * The ClassLoader is a way of customizing the way Java gets its classes
  * and loads them into memory.  The verifier and other standard Java things
@@ -112,7 +118,6 @@ import java.util.Map;
  * @author Eric Blake (ebb9@email.byu.edu)
  * @see Class
  * @since 1.0
- * @status still missing 1.4 functionality
  */
 public abstract class ClassLoader
 {
@@ -157,6 +162,118 @@ public abstract class ClassLoader
     VMClassLoader.getSystemClassLoader();
 
   /**
+   * This cache maps from a Class to its associated annotations.  It's
+   * declared here so that when this class loader becomes unreachable,
+   * so will the corresponding cache.
+   */
+
+  private final ConcurrentHashMap<AnnotationsKey,Object[]> 
+    declaredAnnotations 
+      = new ConcurrentHashMap<AnnotationsKey,Object[]>();
+  
+  static final class AnnotationsKey
+  {
+    final int /* jv_attr_type */ member_type;
+    final int member_index;
+    final int /* jv_attr_kind */ kind_req;
+    final Class declaringClass;
+    final int hashCode;
+
+    public AnnotationsKey (Class declaringClass,
+                          int member_type,
+                          int member_index,
+                          int kind_req)
+    {
+      this.member_type = member_type;
+      this.member_index = member_index;
+      this.kind_req = kind_req;
+      this.declaringClass = declaringClass;
+      hashCode = (member_type ^ member_index ^ kind_req
+                 ^ declaringClass.hashCode());
+    }
+
+    public boolean equals(Object obj)
+    {
+      AnnotationsKey other = (AnnotationsKey)obj;
+      return (this.member_type == other.member_type
+             && this.member_index == other.member_index
+             && this.kind_req == other.kind_req
+             && this.declaringClass == other.declaringClass);
+    }
+
+    public int hashCode()
+    {
+      return hashCode;
+    }
+
+    public static final Annotation[] NIL = new Annotation[0];
+  }
+  
+  final Object[] getDeclaredAnnotations(Class declaringClass,
+                                       int member_type,
+                                       int member_index,
+                                       int kind_req)
+  {
+    Object[] result 
+      = declaredAnnotations.get (new AnnotationsKey
+                                (declaringClass,
+                                 member_type,
+                                 member_index,
+                                 kind_req));
+    if (result != AnnotationsKey.NIL && result != null)
+      return (Object[])result.clone();
+    return null;
+  }
+
+  final Object[] putDeclaredAnnotations(Class declaringClass,
+                                       int member_type,
+                                       int member_index,
+                                       int kind_req,
+                                       Object[] annotations)
+  {
+    declaredAnnotations.put 
+      (new AnnotationsKey
+       (declaringClass,        member_type,
+       member_index, kind_req), 
+       annotations == null ? AnnotationsKey.NIL : annotations);
+
+    return annotations == null ? null : (Object[])annotations.clone();
+  }
+
+  static
+  {
+    // Find out if we have to install a default security manager. Note
+    // that this is done here because we potentially need the system
+    // class loader to load the security manager and note also that we
+    // don't need the security manager until the system class loader
+    // is created.  If the runtime chooses to use a class loader that
+    // doesn't have the system class loader as its parent, it is
+    // responsible for setting up a security manager before doing so.
+    String secman = SystemProperties.getProperty("java.security.manager");
+    if (secman != null && SecurityManager.current == null)
+    {
+      if (secman.equals("") || secman.equals("default"))
+      {
+       SecurityManager.current = new SecurityManager();
+      }
+      else
+      {
+       try
+       {
+         Class cl = Class.forName(secman, false, systemClassLoader);
+         SecurityManager.current = (SecurityManager) cl.newInstance();
+       }
+       catch (Exception x)
+       {
+         throw (InternalError)
+           new InternalError("Unable to create SecurityManager")
+               .initCause(x);
+       }
+      }
+    }
+  }
+
+  /**
    * The default protection domain, used when defining a class with a null
    * paramter for the domain.
    */
@@ -255,11 +372,14 @@ public abstract class ClassLoader
    * @return the loaded class
    * @throws ClassNotFoundException if the class cannot be found
    */
-  public Class loadClass(String name) throws ClassNotFoundException
+  public Class<?> loadClass(String name) throws ClassNotFoundException
   {
     return loadClass(name, false);
   }
 
+  private native Class loadClassFromSig(String name)
+    throws ClassNotFoundException;
+
   /**
    * Load a class using this ClassLoader or its parent, possibly resolving
    * it as well using <code>resolveClass()</code>. It first tries to find
@@ -280,33 +400,48 @@ public abstract class ClassLoader
    * @return the loaded class
    * @throws ClassNotFoundException if the class cannot be found
    */
-  protected synchronized Class loadClass(String name, boolean resolve)
+  protected synchronized Class<?> loadClass(String name, boolean resolve)
     throws ClassNotFoundException
   {
-    // Have we already loaded this class?
-    Class c = findLoadedClass(name);
-    if (c != null)
-      return c;
+    SecurityManager sm = SecurityManager.current;
+    if (sm != null)
+      {
+       int lastDot = name.lastIndexOf('.');
+       if (lastDot != -1)
+         sm.checkPackageAccess(name.substring(0, lastDot));
+      }
 
-    // Can the class be loaded by a parent?
-    try
+    // Arrays are handled specially.
+    Class c;
+    if (name.length() > 0 && name.charAt(0) == '[')
+      c = loadClassFromSig(name);
+    else
       {
-       if (parent == null)
-         {
-           c = VMClassLoader.loadClass(name, resolve);
-           if (c != null)
-             return c;
-         }
-       else
+       // Have we already loaded this class?
+       c = findLoadedClass(name);
+       if (c == null)
          {
-           return parent.loadClass(name, resolve);
+           // Can the class be loaded by a parent?
+           try
+             {
+               if (parent == null)
+                 {
+                   c = VMClassLoader.loadClass(name, resolve);
+                   if (c != null)
+                     return c;
+                 }
+               else
+                 {
+                   return parent.loadClass(name, resolve);
+                 }
+             }
+           catch (ClassNotFoundException e)
+             {
+             }
+           // Still not found, we have to do it ourself.
+           c = findClass(name);
          }
       }
-    catch (ClassNotFoundException e)
-      {
-      }
-    // Still not found, we have to do it ourself.
-    c = findClass(name);
     if (resolve)
       resolveClass(c);
     return c;
@@ -354,7 +489,7 @@ public abstract class ClassLoader
    * @throws ClassNotFoundException when the class can not be found
    * @since 1.2
    */
-  protected Class findClass(String name) throws ClassNotFoundException
+  protected Class<?> findClass(String name) throws ClassNotFoundException
   {
     throw new ClassNotFoundException(name);
   }
@@ -372,7 +507,7 @@ public abstract class ClassLoader
    *         offset + len exceeds data
    * @deprecated use {@link #defineClass(String, byte[], int, int)} instead
    */
-  protected final Class defineClass(byte[] data, int offset, int len)
+  protected final Class<?> defineClass(byte[] data, int offset, int len)
     throws ClassFormatError
   {
     return defineClass(null, data, offset, len);
@@ -397,8 +532,8 @@ public abstract class ClassLoader
    * @throws SecurityException if name starts with "java."
    * @since 1.1
    */
-  protected final Class defineClass(String name, byte[] data, int offset,
-                                    int len) throws ClassFormatError
+  protected final Class<?> defineClass(String name, byte[] data, int offset,
+                                      int len) throws ClassFormatError
   {
     return defineClass(name, data, offset, len, null);
   }
@@ -426,15 +561,14 @@ public abstract class ClassLoader
    *         do not match up
    * @since 1.2
    */
-  protected final synchronized Class defineClass(String name, byte[] data,
-                                                int offset, int len,
-                                                ProtectionDomain domain)
+  protected final synchronized Class<?> defineClass(String name, byte[] data,
+                                                   int offset, int len,
+                                                   ProtectionDomain domain)
     throws ClassFormatError
   {
+    checkInitialized();
     if (domain == null)
       domain = defaultProtectionDomain;
-    if (! initialized)
-      throw new SecurityException("attempt to define class from uninitialized class loader");
     
     Class retval = VMClassLoader.defineClass(this, name, data,
                                             offset, len, domain);
@@ -443,6 +577,35 @@ public abstract class ClassLoader
   }
 
   /**
+   * Helper to define a class using the contents of a byte buffer. If
+   * the domain is null, the default of
+   * <code>Policy.getPolicy().getPermissions(new CodeSource(null,
+   * null))</code> is used. Once a class has been defined in a
+   * package, all further classes in that package must have the same
+   * set of certificates or a SecurityException is thrown.
+   *
+   * @param name the name to give the class.  null if unknown
+   * @param buf a byte buffer containing bytes that form a class.
+   * @param domain the ProtectionDomain to give to the class, null for the
+   *        default protection domain
+   * @return the class that was defined
+   * @throws ClassFormatError if data is not in proper classfile format
+   * @throws NoClassDefFoundError if the supplied name is not the same as
+   *                              the one specified by the byte buffer.
+   * @throws SecurityException if name starts with "java.", or if certificates
+   *         do not match up
+   * @since 1.5
+   */
+  protected final Class<?> defineClass(String name, ByteBuffer buf,
+                                      ProtectionDomain domain)
+    throws ClassFormatError
+  {
+    byte[] data = new byte[buf.remaining()];
+    buf.get(data);
+    return defineClass(name, data, 0, data.length, domain);
+  }
+
+  /**
    * Links the class, if that has not already been done. Linking basically
    * resolves all references to other classes made by this class.
    *
@@ -450,8 +613,9 @@ public abstract class ClassLoader
    * @throws NullPointerException if c is null
    * @throws LinkageError if linking fails
    */
-  protected final void resolveClass(Class c)
+  protected final void resolveClass(Class<?> c)
   {
+    checkInitialized();
     VMClassLoader.resolveClass(c);
   }
 
@@ -464,9 +628,10 @@ public abstract class ClassLoader
    * @return the found class
    * @throws ClassNotFoundException if the class cannot be found
    */
-  protected final Class findSystemClass(String name)
+  protected final Class<?> findSystemClass(String name)
     throws ClassNotFoundException
   {
+    checkInitialized();
     return Class.forName(name, false, systemClassLoader);
   }
 
@@ -486,8 +651,7 @@ public abstract class ClassLoader
     SecurityManager sm = System.getSecurityManager();
     if (sm != null)
       {
-        Class c = VMSecurityManager.getClassContext()[1];
-        ClassLoader cl = c.getClassLoader();
+       ClassLoader cl = VMStackWalker.getCallingClassLoader();
        if (cl != null && ! cl.isAncestorOf(this))
           sm.checkPermission(new RuntimePermission("getClassLoader"));
       }
@@ -502,8 +666,9 @@ public abstract class ClassLoader
    * @param signers the signers to set
    * @since 1.1
    */
-  protected final void setSigners(Class c, Object[] signers)
+  protected final void setSigners(Class<?> c, Object[] signers)
   {
+    checkInitialized();
     c.setSigners(signers);
   }
 
@@ -514,8 +679,9 @@ public abstract class ClassLoader
    * @return the found Class, or null if it is not found
    * @since 1.1
    */
-  protected final synchronized Class findLoadedClass(String name)
+  protected final synchronized Class<?> findLoadedClass(String name)
   {
+    checkInitialized();
     // NOTE: If the VM is keeping its own cache, it may make sense to have
     // this method be native.
     return (Class) loadedClasses.get(name);
@@ -568,15 +734,16 @@ public abstract class ClassLoader
    * @return an enumaration of all resources found
    * @throws IOException if I/O errors occur in the process
    * @since 1.2
+   * @specnote this was <code>final</code> prior to 1.5
    */
-  public final Enumeration getResources(String name) throws IOException
+  public Enumeration<URL> getResources(String name) throws IOException
   {
-    Enumeration parentResources;
+    Enumeration<URL> parentResources;
     if (parent == null)
       parentResources = VMClassLoader.getResources(name);
     else
       parentResources = parent.getResources(name);
-    return new DoubleEnumeration(parentResources, findResources(name));
+    return new DoubleEnumeration<URL>(parentResources, findResources(name));
   }
 
   /**
@@ -596,9 +763,9 @@ public abstract class ClassLoader
    * @throws IOException if I/O errors occur in the process
    * @since 1.2
    */
-  protected Enumeration findResources(String name) throws IOException
+  protected Enumeration<URL> findResources(String name) throws IOException
   {
-    return EmptyEnumeration.getInstance();
+    return (Enumeration<URL>) EmptyEnumeration.getInstance();
   }
 
   /**
@@ -643,7 +810,8 @@ public abstract class ClassLoader
    * @throws IOException if I/O errors occur in the process
    * @since 1.2
    */
-  public static Enumeration getSystemResources(String name) throws IOException
+  public static Enumeration<URL> getSystemResources(String name)
+    throws IOException
   {
     return systemClassLoader.getResources(name);
   }
@@ -700,14 +868,15 @@ public abstract class ClassLoader
 
   /**
    * Returns the system classloader. The system classloader (also called
-   * the application classloader) is the classloader that was used to
+   * the application classloader) is the classloader that is used to
    * load the application classes on the classpath (given by the system
    * property <code>java.class.path</code>. This is set as the context
    * class loader for a thread. The system property
    * <code>java.system.class.loader</code>, if defined, is taken to be the
    * name of the class to use as the system class loader, which must have
-   * a public constructor which takes a ClassLoader as a parent; otherwise this
-   * uses gnu.java.lang.SystemClassLoader.
+   * a public constructor which takes a ClassLoader as a parent. The parent
+   * class loader passed in the constructor is the default system class
+   * loader.
    *
    * <p>Note that this is different from the bootstrap classloader that
    * actually loads all the real "system" classes (the bootstrap classloader
@@ -729,8 +898,7 @@ public abstract class ClassLoader
     SecurityManager sm = System.getSecurityManager();
     if (sm != null)
       {
-       Class c = VMSecurityManager.getClassContext()[1];
-       ClassLoader cl = c.getClassLoader();
+       ClassLoader cl = VMStackWalker.getCallingClassLoader();
        if (cl != null && cl != systemClassLoader)
          sm.checkPermission(new RuntimePermission("getClassLoader"));
       }
@@ -775,7 +943,7 @@ public abstract class ClassLoader
       throw new IllegalArgumentException("Package " + name
                                          + " already defined");
     Package p = new Package(name, specTitle, specVendor, specVersion,
-                            implTitle, implVendor, implVersion, sealed);
+                            implTitle, implVendor, implVersion, sealed, this);
     synchronized (definedPackages)
       {
         definedPackages.put(name, p);
@@ -854,7 +1022,7 @@ public abstract class ClassLoader
    *
    * @param name the (system specific) name of the requested library
    * @return the full pathname to the requested library, or null
-   * @see Runtime#loadLibrary()
+   * @see Runtime#loadLibrary(String)
    * @since 1.2
    */
   protected String findLibrary(String name)
@@ -884,7 +1052,7 @@ public abstract class ClassLoader
    *
    * @param name the package (and subpackages) to affect
    * @param enabled true to set the default to enabled
-   * @see #setDefaultAssertionStatus(String, boolean)
+   * @see #setDefaultAssertionStatus(boolean)
    * @see #setClassAssertionStatus(String, boolean)
    * @see #clearAssertionStatus()
    * @since 1.4
@@ -905,7 +1073,7 @@ public abstract class ClassLoader
    * @param name the class to affect
    * @param enabled true to set the default to enabled
    * @throws NullPointerException if name is null
-   * @see #setDefaultAssertionStatus(String, boolean)
+   * @see #setDefaultAssertionStatus(boolean)
    * @see #setPackageAssertionStatus(String, boolean)
    * @see #clearAssertionStatus()
    * @since 1.4
@@ -951,4 +1119,16 @@ public abstract class ClassLoader
       }
     return false;
   }
+
+  /**
+   * Before doing anything "dangerous" please call this method to make sure
+   * this class loader instance was properly constructed (and not obtained
+   * by exploiting the finalizer attack)
+   * @see #initialized
+   */
+  private void checkInitialized()
+  {
+    if (! initialized)
+      throw new SecurityException("attempt to use uninitialized class loader");
+  }
 }