/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.lang;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.NoSuchElementException;
import java.util.Vector;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.BootstrapClassLoader;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.classloader.RVMClassLoader;
import org.jikesrvm.classloader.RVMType;
import org.jikesrvm.runtime.DynamicLibrary;
import org.apache.harmony.lang.RuntimePermissionCollection;
/**
* <p>
* A ClassLoader is used for loading classes.
* </p>
*
* <h4>VM Implementors Note</h4>
* <p>
* This class must be implemented by the VM. The documented methods and natives
* must be implemented to support other provided class implementations in this
* package.
* </p>
*
* @since 1.0
* @see Class
*/
public abstract class ClassLoader {
/**
* Print extra debug info.
*/
private static final boolean DEBUG = false;
/**
* empty set of certificates
*/
private static final Certificate[] EMPTY_CERTIFICATES = new Certificate[0];
/**
* default protection domain.
*/
private ProtectionDomain defaultDomain;
/**
* Map containing all packages defined in the class loader
*/
private final HashMap<String, Package> definedPackages;
/**
* Map containing all classes loaded by the class loader
*/
private final HashMap<String, Class<?>> loadedClasses;
/**
* The following
* mapping is used <String name, Certificate[] certificates>, where name -
* the name of a package, certificates - array of certificates.
*/
private final Hashtable<String, Certificate[]> packageCertificates;
/**
* The 'System' ClassLoader; also known as the bootstrap ClassLoader.
*
* @see #getSystemClassLoader()
*/
private static ClassLoader systemClassLoader;
/**
* parent class loader
*/
private final ClassLoader parentClassLoader;
/**
* Constructs a new instance of this class with the system class loader as
* its parent.
*
* @throws SecurityException
* if a security manager exists and it does not allow the
* creation of new ClassLoaders.
*/
protected ClassLoader() {
this(getSystemClassLoader());
}
/**
* Constructs a new instance of this class with the given class loader as
* its parent.
*
* @param parentLoader
* The ClassLoader to use as the new class loaders parent.
* @throws SecurityException
* if a security manager exists and it does not allow the
* creation of new ClassLoaders.
* @throws NullPointerException
* if the parent is null.
*/
protected ClassLoader(ClassLoader parentLoader) {
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
sc.checkCreateClassLoader();
}
parentClassLoader = parentLoader;
definedPackages = new HashMap<String, Package>();
loadedClasses = new HashMap<String, Class<?>>();
packageCertificates = new Hashtable<String, Certificate[]>();
}
/**
* <p>
* TODO Document this method.
* </p>
*/
static final void initializeClassLoaders() {
return;
}
/**
* Returns the system class loader. This is the parent for new ClassLoader
* instances, and is typically the class loader used to start the
* application. If a security manager is present, and the caller's class
* loader is not null and the caller's class loader is not the same as or an
* ancestor of the system class loader, then this method calls the security
* manager's checkPermission method with a
* RuntimePermission("getClassLoader") permission to ensure it's ok to
* access the system class loader. If not, a SecurityException will be
* thrown.
*
* @return The system classLoader.
* @throws SecurityException
* if a security manager exists and it does not allow access to
* the system class loader.
*/
public static ClassLoader getSystemClassLoader() {
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
// we use VMClassRegistry.getClassLoader(...) method instead of
// Class.getClassLoader() due to avoid redundant security
// checking
ClassLoader callerLoader = RVMClass.getClassLoaderFromStackFrame(1);
if (callerLoader != null && callerLoader != systemClassLoader) {
sc.checkPermission(RuntimePermissionCollection.GET_CLASS_LOADER_PERMISSION);
}
}
return BootstrapClassLoader.getBootstrapClassLoader();
}
/**
* Answers an URL specifying a resource which can be found by looking up
* resName using the system class loader's resource lookup algorithm.
*
* @return A URL specifying a system resource or null.
* @param resName
* The name of the resource to find.
* @see Class#getResource
*/
public static URL getSystemResource(String resName) {
return getSystemClassLoader().getResource(resName);
}
/**
* Answers an Enumeration of URLs containing all resources which can be
* found by looking up resName using the system class loader's resource
* lookup algorithm.
*
* @return An Enumeration of URLs containing the system resources
* @param resName
* String the name of the resource to find.
* @throws IOException
* if an IO exception occurs
*/
public static Enumeration<URL> getSystemResources(String resName)
throws IOException {
return getSystemClassLoader().getResources(resName);
}
/**
* Answers a stream on a resource found by looking up resName using the
* system class loader's resource lookup algorithm. Basically, the contents
* of the java.class.path are searched in order, looking for a path which
* matches the specified resource.
*
* @return A stream on the resource or null.
* @param resName
* The name of the resource to find.
* @see Class#getResourceAsStream
*/
public static InputStream getSystemResourceAsStream(String resName) {
return getSystemClassLoader().getResourceAsStream(resName);
}
/**
* Constructs a new class from an array of bytes containing a class
* definition in class file format.
*
* @param classRep
* A memory image of a class file.
* @param offset
* The offset into the classRep.
* @param length
* The length of the class file.
* @deprecated Use defineClass(String, byte[], int, int)
*/
@Deprecated
protected final Class<?> defineClass(byte[] classRep, int offset, int length)
throws ClassFormatError {
return defineClass(null, classRep, offset, length);
}
/**
* Constructs a new class from an array of bytes containing a class
* definition in class file format.
*
* @param className
* The name of the new class
* @param classRep
* A memory image of a class file
* @param offset
* The offset into the classRep
* @param length
* The length of the class file
*/
protected final Class<?> defineClass(String className, byte[] classRep,
int offset, int length) throws ClassFormatError {
return defineClass(className, classRep, offset, length, null);
}
/**
* Constructs a new class from an array of bytes containing a class
* definition in class file format and assigns the new class to the
* specified protection domain.
*
* @param className
* The name of the new class.
* @param classRep
* A memory image of a class file.
* @param offset
* The offset into the classRep.
* @param length
* The length of the class file.
* @param protectionDomain
* The protection domain this class should belongs to.
*/
protected final Class<?> defineClass(String className, byte[] classRep,
int offset, int length, ProtectionDomain protectionDomain)
throws java.lang.ClassFormatError {
if (className != null && className.indexOf('/') != -1) {
throw new NoClassDefFoundError(
"The name is expected in binary (canonical) form,"
+ " therefore '/' symbols are not allowed: " + className);
}
if (offset < 0 || length < 0 || offset + length > classRep.length) {
throw new IndexOutOfBoundsException(
"Either offset or len is outside of the data array");
}
if (protectionDomain == null) {
if (defaultDomain == null) {
defaultDomain = new ProtectionDomain(
new CodeSource(null, (Certificate[])null), null, this, null);
}
protectionDomain = defaultDomain;
}
Certificate[] certs = null;
String packageName = null;
if (className != null) {
if (className.startsWith("java.")) {
throw new SecurityException(
"It is not allowed to define classes inside the java.* package: " + className);
}
int lastDot = className.lastIndexOf('.');
packageName = lastDot == -1 ? "" : className.substring(0, lastDot);
certs = getCertificates(packageName, protectionDomain.getCodeSource());
}
Class<?> clazz = defineClass0(className, classRep, offset, length);
clazz.setProtectionDomain(protectionDomain);
if (certs != null) {
packageCertificates.put(packageName, certs);
}
return clazz;
}
/**
* Loads new type into the classloader name space.
* The class loader is marked as defining class loader.
*/
private Class<?> defineClass0(String name, byte[] data, int offset, int len)
throws ClassFormatError {
RVMType vmType = RVMClassLoader.defineClassInternal(name, data, offset, len, this);
Class<?> ans = vmType.getClassForType();
loadedClasses.put(name, ans);
return ans;
}
/**
* <p>
* Defines a new class for the name, bytecodes in the byte buffer and the
* protection domain.
* </p>
*
* @param name
* The name of the class to define.
* @param b
* The byte buffer containing the bytecodes of the new class.
* @param protectionDomain
* The protection domain this class belongs to.
* @return The defined class.
* @throws ClassFormatError
* if an invalid class file is defined.
* @since 1.5
*/
protected final Class<?> defineClass(String name, ByteBuffer b,
ProtectionDomain protectionDomain) throws ClassFormatError {
byte[] temp = new byte[b.remaining()];
b.get(temp);
return defineClass(name, temp, 0, temp.length, protectionDomain);
}
/**
* Overridden by subclasses, by default throws ClassNotFoundException. This
* method is called by loadClass() after the parent ClassLoader has failed
* to find a loaded class of the same name.
*
* @return The class or null.
* @param className
* The name of the class to search for.
* @throws ClassNotFoundException
* if the class cannot be found.
*/
protected Class<?> findClass(String className)
throws ClassNotFoundException {
throw new ClassNotFoundException("Can not find class " + className);
}
/**
* Attempts to find and return a class which has already been loaded by the
* virtual machine. Note that the class may not have been linked and the
* caller should call resolveClass() on the result if necessary.
*
* @return The class or null.
* @param className
* The name of the class to search for.
*/
protected final Class<?> findLoadedClass(String className) {
return loadedClasses.get(className);
}
/**
* Attempts to load a class using the system class loader. Note that the
* class has already been been linked.
*
* @return The class which was loaded.
* @param className
* The name of the class to search for.
* @throws ClassNotFoundException
* if the class cannot be found.
*/
protected final Class<?> findSystemClass(String className)
throws ClassNotFoundException {
return getSystemClassLoader().loadClass(className, false);
}
/**
* Returns the specified ClassLoader's parent.
*
* @return The class or null.
* @throws SecurityException
* if a security manager exists and it does not allow the parent
* loader to be retrieved.
*/
public final ClassLoader getParent() {
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
ClassLoader callerLoader = RVMClass.getClassLoaderFromStackFrame(1);
if (callerLoader != null && !callerLoader.isSameOrAncestor(this)) {
sc.checkPermission(RuntimePermissionCollection.GET_CLASS_LOADER_PERMISSION);
}
}
return parentClassLoader;
}
/**
* Answers an URL which can be used to access the resource described by
* resName, using the class loader's resource lookup algorithm. The default
* behavior is just to return null.
*
* @return The location of the resource.
* @param resName
* String the name of the resource to find.
* @see Class#getResource(String)
*/
public URL getResource(String resName) {
String nm = resName.toString(); // NPE if null
URL foundResource = (parentClassLoader == null)
? BootstrapClassLoader.getBootstrapClassLoader().findResource(nm)
: parentClassLoader.getResource(nm);
return foundResource == null ? findResource(nm) : foundResource;
}
/**
* Answers an Enumeration of URL which can be used to access the resources
* described by resName, using the class loader's resource lookup algorithm.
* The default behavior is just to return an empty Enumeration.
*
* @return The location of the resources.
* @param resName
* String the name of the resource to find.
* @throws IOException
* if an IO exception occurs
*/
public Enumeration<URL> getResources(String resName) throws IOException {
if (DEBUG) org.jikesrvm.VM.sysWriteln("getResources " + resName);
ClassLoader cl = this;
final ArrayList<Enumeration<URL>> foundResources =
new ArrayList<Enumeration<URL>>();
Enumeration<URL> resourcesEnum;
do {
resourcesEnum = cl.findResources(resName);
if (resourcesEnum != null && resourcesEnum.hasMoreElements()) {
foundResources.add(resourcesEnum);
}
} while ((cl = cl.parentClassLoader) != null);
resourcesEnum = BootstrapClassLoader.getBootstrapClassLoader().findResources(resName);
if (resourcesEnum != null && resourcesEnum.hasMoreElements()) {
foundResources.add(resourcesEnum);
}
return new Enumeration<URL>() {
private int position = foundResources.size() - 1;
public boolean hasMoreElements() {
while (position >= 0) {
if (foundResources.get(position).hasMoreElements()) {
return true;
}
position--;
}
return false;
}
public URL nextElement() {
while (position >= 0) {
try {
return (foundResources.get(position)).nextElement();
} catch (NoSuchElementException e) {}
position--;
}
throw new NoSuchElementException();
}
};
}
/**
* Answers a stream on a resource found by looking up resName using the
* class loader's resource lookup algorithm. The default behavior is just to
* return null.
*
* @return A stream on the resource or null.
* @param resName
* String the name of the resource to find.
* @see Class#getResourceAsStream
*/
public InputStream getResourceAsStream(String resName) {
URL foundResource = getResource(resName);
if (foundResource != null) {
try {
return foundResource.openStream();
} catch (IOException e) {
}
}
return null;
}
/**
* Invoked by the Virtual Machine when resolving class references.
* Equivalent to loadClass(className, false);
*
* @return The Class object.
* @param className
* The name of the class to search for.
* @throws ClassNotFoundException
* if the class could not be found.
*/
public Class<?> loadClass(String className) throws ClassNotFoundException {
return loadClass(className, false);
}
/**
* Loads the class with the specified name, optionally linking the class
* after load. Steps are: 1) Call findLoadedClass(className) to determine if
* class is loaded 2) Call loadClass(className, resolveClass) on the parent
* loader. 3) Call findClass(className) to find the class
*
* @return The Class object.
* @param className
* The name of the class to search for.
* @param resolveClass
* Indicates if class should be resolved after loading.
* @throws ClassNotFoundException
* if the class could not be found.
*/
protected Class<?> loadClass(String className, boolean resolveClass)
throws ClassNotFoundException {
if (className == null) {
throw new NullPointerException();
}
if(className.indexOf("/") != -1) {
throw new ClassNotFoundException(className);
}
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
if (parentClassLoader == null) {
clazz = BootstrapClassLoader.getBootstrapClassLoader().loadClass(className, false);
} else {
try {
clazz = parentClassLoader.loadClass(className);
// NB DRLVM does a trick here to determine the class loader
// for a class, for Jikes RVM this is unnecessary as we have
// the class loader in the type reference already pulled
// from the stack, bytecode or specified
} catch (ClassNotFoundException e) {
}
}
if (clazz == null) {
clazz = findClass(className);
if (clazz == null) {
throw new ClassNotFoundException(className);
}
}
}
if (resolveClass) {
resolveClass(clazz);
}
return clazz;
}
/**
* Forces a class to be linked (initialized). If the class has already been
* linked this operation has no effect.
*
* @param clazz
* The Class to link.
* @throws NullPointerException
* if clazz is null.
*/
protected final void resolveClass(Class<?> clazz) {
RVMType cls = JikesRVMSupport.getTypeForClass(clazz);
cls.resolve();
cls.instantiate();
cls.initialize();
}
/**
* This method must be provided by the VM vendor, as it is used by other
* provided class implementations in this package. A sample implementation
* of this method is provided by the reference implementation. This method
* is used by SecurityManager.classLoaderDepth(), currentClassLoader() and
* currentLoadedClass(). Answers true if the receiver is a system class
* loader.
*
* Note that this method has package visibility only. It is defined here to
* avoid the security manager check in getSystemClassLoader, which would be
* required to implement this method anywhere else.
*
*
* @return <code>true</code> if the receiver is a system class loader
* @see Class#getClassLoaderImpl()
*/
final boolean isSystemClassLoader() {
return BootstrapClassLoader.getBootstrapClassLoader() == this;
}
/**
* <p>
* Answers true if the receiver is the same or ancestor of another class loader.
* </p>
* <p>
* Note that this method has package visibility only. It is defined here to
* avoid the security manager check in getParent, which would be required to
* implement this method anywhere else.
* </p>
*
* @param child
* A child candidate
* @return <code>true</code> if the receiver is ancestor of the parameter
*/
final boolean isSameOrAncestor(ClassLoader child) {
while (child != null) {
if (this == child) {
return true;
}
child = child.parentClassLoader;
}
return false;
}
/**
* Answers an URL which can be used to access the resource described by
* resName, using the class loader's resource lookup algorithm. The default
* behavior is just to return null. This should be implemented by a
* ClassLoader.
*
* @return The location of the resource.
* @param resName
* The name of the resource to find.
*/
protected URL findResource(String resName) {
return null;
}
/**
* Answers an Enumeration of URL which can be used to access the resources
* described by resName, using the class loader's resource lookup algorithm.
* The default behavior is just to return an empty Enumeration.
*
* @param resName
* The name of the resource to find.
*
* @return The locations of the resources.
*
* @throws IOException
* when an error occurs
*/
protected Enumeration<URL> findResources(String resName) throws IOException {
// TODO: create a more efficient empty enum enumeration
return new Vector<URL>(0).elements();
}
/**
* Answers the absolute path of the file containing the library associated
* with the given name, or null. If null is answered, the system searches
* the directories specified by the system property "java.library.path".
*
* @return The library file name or null.
* @param libName
* The name of the library to find.
*/
protected String findLibrary(String libName) {
return null;
}
/**
* Attempt to locate the requested package. If no package information can be
* located, null is returned.
*
* @param name
* The name of the package to find
* @return The package requested, or null
*/
protected Package getPackage(String name) {
Package pkg = null;
if (name == null) {
throw new NullPointerException();
}
synchronized (definedPackages) {
pkg = definedPackages.get(name);
}
if (pkg == null) {
if (parentClassLoader == null) {
if (this != BootstrapClassLoader.getBootstrapClassLoader()) {
pkg = BootstrapClassLoader.getBootstrapClassLoader().getPackage(name);
} else {
pkg = null;
}
} else {
pkg = parentClassLoader.getPackage(name);
}
}
return pkg;
}
/**
* Return all the packages known to this class loader.
*
* @return All the packages known to this classloader
*/
protected Package[] getPackages() {
ArrayList<Package> packages = new ArrayList<Package>();
fillPackages(packages);
return packages.toArray(new Package[packages.size()]);
}
/**
* Define a new Package using the specified information.
*
* @param name
* The name of the package
* @param specTitle
* The title of the specification for the Package
* @param specVersion
* The version of the specification for the Package
* @param specVendor
* The vendor of the specification for the Package
* @param implTitle
* The implementation title of the Package
* @param implVersion
* The implementation version of the Package
* @param implVendor
* The specification vendor of the Package
* @param sealBase
* If sealBase is null, the package is left unsealed. Otherwise,
* the the package is sealed using this URL.
* @return The Package created
* @throws IllegalArgumentException
* if the Package already exists
*/
protected Package definePackage(String name, String specTitle,
String specVersion, String specVendor, String implTitle,
String implVersion, String implVendor, URL sealBase)
throws IllegalArgumentException {
synchronized (definedPackages) {
if (getPackage(name) != null) {
throw new IllegalArgumentException("Package " + name
+ "has been already defined.");
}
Package pkg = new Package(this, name, specTitle, specVersion, specVendor,
implTitle, implVersion, implVendor, sealBase);
definedPackages.put(name, pkg);
return pkg;
}
}
/**
* Gets the signers of a class.
*
* @param c
* The Class object
* @return signers The signers for the class
*/
final Object[] getSigners(Class<?> c) {
VM.sysWriteln("TODO ClassLoader.getSigners");
return null;
}
/**
* Sets the signers of a class.
*
* @param c
* The Class object
* @param signers
* The signers for the class
*/
protected final void setSigners(Class<?> c, Object[] signers) {
VM.sysWriteln("TODO ClassLoader.setSigners");
return;
}
/**
* <p>
* This must be provided by the VM vendor. It is used by
* SecurityManager.checkMemberAccess() with depth = 3. Note that
* checkMemberAccess() assumes the following stack when called:<br>
* </p>
*
* <pre>
* < user code > <- want this class
* Class.getDeclared*();
* Class.checkMemberAccess();
* SecurityManager.checkMemberAccess(); <- current frame
* </pre>
*
* <p>
* Returns the ClassLoader of the method (including natives) at the
* specified depth on the stack of the calling thread. Frames representing
* the VM implementation of java.lang.reflect are not included in the list.
* </p>
* Notes:
* <ul>
* <li>This method operates on the defining classes of methods on stack.
* NOT the classes of receivers.</li>
* <li>The item at depth zero is the caller of this method</li>
* </ul>
*
* @param depth
* the stack depth of the requested ClassLoader
* @return the ClassLoader at the specified depth
*/
static final ClassLoader getStackClassLoader(int depth) {
return RVMClass.getClassLoaderFromStackFrame(depth);
}
/**
* This method must be included, as it is used by System.load(),
* System.loadLibrary(). The reference implementation of this method uses
* the getStackClassLoader() method. Returns the ClassLoader of the method
* that called the caller. i.e. A.x() calls B.y() calls callerClassLoader(),
* A's ClassLoader will be returned. Returns null for the bootstrap
* ClassLoader.
*
* @return a ClassLoader or null for the bootstrap ClassLoader
*/
static ClassLoader callerClassLoader() {
if (org.jikesrvm.VM.runningVM) {
ClassLoader ans = RVMClass.getClassLoaderFromStackFrame(1);
if (ans == BootstrapClassLoader.getBootstrapClassLoader()) {
return null;
} else {
return ans;
}
}
else {
return null;
}
}
/**
* This method must be provided by the VM vendor, as it is called by
* java.lang.System.loadLibrary(). System.loadLibrary() cannot call
* Runtime.loadLibrary() because this method loads the library using the
* ClassLoader of the calling method. Loads and links the library specified
* by the argument.
*
* @param libName
* the name of the library to load
* @param loader
* the classloader in which to load the library
* @throws UnsatisfiedLinkError
* if the library could not be loaded
* @throws SecurityException
* if the library was not allowed to be loaded
*/
static void loadLibraryWithClassLoader(String libName, ClassLoader loader) {
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
sc.checkLink(libName);
}
if (loader != null) {
String fullLibName = loader.findLibrary(libName);
if (fullLibName != null) {
loadLibrary(fullLibName, loader, null);
return;
}
}
String path = System.getProperty("java.library.path", "");
path += System.getProperty("vm.boot.library.path", "");
loadLibrary(libName, loader, path);
}
static final void loadLibrary (String libName, ClassLoader loader, String libraryPath) {
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
sc.checkLink(libName);
}
String pathSeparator = System.getProperty("path.separator");
String fileSeparator = System.getProperty("file.separator");
if (DEBUG) {
org.jikesrvm.VM.sysWriteln("path.separator=", pathSeparator);
org.jikesrvm.VM.sysWriteln("file.separator=", fileSeparator);
org.jikesrvm.VM.sysWriteln("libraryPath=", libraryPath);
}
String st[] = fracture(libraryPath, pathSeparator);
int l = st.length;
for (int i = 0; i < l; i++) {
// TODO: support loader argument
if (DEBUG) org.jikesrvm.VM.sysWriteln("load(" + st[i]+ fileSeparator + libName + ")");
if (DynamicLibrary.load(st[i] + fileSeparator + libName) != 0) {
return;
}
}
org.jikesrvm.VM.sysWriteln("ULE(" + libName + ")");
throw new UnsatisfiedLinkError(libName);
}
/**
* This method must be provided by the VM vendor, as it is called by
* java.lang.System.load(). System.load() cannot call Runtime.load() because
* the library is loaded using the ClassLoader of the calling method. Loads
* and links the library specified by the argument. No security check is
* done.
*
* @param libName
* the name of the library to load
* @param loader
* the classloader in which to load the library
* @param libraryPath
* the library path to search, or null
* @throws UnsatisfiedLinkError
* if the library could not be loaded
*/
static void loadLibraryWithPath(String libName, ClassLoader loader,
String libraryPath) {
throw new Error("TODO - no reference DRLVM code");
}
/**
* Sets the assertion status of a class.
*
* @param cname
* Class name
* @param enable
* Enable or disable assertion
*/
public void setClassAssertionStatus(String cname, boolean enable) {
VM.sysWriteln("TODO ClassLoader.setClassAssertionStatus");
return;
}
/**
* Sets the assertion status of a package.
*
* @param pname
* Package name
* @param enable
* Enable or disable assertion
*/
public void setPackageAssertionStatus(String pname, boolean enable) {
VM.sysWriteln("TODO ClassLoader.setPackageAssertionStatus");
return;
}
/**
* Sets the default assertion status of a classloader
*
* @param enable
* Enable or disable assertion
*/
public void setDefaultAssertionStatus(boolean enable) {
VM.sysWriteln("TODO ClassLoader.setDefaultAssertionStatus");
return;
}
/**
* Clears the default, package and class assertion status of a classloader
*
*/
public void clearAssertionStatus() {
VM.sysWriteln("TODO ClassLoader.clearAssertionStatus");
return;
}
/**
* Answers the assertion status of the named class Returns the assertion
* status of the class or nested class if it has been set. Otherwise returns
* the assertion status of its package or superpackage if that has been set.
* Otherwise returns the default assertion status. Returns 1 for enabled and
* 0 for disabled.
*
* @return the assertion status.
* @param cname
* the name of class.
*/
boolean getClassAssertionStatus(String cname) {
VM.sysWriteln("TODO ClassLoader.getClassAssertionStatus");
return false;
}
/**
* Answers the assertion status of the named package Returns the assertion
* status of the named package or superpackage if that has been set.
* Otherwise returns the default assertion status. Returns 1 for enabled and
* 0 for disabled.
*
* @return the assertion status.
* @param pname
* the name of package.
*/
boolean getPackageAssertionStatus(String pname) {
VM.sysWriteln("TODO ClassLoader.setPackageAssertionStatus");
return false;
}
/**
* Answers the default assertion status
*
* @return boolean the default assertion status.
*/
boolean getDefaultAssertionStatus() {
VM.sysWriteln("TODO ClassLoader.getDefaultAssertionStatus");
return false;
}
/**
* Helper method to avoid StringTokenizer using.
*/
private static String[] fracture(String str, String sep) {
if (str.length() == 0) {
return new String[0];
}
ArrayList<String> res = new ArrayList<String>();
int in = 0;
int curPos = 0;
int i = str.indexOf(sep);
int len = sep.length();
while (i != -1) {
String s = str.substring(curPos, i);
res.add(s);
in++;
curPos = i + len;
i = str.indexOf(sep, curPos);
}
len = str.length();
if (curPos <= len) {
String s = str.substring(curPos, len);
in++;
res.add(s);
}
return res.toArray(new String[in]);
}
/**
* Helper method for defineClass(...)
*
* @return null if the package already has the same set of certificates, if
* first class in the package is being defined then array of
* certificates extracted from codeSource is returned.
* @throws SecurityException if the package has different set of
* certificates than codeSource
*/
private Certificate[] getCertificates(String packageName,
CodeSource codeSource) {
Certificate[] definedCerts = packageCertificates
.get(packageName);
Certificate[] classCerts = codeSource != null
? codeSource.getCertificates() : EMPTY_CERTIFICATES;
classCerts = classCerts != null ? classCerts : EMPTY_CERTIFICATES;
// not first class in the package
if (definedCerts != null) {
if (!compareAsSet(definedCerts, classCerts)) {
throw new SecurityException("It is prohobited to define a "
+ "class which has different set of signers than "
+ "other classes in this package");
}
return null;
}
return classCerts;
}
/**
* Helper method for the getPackages() method.
*/
private void fillPackages(ArrayList<Package> packages) {
if (parentClassLoader != null) {
parentClassLoader.fillPackages(packages);
}
synchronized (definedPackages) {
packages.addAll(definedPackages.values());
}
}
/**
* Neither certs1 nor certs2 cann't be equal to null.
*/
private boolean compareAsSet(Certificate[] certs1, Certificate[] certs2) {
// TODO Is it possible to have multiple instances of same
// certificate in array? This implementation assumes that it is
// not possible.
if (certs1.length != certs1.length) {
return false;
}
if (certs1.length == 0) {
return true;
}
boolean[] hasEqual = new boolean[certs1.length];
for (int i = 0; i < certs1.length; i++) {
boolean isMatch = false;
for (int j = 0; j < certs2.length; j++) {
if (!hasEqual[j] && certs1[i].equals(certs2[j])) {
hasEqual[j] = isMatch = true;
break;
}
}
if (!isMatch) {
return false;
}
}
return true;
}
}