# HG changeset patch
# User Jaroslav Tulach While this interface method is declared to throw {@code
+ * Exception}, implementers are strongly encouraged to
+ * declare concrete implementations of the {@code close} method to
+ * throw more specific exceptions, or to throw no exception at all
+ * if the close operation cannot fail.
+ *
+ * Implementers of this interface are also strongly advised
+ * to not have the {@code close} method throw {@link
+ * InterruptedException}.
+ *
+ * This exception interacts with a thread's interrupted status,
+ * and runtime misbehavior is likely to occur if an {@code
+ * InterruptedException} is {@linkplain Throwable#addSuppressed
+ * suppressed}.
+ *
+ * More generally, if it would cause problems for an
+ * exception to be suppressed, the {@code AutoCloseable.close}
+ * method should not throw it.
+ *
+ * Note that unlike the {@link java.io.Closeable#close close}
+ * method of {@link java.io.Closeable}, this {@code close} method
+ * is not required to be idempotent. In other words,
+ * calling this {@code close} method more than once may have some
+ * visible side effect, unlike {@code Closeable.close} which is
+ * required to have no effect if called more than once.
+ *
+ * However, implementers of this interface are strongly encouraged
+ * to make their {@code close} methods idempotent.
+ *
+ * @throws Exception if this resource cannot be closed
+ */
+ void close() throws Exception;
+}
diff -r 5daeb26fb58d -r 484416f2dc2c emul/src/main/java/java/lang/ClassLoader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emul/src/main/java/java/lang/ClassLoader.java Tue Oct 30 08:27:04 2012 +0100
@@ -0,0 +1,2204 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+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.security.cert.Certificate;
+import java.util.Collections;
+import java.util.Enumeration;
+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 java.util.Hashtable;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import sun.misc.ClassFileTransformer;
+import sun.misc.CompoundEnumeration;
+import sun.misc.Resource;
+import sun.misc.URLClassPath;
+import sun.misc.VM;
+import sun.reflect.Reflection;
+import sun.security.util.SecurityConstants;
+
+/**
+ * A class loader is an object that is responsible for loading classes. The
+ * class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to
+ * locate or generate data that constitutes a definition for the class. A
+ * typical strategy is to transform the name into a file name and then read a
+ * "class file" of that name from a file system.
+ *
+ * Every {@link Class Class} object contains a {@link
+ * Class#getClassLoader() reference} to the ClassLoader that defined
+ * it.
+ *
+ * Class objects for array classes are not created by class
+ * loaders, but are created automatically as required by the Java runtime.
+ * The class loader for an array class, as returned by {@link
+ * Class#getClassLoader()} is the same as the class loader for its element
+ * type; if the element type is a primitive type, then the array class has no
+ * class loader.
+ *
+ * Applications implement subclasses of ClassLoader in order to
+ * extend the manner in which the Java virtual machine dynamically loads
+ * classes.
+ *
+ * Class loaders may typically be used by security managers to indicate
+ * security domains.
+ *
+ * The ClassLoader class uses a delegation model to search for
+ * classes and resources. Each instance of ClassLoader has an
+ * associated parent class loader. When requested to find a class or
+ * resource, a ClassLoader instance will delegate the search for the
+ * class or resource to its parent class loader before attempting to find the
+ * class or resource itself. The virtual machine's built-in class loader,
+ * called the "bootstrap class loader", does not itself have a parent but may
+ * serve as the parent of a ClassLoader instance.
+ *
+ * Class loaders that support concurrent loading of classes are known as
+ * parallel capable class loaders and are required to register
+ * themselves at their class initialization time by invoking the
+ * {@link
+ * #registerAsParallelCapable ClassLoader.registerAsParallelCapable}
+ * method. Note that the ClassLoader class is registered as parallel
+ * capable by default. However, its subclasses still need to register themselves
+ * if they are parallel capable. Normally, the Java virtual machine loads classes from the local file
+ * system in a platform-dependent manner. For example, on UNIX systems, the
+ * virtual machine loads classes from the directory defined by the
+ * CLASSPATH environment variable.
+ *
+ * However, some classes may not originate from a file; they may originate
+ * from other sources, such as the network, or they could be constructed by an
+ * application. The method {@link #defineClass(String, byte[], int, int)
+ * defineClass} converts an array of bytes into an instance of class
+ * Class. Instances of this newly defined class can be created using
+ * {@link Class#newInstance Class.newInstance}.
+ *
+ * The methods and constructors of objects created by a class loader may
+ * reference other classes. To determine the class(es) referred to, the Java
+ * virtual machine invokes the {@link #loadClass loadClass} method of
+ * the class loader that originally created the class.
+ *
+ * For example, an application could create a network class loader to
+ * download class files from a server. Sample code might look like:
+ *
+ * The network class loader subclass must define the methods {@link
+ * #findClass findClass} and loadClassData to load a class
+ * from the network. Once it has downloaded the bytes that make up the class,
+ * it should use the method {@link #defineClass defineClass} to
+ * create a class instance. A sample implementation is:
+ *
+ * Any class name provided as a {@link String} parameter to methods in
+ * ClassLoader must be a binary name as defined by
+ * The Java™ Language Specification.
+ *
+ * Examples of valid class names include:
+ * If there is a security manager, its {@link
+ * SecurityManager#checkCreateClassLoader()
+ * checkCreateClassLoader} method is invoked. This may result in
+ * a security exception. If there is a security manager, its {@link
+ * SecurityManager#checkCreateClassLoader()
+ * checkCreateClassLoader} method is invoked. This may result in
+ * a security exception.
+ * In environments in which the delegation model is not strictly
+ * hierarchical, class loaders need to be parallel capable, otherwise class
+ * loading can lead to deadlocks because the loader lock is held for the
+ * duration of the class loading process (see {@link #loadClass
+ * loadClass} methods).
+ *
+ *
+ *
+ *
+ * ClassLoader loader = new NetworkClassLoader(host, port);
+ * Object main = loader.loadClass("Main", true).newInstance();
+ * . . .
+ *
+ *
+ *
+ * class NetworkClassLoader extends ClassLoader {
+ * String host;
+ * int port;
+ *
+ * public Class findClass(String name) {
+ * byte[] b = loadClassData(name);
+ * return defineClass(name, b, 0, b.length);
+ * }
+ *
+ * private byte[] loadClassData(String name) {
+ * // load the class data from the connection
+ * . . .
+ * }
+ * }
+ *
Binary names
+ *
+ *
+ *
+ * @see #resolveClass(Class)
+ * @since 1.0
+ */
+public abstract class ClassLoader {
+
+ private static native void registerNatives();
+ static {
+ registerNatives();
+ }
+
+ // The parent class loader for delegation
+ // Note: VM hardcoded the offset of this field, thus all new fields
+ // must be added *after* it.
+ private final ClassLoader parent;
+
+ /**
+ * Encapsulates the set of parallel capable loader types.
+ */
+ private static class ParallelLoaders {
+ private ParallelLoaders() {}
+
+ // the set of parallel capable loader types
+ private static final Set
+ * "java.lang.String"
+ * "javax.swing.JSpinner$DefaultEditor"
+ * "java.security.KeyStore$Builder$FileBuilder$1"
+ * "java.net.URLClassLoader$3$1"
+ *
Invoke {@link #findLoadedClass(String)} to check if the class + * has already been loaded.
Invoke the {@link #loadClass(String) loadClass} method + * on the parent class loader. If the parent is null the class + * loader built-in to the virtual machine is used, instead.
Invoke the {@link #findClass(String)} method to find the + * class.
If the class was found using the above steps, and the + * resolve flag is true, this method will then invoke the {@link + * #resolveClass(Class)} method on the resulting Class object. + * + *
Subclasses of ClassLoader are encouraged to override {@link + * #findClass(String)}, rather than this method.
+ * + *Unless overridden, this method synchronizes on the result of + * {@link #getClassLoadingLock getClassLoadingLock} method + * during the entire class loading process. + * + * @param name + * The binary name of the class + * + * @param resolve + * If true then resolve the class + * + * @return The resulting Class object + * + * @throws ClassNotFoundException + * If the class could not be found + */ + protected Class> loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + synchronized (getClassLoadingLock(name)) { + // First, check if the class has already been loaded + Class c = findLoadedClass(name); + if (c == null) { + long t0 = System.nanoTime(); + try { + if (parent != null) { + c = parent.loadClass(name, false); + } else { + c = findBootstrapClassOrNull(name); + } + } catch (ClassNotFoundException e) { + // ClassNotFoundException thrown if class not found + // from the non-null parent class loader + } + + if (c == null) { + // If still not found, then invoke findClass in order + // to find the class. + long t1 = System.nanoTime(); + c = findClass(name); + + // this is the defining class loader; record the stats + sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); + sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); + sun.misc.PerfCounter.getFindClasses().increment(); + } + } + if (resolve) { + resolveClass(c); + } + return c; + } + } + + /** + * Returns the lock object for class loading operations. + * For backward compatibility, the default implementation of this method + * behaves as follows. If this ClassLoader object is registered as + * parallel capable, the method returns a dedicated object associated + * with the specified class name. Otherwise, the method returns this + * ClassLoader object.
+ * + * @param className + * The name of the to-be-loaded class + * + * @return the lock for class loading operations + * + * @throws NullPointerException + * If registered as parallel capable and className is null + * + * @see #loadClass(String, boolean) + * + * @since 1.7 + */ + protected Object getClassLoadingLock(String className) { + Object lock = this; + if (parallelLockMap != null) { + Object newLock = new Object(); + lock = parallelLockMap.putIfAbsent(className, newLock); + if (lock == null) { + lock = newLock; + } + } + return lock; + } + + // This method is invoked by the virtual machine to load a class. + private Class loadClassInternal(String name) + throws ClassNotFoundException + { + // For backward compatibility, explicitly lock on 'this' when + // the current class loader is not parallel capable. + if (parallelLockMap == null) { + synchronized (this) { + return loadClass(name); + } + } else { + return loadClass(name); + } + } + + // Invoked by the VM after loading class with this loader. + 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 PrivilegedActionThis method assigns a default {@link java.security.ProtectionDomain + * ProtectionDomain} to the newly defined class. The + * ProtectionDomain is effectively granted the same set of + * permissions returned when {@link + * java.security.Policy#getPermissions(java.security.CodeSource) + * Policy.getPolicy().getPermissions(new CodeSource(null, null))} + * is invoked. The default domain is created on the first invocation of + * {@link #defineClass(String, byte[], int, int) defineClass}, + * and re-used on subsequent invocations. + * + *
To assign a specific ProtectionDomain to the class, use + * the {@link #defineClass(String, byte[], int, int, + * java.security.ProtectionDomain) defineClass} method that takes a + * ProtectionDomain as one of its arguments.
+ * + * @param name + * The expected binary name of the class, or + * null if not known + * + * @param b + * The bytes that make up the class data. The bytes in positions + * off through off+len-1 should have the format + * of a valid class file as defined by + * The Java™ Virtual Machine Specification. + * + * @param off + * The start offset in b of the class data + * + * @param len + * The length of the class data + * + * @return The Class object that was created from the specified + * class data. + * + * @throws ClassFormatError + * If the data did not contain a valid class + * + * @throws IndexOutOfBoundsException + * If either off or len is negative, or if + * off+len is greater than b.length. + * + * @throws SecurityException + * If an attempt is made to add this class to a package that + * contains classes that were signed by a different set of + * certificates than this class (which is unsigned), or if + * name begins with "java.". + * + * @see #loadClass(String, boolean) + * @see #resolveClass(Class) + * @see java.security.CodeSource + * @see java.security.SecureClassLoader + * + * @since 1.1 + */ + protected final Class> defineClass(String name, byte[] b, int off, int len) + throws ClassFormatError + { + return defineClass(name, b, off, len, null); + } + + /* Determine protection domain, and check that: + - not define java.* class, + - signer of this class matches signers for the rest of the classes in + package. + */ + private ProtectionDomain preDefineClass(String name, + ProtectionDomain pd) + { + if (!checkName(name)) + throw new NoClassDefFoundError("IllegalName: " + name); + + if ((name != null) && name.startsWith("java.")) { + throw new SecurityException + ("Prohibited package name: " + + name.substring(0, name.lastIndexOf('.'))); + } + if (pd == null) { + pd = defaultDomain; + } + + if (name != null) checkCerts(name, pd.getCodeSource()); + + return pd; + } + + private String defineClassSourceLocation(ProtectionDomain pd) + { + CodeSource cs = pd.getCodeSource(); + String source = null; + if (cs != null && cs.getLocation() != null) { + source = cs.getLocation().toString(); + } + return source; + } + + private Class defineTransformedClass(String name, byte[] b, int off, int len, + ProtectionDomain pd, + ClassFormatError cfe, String source) + throws ClassFormatError + { + // Class format error - try to transform the bytecode and + // define the class again + // + ClassFileTransformer[] transformers = + ClassFileTransformer.getTransformers(); + Class c = null; + + if (transformers != null) { + for (ClassFileTransformer transformer : transformers) { + try { + // Transform byte code using transformer + byte[] tb = transformer.transform(b, off, len); + c = defineClass1(name, tb, 0, tb.length, + pd, source); + break; + } catch (ClassFormatError cfe2) { + // If ClassFormatError occurs, try next transformer + } + } + } + + // Rethrow original ClassFormatError if unable to transform + // bytecode to well-formed + // + if (c == null) + throw cfe; + + return c; + } + + private void postDefineClass(Class c, ProtectionDomain pd) + { + if (pd.getCodeSource() != null) { + Certificate certs[] = pd.getCodeSource().getCertificates(); + if (certs != null) + setSigners(c, certs); + } + } + + /** + * Converts an array of bytes into an instance of class Class, + * with an optional ProtectionDomain. If the domain is + * null, then a default domain will be assigned to the class as + * specified in the documentation for {@link #defineClass(String, byte[], + * int, int)}. Before the class can be used it must be resolved. + * + *The first class defined in a package determines the exact set of + * certificates that all subsequent classes defined in that package must + * contain. The set of certificates for a class is obtained from the + * {@link java.security.CodeSource CodeSource} within the + * ProtectionDomain of the class. Any classes added to that + * package must contain the same set of certificates or a + * SecurityException will be thrown. Note that if + * name is null, this check is not performed. + * You should always pass in the binary name of the + * class you are defining as well as the bytes. This ensures that the + * class you are defining is indeed the class you think it is. + * + *
The specified name cannot begin with "java.", since + * all classes in the "java.* packages can only be defined by the + * bootstrap class loader. If name is not null, it + * must be equal to the binary name of the class + * specified by the byte array "b", otherwise a {@link + * NoClassDefFoundError} will be thrown.
+ * + * @param name + * The expected binary name of the class, or + * null if not known + * + * @param b + * The bytes that make up the class data. The bytes in positions + * off through off+len-1 should have the format + * of a valid class file as defined by + * The Java™ Virtual Machine Specification. + * + * @param off + * The start offset in b of the class data + * + * @param len + * The length of the class data + * + * @param protectionDomain + * The ProtectionDomain of the class + * + * @return The Class object created from the data, + * and optional ProtectionDomain. + * + * @throws ClassFormatError + * If the data did not contain a valid class + * + * @throws NoClassDefFoundError + * If name is not equal to the binary + * name of the class specified by b + * + * @throws IndexOutOfBoundsException + * If either off or len is negative, or if + * off+len is greater than b.length. + * + * @throws SecurityException + * If an attempt is made to add this class to a package that + * contains classes that were signed by a different set of + * certificates than this class, or if name begins with + * "java.". + */ + protected final Class> defineClass(String name, byte[] b, int off, int len, + ProtectionDomain protectionDomain) + throws ClassFormatError + { + protectionDomain = preDefineClass(name, protectionDomain); + + Class c = null; + String source = defineClassSourceLocation(protectionDomain); + + try { + c = defineClass1(name, b, off, len, protectionDomain, source); + } catch (ClassFormatError cfe) { + c = defineTransformedClass(name, b, off, len, protectionDomain, cfe, + source); + } + + postDefineClass(c, protectionDomain); + return c; + } + + /** + * Converts a {@link java.nio.ByteBuffer ByteBuffer} + * into an instance of class Class, + * with an optional ProtectionDomain. If the domain is + * null, then a default domain will be assigned to the class as + * specified in the documentation for {@link #defineClass(String, byte[], + * int, int)}. Before the class can be used it must be resolved. + * + *The rules about the first class defined in a package determining the + * set of certificates for the package, and the restrictions on class names + * are identical to those specified in the documentation for {@link + * #defineClass(String, byte[], int, int, ProtectionDomain)}. + * + *
An invocation of this method of the form + * cl.defineClass(name, + * bBuffer, pd) yields exactly the same + * result as the statements + * + *
+ * ...+ * + * @param name + * The expected binary name. of the class, or + * null if not known + * + * @param b + * The bytes that make up the class data. The bytes from positions + * b.position() through b.position() + b.limit() -1 + * should have the format of a valid class file as defined by + * The Java™ Virtual Machine Specification. + * + * @param protectionDomain + * The ProtectionDomain of the class, or null. + * + * @return The Class object created from the data, + * and optional ProtectionDomain. + * + * @throws ClassFormatError + * If the data did not contain a valid class. + * + * @throws NoClassDefFoundError + * If name is not equal to the binary + * name of the class specified by b + * + * @throws SecurityException + * If an attempt is made to add this class to a package that + * contains classes that were signed by a different set of + * certificates than this class, or if name begins with + * "java.". + * + * @see #defineClass(String, byte[], int, int, ProtectionDomain) + * + * @since 1.5 + */ + protected final Class> defineClass(String name, java.nio.ByteBuffer b, + ProtectionDomain protectionDomain) + throws ClassFormatError + { + int len = b.remaining(); + + // Use byte[] if not a direct ByteBufer: + if (!b.isDirect()) { + if (b.hasArray()) { + return defineClass(name, b.array(), + b.position() + b.arrayOffset(), len, + protectionDomain); + } else { + // no array, or read-only array + byte[] tb = new byte[len]; + b.get(tb); // get bytes out of byte buffer. + return defineClass(name, tb, 0, len, protectionDomain); + } + } + + protectionDomain = preDefineClass(name, protectionDomain); + + Class c = null; + String source = defineClassSourceLocation(protectionDomain); + + try { + c = defineClass2(name, b, b.position(), len, protectionDomain, + source); + } catch (ClassFormatError cfe) { + byte[] tb = new byte[len]; + b.get(tb); // get bytes out of byte buffer. + c = defineTransformedClass(name, tb, 0, len, protectionDomain, cfe, + source); + } + + postDefineClass(c, protectionDomain); + return c; + } + + private native Class defineClass0(String name, byte[] b, int off, int len, + ProtectionDomain pd); + + private native Class defineClass1(String name, byte[] b, int off, int len, + ProtectionDomain pd, String source); + + private native Class defineClass2(String name, java.nio.ByteBuffer b, + int off, int len, ProtectionDomain pd, + String source); + + // true if the name is null or has the potential to be a valid binary name + private boolean checkName(String name) { + if ((name == null) || (name.length() == 0)) + return true; + if ((name.indexOf('/') != -1) + || (!VM.allowArraySyntax() && (name.charAt(0) == '['))) + return false; + return true; + } + + private void checkCerts(String name, CodeSource cs) { + int i = name.lastIndexOf('.'); + String pname = (i == -1) ? "" : name.substring(0, i); + + Certificate[] certs = null; + if (cs != null) { + certs = cs.getCertificates(); + } + Certificate[] pcerts = null; + if (parallelLockMap == null) { + synchronized (this) { + pcerts = package2certs.get(pname); + if (pcerts == null) { + package2certs.put(pname, (certs == null? nocerts:certs)); + } + } + } else { + pcerts = ((ConcurrentHashMap
+ * byte[] temp = new byte[bBuffer.{@link + * java.nio.ByteBuffer#remaining remaining}()];
+ * bBuffer.{@link java.nio.ByteBuffer#get(byte[]) + * get}(temp);
+ * return {@link #defineClass(String, byte[], int, int, ProtectionDomain) + * cl.defineClass}(name, temp, 0, + * temp.length, pd);
+ *
This method loads the class through the system class loader (see + * {@link #getSystemClassLoader()}). The Class object returned + * might have more than one ClassLoader associated with it. + * Subclasses of ClassLoader need not usually invoke this method, + * because most class loaders need to override just {@link + * #findClass(String)}.
+ * + * @param name + * The binary name of the class + * + * @return The Class object for the specified name + * + * @throws ClassNotFoundException + * If the class could not be found + * + * @see #ClassLoader(ClassLoader) + * @see #getParent() + */ + protected final Class> findSystemClass(String name) + throws ClassNotFoundException + { + ClassLoader system = getSystemClassLoader(); + if (system == null) { + if (!checkName(name)) + throw new ClassNotFoundException(name); + Class cls = findBootstrapClass(name); + if (cls == null) { + throw new ClassNotFoundException(name); + } + return cls; + } + return system.loadClass(name); + } + + /** + * Returns a class loaded by the bootstrap class loader; + * or return null if not found. + */ + private Class findBootstrapClassOrNull(String name) + { + if (!checkName(name)) return null; + + return findBootstrapClass(name); + } + + // return null if not found + private native Class findBootstrapClass(String name); + + /** + * Returns the class with the given binary name if this + * loader has been recorded by the Java virtual machine as an initiating + * loader of a class with that binary name. Otherwise + * null is returned. + * + * @param name + * The binary name of the class + * + * @return The Class object, or null if the class has + * not been loaded + * + * @since 1.1 + */ + protected final Class> findLoadedClass(String name) { + if (!checkName(name)) + 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. + * + * @param c + * The Class object + * + * @param signers + * The signers for the class + * + * @since 1.1 + */ + protected final void setSigners(Class> c, Object[] signers) { + 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. + * + *The name of a resource is a '/'-separated path name that + * identifies the resource. + * + *
This method will first search the parent class loader for the + * resource; if the parent is null 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.
+ * + * @param name + * The resource name + * + * @return A URL object for reading the resource, or + * null 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. + * + *The name of a resource is a /-separated path name that + * identifies the resource. + * + *
The search order is described in the documentation for {@link + * #getResource(String)}.
+ * + * @param name + * The resource name + * + * @return An enumeration of {@link java.net.URL URL} 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 EnumerationThe search order is described in the documentation for {@link + * #getSystemResource(String)}.
+ * + * @param name + * The resource name + * + * @return An enumeration of resource {@link java.net.URL URL} + * objects + * + * @throws IOException + * If I/O errors occur + + * @since 1.2 + */ + public static EnumerationThe search order is described in the documentation for {@link + * #getResource(String)}.
+ * + * @param name + * The resource name + * + * @return An input stream for reading the resource, or null + * 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()}). + * + * @param name + * The resource name + * + * @return An input stream for reading the resource, or null + * 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 -- + + /** + * Returns the parent class loader for delegation. Some implementations may + * use null to represent the bootstrap class loader. This method + * will return null in such implementations if this class loader's + * parent is the bootstrap class loader. + * + *If a security manager is present, and the invoker's class loader is + * not null and is not an ancestor of this class loader, then this + * method invokes the security manager's {@link + * SecurityManager#checkPermission(java.security.Permission) + * checkPermission} method with a {@link + * RuntimePermission#RuntimePermission(String) + * RuntimePermission("getClassLoader")} permission to verify + * access to the parent class loader is permitted. If not, a + * SecurityException will be thrown.
+ * + * @return The parent ClassLoader + * + * @throws SecurityException + * If a security manager exists and its checkPermission + * method doesn't allow access to this class loader's parent class + * loader. + * + * @since 1.2 + */ + 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; + } + + /** + * Returns the system class loader for delegation. This is the default + * delegation parent for new ClassLoader instances, and is + * typically the class loader used to start the application. + * + *This method is first invoked early in the runtime's startup + * sequence, at which point it creates the system class loader and sets it + * as the context class loader of the invoking Thread. + * + *
The default system class loader is an implementation-dependent + * instance of this class. + * + *
If the system property "java.system.class.loader" is defined + * when this method is first invoked then the value of that property is + * taken to be the name of a class that will be returned as the system + * class loader. The class is loaded using the default system class loader + * and must define a public constructor that takes a single parameter of + * type ClassLoader which is used as the delegation parent. An + * instance is then created using this constructor with the default system + * class loader as the parameter. The resulting class loader is defined + * to be the system class loader. + * + *
If a security manager is present, and the invoker's class loader is + * not null and the invoker's class loader is not the same as or + * an ancestor of the system class loader, then this method invokes the + * security manager's {@link + * SecurityManager#checkPermission(java.security.Permission) + * checkPermission} method with a {@link + * RuntimePermission#RuntimePermission(String) + * RuntimePermission("getClassLoader")} permission to verify + * access to the system class loader. If not, a + * SecurityException will be thrown.
+ * + * @return The system ClassLoader for delegation, or + * null if none + * + * @throws SecurityException + * If a security manager exists and its checkPermission + * method doesn't allow access to the system class loader. + * + * @throws IllegalStateException + * If invoked recursively during the construction of the class + * loader specified by the "java.system.class.loader" + * property. + * + * @throws Error + * If the system property "java.system.class.loader" + * is defined but the named class could not be loaded, the + * provider class does not define the required constructor, or an + * exception is thrown by that constructor when it is invoked. The + * underlying cause of the error can be retrieved via the + * {@link Throwable#getCause()} method. + * + * @revised 1.4 + */ + 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; + } + + private static synchronized void initSystemClassLoader() { + if (!sclSet) { + if (scl != null) + throw new IllegalStateException("recursive invocation"); + sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); + if (l != null) { + Throwable oops = null; + scl = l.getClassLoader(); + try { + scl = AccessController.doPrivileged( + new SystemClassLoaderAction(scl)); + } 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; + } + } + + // Returns true if the specified class loader can be found in this class + // loader's delegation chain. + boolean isAncestor(ClassLoader cl) { + ClassLoader acl = this; + do { + acl = acl.parent; + if (cl == acl) { + return true; + } + } while (acl != null); + return false; + } + + // Returns the invoker's class loader, or null if none. + // NOTE: This must always be invoked when there is exactly one intervening + // frame from the core libraries on the stack between this method's + // invocation and the desired invoker. + static ClassLoader getCallerClassLoader() { + // NOTE use of more generic Reflection.getCallerClass() + Class caller = Reflection.getCallerClass(3); + // This can be null if the VM is requesting it + if (caller == null) { + return null; + } + // Circumvent security check since this is package-private + return caller.getClassLoader0(); + } + + // The class loader for the system + // @GuardedBy("ClassLoader.class") + private static ClassLoader scl; + + // Set to true once the system class loader has been set + // @GuardedBy("ClassLoader.class") + private static boolean sclSet; + + + // -- Package -- + + /** + * Defines a package by name in this ClassLoader. 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. + * + * @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 null, then this package is sealed with + * respect to the given code source {@link java.net.URL + * URL} object. Otherwise, the package is not sealed. + * + * @return The newly defined Package 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, this); + packages.put(name, pkg); + return pkg; + } + } + + /** + * Returns a Package that has been defined by this class loader + * or any of its ancestors. + * + * @param name + * The package name + * + * @return The Package corresponding to the given name, or + * null if not found + * + * @since 1.2 + */ + protected Package getPackage(String name) { + Package pkg; + synchronized (packages) { + pkg = packages.get(name); + } + if (pkg == null) { + if (parent != null) { + pkg = parent.getPackage(name); + } else { + pkg = Package.getSystemPackage(name); + } + if (pkg != null) { + synchronized (packages) { + Package pkg2 = packages.get(name); + if (pkg2 == null) { + packages.put(name, pkg); + } else { + pkg = pkg2; + } + } + } + } + return pkg; + } + + /** + * Returns all of the Packages defined by this class loader and + * its ancestors. + * + * @return The array of Package objects defined by this + * ClassLoader + * + * @since 1.2 + */ + protected Package[] getPackages() { + MapEvery native library requires a particular version of JNI. This is + * denoted by the private jniVersion 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.
+ * + * @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 ClassLoader.nativeLibraryContext.peek().fromClass; + } + } + + // All native library names we've loaded. + private static Vector