You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ko...@apache.org on 2005/08/13 20:51:45 UTC
svn commit: r232515 -
/jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/ContinuationClassLoader.java
Author: kohsuke
Date: Sat Aug 13 11:51:41 2005
New Revision: 232515
URL: http://svn.apache.org/viewcvs?rev=232515&view=rev
Log:
rewritten by using the URLClassLoader as the base class
Modified:
jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/ContinuationClassLoader.java
Modified: jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/ContinuationClassLoader.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/ContinuationClassLoader.java?rev=232515&r1=232514&r2=232515&view=diff
==============================================================================
--- jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/ContinuationClassLoader.java (original)
+++ jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/ContinuationClassLoader.java Sat Aug 13 11:51:41 2005
@@ -15,37 +15,26 @@
*/
package org.apache.commons.javaflow;
+import org.apache.commons.javaflow.bytecode.transformation.ClassTransformer;
+import org.apache.commons.javaflow.bytecode.transformation.bcel.BcelClassTransformer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URLClassLoader;
import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import org.apache.commons.javaflow.bytecode.transformation.ClassTransformer;
-import org.apache.commons.javaflow.bytecode.transformation.bcel.BcelClassTransformer;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
/**
- * ClassLoader with bytecode instrumentation for javaflow.
- *
- * <p>
- * This <tt>ClassLoader</tt> works like an <tt>URLClassLoader</tt>
- * in the sense that it locates class files from specified {@link File}s.
- * But instead of simply loading classes into the VM, this class loader
- * performs the bytecode instrumentation necessary for javaflow.
+ * {@link URLClassLoader} with bytecode instrumentation for javaflow.
*
* <p>
* This class loader is useful where the application can set up multiple
@@ -54,110 +43,14 @@
* <a href="http://forehead.werken.com/">Forehead</a>) and when you can
* isolate the continuation-enabled portion of your application into a separate
* jar file.
- *
- * <p>
- * This code is based on <tt>AntClassLoader</tt>.
*/
-public final class ContinuationClassLoader extends ClassLoader {
+public final class ContinuationClassLoader extends URLClassLoader {
private final static Log log = LogFactory.getLog(ContinuationClassLoader.class);
- /**
- * An enumeration of all resources of a given name found within the
- * classpath of this class loader. This enumeration is used by the
- * ClassLoader.findResources method, which is in
- * turn used by the ClassLoader.getResources method.
- *
- * @see ContinuationClassLoader#findResources(String)
- * @see java.lang.ClassLoader#getResources(String)
- */
- private class ResourceEnumeration implements Enumeration {
- /**
- * The name of the resource being searched for.
- */
- private String resourceName;
-
- /**
- * The index of the next classpath element to search.
- */
- private int pathElementsIndex;
-
- /**
- * The URL of the next resource to return in the enumeration. If this
- * field is <code>null</code> then the enumeration has been completed,
- * i.e., there are no more elements to return.
- */
- private URL nextResource;
-
- /**
- * Constructs a new enumeration of resources of the given name found
- * within this class loader's classpath.
- *
- * @param name the name of the resource to search for.
- */
- ResourceEnumeration(String name) {
- this.resourceName = name;
- this.pathElementsIndex = 0;
- findNextResource();
- }
-
- /**
- * Indicates whether there are more elements in the enumeration to
- * return.
- *
- * @return <code>true</code> if there are more elements in the
- * enumeration; <code>false</code> otherwise.
- */
- public boolean hasMoreElements() {
- return (this.nextResource != null);
- }
-
- /**
- * Returns the next resource in the enumeration.
- *
- * @return the next resource in the enumeration
- */
- public Object nextElement() {
- URL ret = this.nextResource;
- findNextResource();
- return ret;
- }
-
- /**
- * Locates the next resource of the correct name in the classpath and
- * sets <code>nextResource</code> to the URL of that resource. If no
- * more resources can be found, <code>nextResource</code> is set to
- * <code>null</code>.
- */
- private void findNextResource() {
- synchronized(ContinuationClassLoader.this) {
- URL url = null;
- while ((pathElementsIndex < pathComponents.size())
- && (url == null)) {
- File pathComponent
- = (File) pathComponents.get(pathElementsIndex);
- url = getResourceURL(pathComponent, this.resourceName);
- pathElementsIndex++;
- }
- this.nextResource = url;
- }
- }
- }
-
private final ClassTransformer transformer;
/**
- * The size of buffers to be used in this classloader.
- */
- private static final int BUFFER_SIZE = 8192;
-
- /**
- * The components of the classpath that the classloader searches
- * for classes. {@link List} of {@link File}s.
- */
- private List pathComponents = new ArrayList();
-
- /**
* Indicates whether the parent class loader should be
* consulted before trying to load with this class loader.
*/
@@ -190,66 +83,42 @@
*/
private ClassLoader parent = null;
- /**
- * A hashtable of zip files opened by the classloader (File to ZipFile).
- */
- private Map zipFiles = new HashMap();
+ /* The context to be used when loading classes and resources */
+ private final AccessControlContext acc;
+ private static final int BUFFER_SIZE = 4096;
/**
- * Creates a classloader using the classpath given.
+ * Creates a classloader by using the classpath given.
*
- * @param parent The parent classloader to which unsatisfied loading
- * attempts are delegated. May be <code>null</code>,
- * in which case the classloader which loaded this
- * class is used as the parent.
- * @param classpath
- * a {@link Collection} of {@link File}s.
- * the classpath to use to load the classes.
- * May be <code>null</code>, in which case no path
- * elements are set up to start with.
- */
- public ContinuationClassLoader(ClassLoader parent, Collection classpath) {
- this(parent,new BcelClassTransformer(),classpath);
+ * @param urls
+ * The URLs from which to load classes and resources
+ * @param parent
+ * The parent classloader to which unsatisfied loading
+ * attempts are delegated. May be <code>null</code>,
+ * in which case the {@link ClassLoader#getSystemClassLoader() system classloader}
+ * is used as the parent.
+ * @param transformer
+ * This transformer is used to perform the byte-code enhancement.
+ * May not be null.
+ */
+ public ContinuationClassLoader(URL[] urls, ClassLoader parent, ClassTransformer transformer) {
+ super(urls,fixNullParent(parent));
+ if(transformer==null)
+ throw new IllegalArgumentException();
+ this.transformer = transformer;
+ acc = AccessController.getContext();
}
- /**
- * Creates a classloader using the classpath given.
- *
- * @param parent The parent classloader to which unsatisfied loading
- * attempts are delegated. May be <code>null</code>,
- * in which case the classloader which loaded this
- * class is used as the parent.
- * @param classpath
- * a {@link Collection} of {@link File}s.
- * the classpath to use to load the classes.
- * May be <code>null</code>, in which case no path
- * elements are set up to start with.
- */
- public ContinuationClassLoader(ClassLoader parent, ClassTransformer transformer, Collection classpath) {
- this.transformer = transformer;
- if (parent != null) {
- setParent(parent);
- }
- if(classpath!=null) {
- for (Iterator itr = classpath.iterator(); itr.hasNext();) {
- File f = (File) itr.next();
- addPathFile(f);
- }
- }
+ public ContinuationClassLoader(URL[] urls, ClassLoader parent) {
+ this(urls,parent,new BcelClassTransformer());
}
- /**
- * Set the parent for this class loader. This is the class loader to which
- * this class loader will delegate to load classes
- *
- * @param parent the parent class loader.
- */
- public void setParent(ClassLoader parent) {
- if (parent == null) {
- this.parent = ContinuationClassLoader.class.getClassLoader();
+ private static ClassLoader fixNullParent(ClassLoader classLoader) {
+ if(classLoader!=null) {
+ return classLoader;
} else {
- this.parent = parent;
+ return getSystemClassLoader();
}
}
@@ -266,16 +135,6 @@
}
/**
- * Add a file to the path
- *
- * @param pathComponent the URL which is to be added to the path for
- * this class loader
- */
- protected synchronized void addPathFile(File pathComponent) {
- pathComponents.add(pathComponent);
- }
-
- /**
* Sets whether this classloader should run in isolated mode. In
* isolated mode, classes not found on the given classpath will
* not be referred to the parent class loader but will cause a
@@ -349,166 +208,6 @@
}
/**
- * Loads a class through this class loader but defer to the parent class
- * loader.
- *
- * This ensures that instances of the returned class will be compatible
- * with instances which have already been loaded on the parent
- * loader.
- *
- * @param classname The name of the class to be loaded.
- * Must not be <code>null</code>.
- *
- * @return the required Class object
- *
- * @exception ClassNotFoundException if the requested class does not exist
- * on this loader's classpath.
- */
- public Class forceLoadSystemClass(String classname)
- throws ClassNotFoundException {
- log.debug("force system loading " + classname);
-
- Class theClass = findLoadedClass(classname);
-
- if (theClass == null) {
- theClass = findBaseClass(classname);
- }
-
- return theClass;
- }
-
- /**
- * Returns a stream to read the requested resource name.
- *
- * @param name The name of the resource for which a stream is required.
- * Must not be <code>null</code>.
- *
- * @return a stream to the required resource or <code>null</code> if the
- * resource cannot be found on the loader's classpath.
- */
- public InputStream getResourceAsStream(String name) {
-
- InputStream resourceStream;
- if (isParentFirst(name)) {
- resourceStream = loadBaseResource(name);
- if (resourceStream != null) {
- log.debug("ResourceStream for " + name
- + " loaded from parent loader");
-
- } else {
- resourceStream = loadResource(name);
- if (resourceStream != null) {
- log.debug("ResourceStream for " + name
- + " loaded from ant loader");
- }
- }
- } else {
- resourceStream = loadResource(name);
- if (resourceStream != null) {
- log.debug("ResourceStream for " + name
- + " loaded from ant loader");
-
- } else {
- resourceStream = loadBaseResource(name);
- if (resourceStream != null) {
- log.debug("ResourceStream for " + name
- + " loaded from parent loader");
- }
- }
- }
-
- if (resourceStream == null) {
- log.debug("Couldn't load ResourceStream for " + name);
- }
-
- return resourceStream;
- }
-
- /**
- * Returns a stream to read the requested resource name from this loader.
- *
- * @param name The name of the resource for which a stream is required.
- * Must not be <code>null</code>.
- *
- * @return a stream to the required resource or <code>null</code> if
- * the resource cannot be found on the loader's classpath.
- */
- private synchronized InputStream loadResource(String name) {
- // we need to search the components of the path to see if we can
- // find the class we want.
- InputStream stream = null;
-
- for (Iterator itr = pathComponents.iterator(); itr.hasNext() && stream==null;) {
- File pathComponent = (File) itr.next();
- stream = getResourceStream(pathComponent, name);
- }
- return stream;
- }
-
- /**
- * Finds a system resource (which should be loaded from the parent
- * classloader).
- *
- * @param name The name of the system resource to load.
- * Must not be <code>null</code>.
- *
- * @return a stream to the named resource, or <code>null</code> if
- * the resource cannot be found.
- */
- private InputStream loadBaseResource(String name) {
- if (parent == null) {
- return getSystemResourceAsStream(name);
- } else {
- return parent.getResourceAsStream(name);
- }
- }
-
- /**
- * Returns an inputstream to a given resource in the given file which may
- * either be a directory or a zip file.
- *
- * @param file the file (directory or jar) in which to search for the
- * resource. Must not be <code>null</code>.
- * @param resourceName The name of the resource for which a stream is
- * required. Must not be <code>null</code>.
- *
- * @return a stream to the required resource or <code>null</code> if
- * the resource cannot be found in the given file.
- */
- private synchronized InputStream getResourceStream(File file, String resourceName) {
- try {
- if (!file.exists()) {
- return null;
- }
-
- if (file.isDirectory()) {
- File resource = new File(file, resourceName);
-
- if (resource.exists()) {
- return new FileInputStream(resource);
- }
- } else {
- // is the zip file in the cache
- ZipFile zipFile = (ZipFile) zipFiles.get(file);
- if (zipFile == null) {
- zipFile = new ZipFile(file);
- zipFiles.put(file, zipFile);
- }
- ZipEntry entry = zipFile.getEntry(resourceName);
- if (entry != null) {
- return zipFile.getInputStream(entry);
- }
- }
- } catch (Exception e) {
- log.debug("Ignoring Exception " + e.getClass().getName()
- + ": " + e.getMessage() + " reading resource " + resourceName
- + " from " + file);
- }
-
- return null;
- }
-
- /**
* Tests whether or not the parent classloader should be checked for
* a resource before this one. If the resource matches both the
* "use parent classloader first" and the "use this classloader first"
@@ -550,124 +249,6 @@
}
/**
- * 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.
- *
- * @param name The name of the resource for which a stream is required.
- * Must not be <code>null</code>.
- *
- * @return a URL for reading the resource, or <code>null</code> if the
- * resource could not be found or the caller doesn't have
- * adequate privileges to get the resource.
- */
- public synchronized URL getResource(String name) {
- // we need to search the components of the path to see if
- // we can find the class we want.
- URL url = null;
- if (isParentFirst(name)) {
- url = (parent == null) ? super.getResource(name)
- : parent.getResource(name);
- }
-
- if (url != null) {
- log.debug("Resource " + name + " loaded from parent loader");
-
- } else {
- // try and load from this loader if the parent either didn't find
- // it or wasn't consulted.
- for (Iterator itr = pathComponents.iterator(); itr.hasNext() && url==null;) {
- File pathComponent = (File) itr.next();
- url = getResourceURL(pathComponent, name);
- if (url != null) {
- log.debug("Resource " + name
- + " loaded from ant loader");
- }
- }
- }
-
- if (url == null && !isParentFirst(name)) {
- // this loader was first but it didn't find it - try the parent
-
- url = (parent == null) ? super.getResource(name)
- : parent.getResource(name);
- if (url != null) {
- log.debug("Resource " + name + " loaded from parent loader");
- }
- }
-
- if (url == null) {
- log.debug("Couldn't load Resource " + name);
- }
-
- return url;
- }
-
- /**
- * Returns an enumeration of URLs representing all the resources with the
- * given name by searching the class loader's classpath.
- *
- * @param name The resource name to search for.
- * Must not be <code>null</code>.
- * @return an enumeration of URLs for the resources
- */
- protected Enumeration findResources(String name) {
- return new ResourceEnumeration(name);
- }
-
- /**
- * Returns the URL of a given resource in the given file which may
- * either be a directory or a zip file.
- *
- * @param file The file (directory or jar) in which to search for
- * the resource. Must not be <code>null</code>.
- * @param resourceName The name of the resource for which a stream
- * is required. Must not be <code>null</code>.
- *
- * @return a stream to the required resource or <code>null</code> if the
- * resource cannot be found in the given file object.
- */
- protected synchronized URL getResourceURL(File file, String resourceName) {
- try {
- if (!file.exists()) {
- return null;
- }
-
- if (file.isDirectory()) {
- File resource = new File(file, resourceName);
-
- if (resource.exists()) {
- try {
- return resource.toURL();
- } catch (MalformedURLException ex) {
- return null;
- }
- }
- } else {
- ZipFile zipFile = (ZipFile) zipFiles.get(file);
- if (zipFile == null) {
- zipFile = new ZipFile(file);
- zipFiles.put(file, zipFile);
- }
-
- ZipEntry entry = zipFile.getEntry(resourceName);
- if (entry != null) {
- try {
- return new URL("jar:" + file.toURL()
- + "!/" + entry);
- } catch (MalformedURLException ex) {
- return null;
- }
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- return null;
- }
-
- /**
* Loads a class with this class loader.
*
* This class attempts to load the class in an order determined by whether
@@ -700,7 +281,7 @@
if (isParentFirst(classname)) {
try {
- theClass = findBaseClass(classname);
+ theClass = parent.loadClass(classname);
log.debug("Class " + classname + " loaded from parent loader "
+ "(parentFirst)");
} catch (ClassNotFoundException cnfe) {
@@ -716,7 +297,7 @@
if (ignoreBase) {
throw cnfe;
}
- theClass = findBaseClass(classname);
+ theClass = parent.loadClass(classname);
log.debug("Class " + classname + " loaded from parent loader");
}
}
@@ -729,33 +310,31 @@
}
/**
- * Converts the class dot notation to a filesystem equivalent for
- * searching purposes.
- *
- * @param classname The class name in dot format (eg java.lang.Integer).
- * Must not be <code>null</code>.
- *
- * @return the classname in filesystem format (eg java/lang/Integer.class)
- */
- private String getClassFilename(String classname) {
- return classname.replace('.', '/') + ".class";
- }
-
- /**
* Define a class given its bytes
*
- * @param container the container from which the class data has been read
- * may be a directory or a jar/zip file.
- *
* @param classData the bytecode data for the class
* @param classname the name of the class
*
* @return the Class instance created from the given data
*/
- protected Class defineClassFromData(File container, byte[] classData, String classname) {
- classData = transformer.transform(classData);
- ProtectionDomain domain = this.getClass().getProtectionDomain();
- return defineClass(classname,classData,0,classData.length,domain);
+ protected Class defineClassFromData(final byte[] classData, final String classname) {
+ return (Class)AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ // define a package if necessary.
+ int i = classname.lastIndexOf('.');
+ if (i>0) {
+ String packageName = classname.substring(0,i);
+ Package pkg = getPackage(packageName);
+ if(pkg==null) {
+ definePackage(packageName,null,null,null,null,null,null,null);
+ }
+ }
+
+ byte[] newData = transformer.transform(classData);
+ ProtectionDomain domain = this.getClass().getProtectionDomain();
+ return defineClass(classname,newData,0,newData.length,domain);
+ }
+ },acc);
}
/**
@@ -765,7 +344,6 @@
* Must not be <code>null</code>.
* @param classname The name of the class in the stream.
* Must not be <code>null</code>.
- * @param container the file or directory containing the class.
*
* @return the Class object read from the stream.
*
@@ -774,8 +352,7 @@
* @exception SecurityException if there is a security problem while
* reading the class from the stream.
*/
- private Class getClassFromStream(InputStream stream, String classname,
- File container)
+ private Class getClassFromStream(InputStream stream, String classname)
throws IOException, SecurityException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bytesRead;
@@ -786,7 +363,7 @@
}
byte[] classData = baos.toByteArray();
- return defineClassFromData(container, classData, classname);
+ return defineClassFromData(classData, classname);
}
/**
@@ -800,117 +377,52 @@
* @exception ClassNotFoundException if the requested class does not exist
* on this loader's classpath.
*/
- public Class findClass(String name) throws ClassNotFoundException {
+ public Class findClass(final String name) throws ClassNotFoundException {
log.debug("Finding class " + name);
- return findClassInComponents(name);
- }
-
- /**
- * Indicate if the given URL is in this loader's path
- *
- * @param component the URL which is to be checked
- *
- * @return true if the URL is in the class path
- */
- protected synchronized boolean isInPath(File component) {
- for (Iterator itr = pathComponents.iterator(); itr.hasNext();) {
- File pathComponent = (File) itr.next();
- if (pathComponent.equals(component)) {
- return true;
- }
- }
- return false;
- }
+ // locate the class file
+ String classFileName = name.replace('.', '/') + ".class";
+ InputStream stream = getResourceAsStream(classFileName);
+ if(stream==null)
+ throw new ClassNotFoundException(name);
- /**
- * Finds a class on the given classpath.
- *
- * @param name The name of the class to be loaded. Must not be
- * <code>null</code>.
- *
- * @return the required Class object
- *
- * @exception ClassNotFoundException if the requested class does not exist
- * on this loader's classpath.
- */
- private synchronized Class findClassInComponents(String name)
- throws ClassNotFoundException {
- // we need to search the components of the path to see if
- // we can find the class we want.
- InputStream stream = null;
- String classFilename = getClassFilename(name);
try {
- for (Iterator itr = pathComponents.iterator(); itr.hasNext();) {
- File pathComponent = (File) itr.next();
- try {
- stream = getResourceStream(pathComponent, classFilename);
- if (stream != null) {
- log.debug("Loaded from " + pathComponent + " " + classFilename);
- return getClassFromStream(stream, name, pathComponent);
- }
- } catch (SecurityException se) {
- throw se;
- } catch (IOException ioe) {
- // ioe.printStackTrace();
- log.debug("Exception reading component " + pathComponent
- + " (reason: " + ioe.getMessage() + ")");
- }
- }
-
- throw new ClassNotFoundException(name);
+ return getClassFromStream(stream, name);
+ } catch (IOException e) {
+ throw new ClassNotFoundException(name,e);
} finally {
try {
- if (stream != null) {
- stream.close();
- }
+ stream.close();
} catch (IOException e) {
- //ignore
+ // ignore
}
}
}
/**
- * Finds a system class (which should be loaded from the same classloader
- * as the Ant core).
- *
- * For JDK 1.1 compatibility, this uses the findSystemClass method if
- * no parent classloader has been specified.
+ * 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.
*
- * @param name The name of the class to be loaded.
+ * @param name The name of the resource for which a stream is required.
* Must not be <code>null</code>.
- *
- * @return the required Class object
- *
- * @exception ClassNotFoundException if the requested class does not exist
- * on this loader's classpath.
+ * @return a URL for reading the resource, or <code>null</code> if the
+ * resource could not be found or the caller doesn't have
+ * adequate privileges to get the resource.
*/
- private Class findBaseClass(String name) throws ClassNotFoundException {
- if (parent == null) {
- return findSystemClass(name);
- } else {
- return parent.loadClass(name);
+ public synchronized URL getResource(String name) {
+ // we need to search the components of the path to see if
+ // we can find the class we want.
+ if (isParentFirst(name)) {
+ return super.getResource(name);
}
- }
- protected void finalize() {
- cleanup();
- }
-
- /**
- * Cleans up any resources held by this classloader. Any open archive
- * files are closed.
- */
- public synchronized void cleanup() {
- for (Iterator itr = zipFiles.values().iterator(); itr.hasNext();) {
- ZipFile zipFile = (ZipFile) itr.next();
- try {
- zipFile.close();
- } catch (IOException ioe) {
- // ignore
- }
+ // try this class loader first, then parent
+ URL url = findResource(name);
+ if(url==null) {
+ url = parent.getResource(name);
}
- zipFiles = new HashMap();
+ return url;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org