morgand 2003/01/26 18:45:31
Modified: grant/src/java/org/apache/tools/ant AntClassLoader.java
Log:
recent changes to the Ant classloader don't play well with the modified
AntClassLoader, so temporarily (?) replacing it with the HEAD Ant version
(1.65)
Revision Changes Path
1.5 +189 -85
jakarta-commons-sandbox/grant/src/java/org/apache/tools/ant/AntClassLoader.java
Index: AntClassLoader.java
===================================================================
RCS file:
/home/cvs/jakarta-commons-sandbox/grant/src/java/org/apache/tools/ant/AntClassLoader.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- AntClassLoader.java 28 Oct 2002 19:58:33 -0000 1.4
+++ AntClassLoader.java 27 Jan 2003 02:45:31 -0000 1.5
@@ -1,7 +1,7 @@
/*
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
+ * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,27 +51,26 @@
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
-
package org.apache.tools.ant;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.Enumeration;
-import java.util.Vector;
import java.util.Hashtable;
-import java.util.zip.ZipFile;
+import java.util.Vector;
import java.util.zip.ZipEntry;
-import java.io.File;
-import java.io.InputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.ByteArrayOutputStream;
-import java.net.URL;
-import java.net.MalformedURLException;
+import java.util.zip.ZipFile;
import org.apache.tools.ant.types.Path;
-import org.apache.tools.ant.util.LoaderUtils;
import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.LoaderUtils;
/**
* Used to load classes within ant with a different claspath from
@@ -82,7 +81,7 @@
*
* @author Conor MacNeill
* @author <a href="mailto:[EMAIL PROTECTED]">Jesse Glick</a>
- * @author <a href="mailto:[EMAIL PROTECTED]">Magesh Umasankar</a>
+ * @author Magesh Umasankar
*/
public class AntClassLoader extends ClassLoader implements BuildListener {
@@ -97,7 +96,6 @@
* @author <a href="mailto:[EMAIL PROTECTED]">David A. Herman</a>
*/
private class ResourceEnumeration implements Enumeration {
-
/**
* The name of the resource being searched for.
*/
@@ -268,6 +266,13 @@
/**
+ * Create an Ant Class Loader
+ */
+ public AntClassLoader() {
+ setParent(null);
+ }
+
+ /**
* Creates a classloader for the given project using the classpath given.
*
* @param project The project to which this classloader is to belong.
@@ -279,21 +284,9 @@
* elements are set up to start with.
*/
public AntClassLoader(Project project, Path classpath) {
- parent = AntClassLoader.class.getClassLoader();
- this.project = project;
- project.addBuildListener(this);
- if (classpath != null) {
- Path actualClasspath = classpath.concatSystemClasspath("ignore");
- String[] pathElements = actualClasspath.list();
- for (int i = 0; i < pathElements.length; ++i) {
- try {
- addPathElement(pathElements[i]);
- } catch (BuildException e) {
- // ignore path elements which are invalid
- // relative to the project
- }
- }
- }
+ setParent(null);
+ setProject(project);
+ setClassPath(classpath);
}
/**
@@ -316,16 +309,10 @@
boolean parentFirst) {
this(project, classpath);
if (parent != null) {
- this.parent = parent;
+ setParent(parent);
}
- this.parentFirst = parentFirst;
- //TODO: turn on
- //addJavaLibraries();
- addSystemPackageRoot("java");
- addSystemPackageRoot("javax");
- addSystemPackageRoot("org.xml.sax");
- addSystemPackageRoot("org.apache.xerces");
- addSystemPackageRoot("org.w3c.dom");
+ setParentFirst(parentFirst);
+ addJavaLibraries();
}
@@ -360,15 +347,73 @@
* load the a class through this loader.
*/
public AntClassLoader(ClassLoader parent, boolean parentFirst) {
- if (parent != null) {
- this.parent = parent;
+ setParent(parent);
+ project = null;
+ this.parentFirst = parentFirst;
+ }
+
+ /**
+ * Set the project associated with this class loader
+ *
+ * @param project the project instance
+ */
+ public void setProject(Project project) {
+ this.project = project;
+ if (project != null) {
+ project.addBuildListener(this);
+ }
+ }
+
+ /**
+ * Set the classpath to search for classes to load. This should not be
+ * changed once the classloader starts to server classes
+ *
+ * @param classpath the serahc classpath consisting of directories and
+ * jar/zip files.
+ */
+ public void setClassPath(Path classpath) {
+ pathComponents.removeAllElements();
+ if (classpath != null) {
+ Path actualClasspath = classpath.concatSystemClasspath("ignore");
+ String[] pathElements = actualClasspath.list();
+ for (int i = 0; i < pathElements.length; ++i) {
+ try {
+ addPathElement(pathElements[i]);
+ } catch (BuildException e) {
+ // ignore path elements which are invalid
+ // relative to the project
+ }
+ }
+ }
+ }
+
+ /**
+ * 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 = AntClassLoader.class.getClassLoader();
} else {
- parent = AntClassLoader.class.getClassLoader();
+ this.parent = parent;
}
- project = null;
+ }
+
+ /**
+ * Control whether class lookup is delegated to the parent loader first
+ * or after this loader. Use with extreme caution. Setting this to
+ * false violates the class loader hierarchy and can lead to Linkage errors
+ *
+ * @param parentFirst if true, delegate initial class search to the parent
+ * classloader.
+ */
+ public void setParentFirst(boolean parentFirst) {
this.parentFirst = parentFirst;
}
+
/**
* Logs a message through the project object if one has been provided.
*
@@ -397,7 +442,7 @@
if (LoaderUtils.isContextLoaderAvailable()) {
savedContextLoader = LoaderUtils.getContextClassLoader();
ClassLoader loader = this;
- if (project != null
+ if (project != null
&& "only".equals(project.getProperty("build.sysclasspath"))) {
loader = this.getClass().getClassLoader();
}
@@ -432,6 +477,22 @@
File pathComponent
= project != null ? project.resolveFile(pathElement)
: new File(pathElement);
+ try {
+ addPathFile(pathComponent);
+ } catch (IOException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Add a file to the path
+ *
+ * @param pathComponent the file which is to be added to the path for
+ * this class loader
+ *
+ * @throws IOException if data needed from the file cannot be read.
+ */
+ protected void addPathFile(File pathComponent) throws IOException {
pathComponents.addElement(pathComponent);
}
@@ -441,7 +502,7 @@
* @return the classpath used for this classloader, with elements
* separated by the path separator for the system.
*/
- public String getClasspath(){
+ public String getClasspath() {
StringBuffer sb = new StringBuffer();
boolean firstPass = true;
Enumeration enum = pathComponents.elements();
@@ -519,7 +580,8 @@
* Should not be <code>null</code>.
*/
public void addSystemPackageRoot(String packageRoot) {
- systemPackages.addElement(packageRoot + ".");
+ systemPackages.addElement(packageRoot
+ + (packageRoot.endsWith(".") ? "" : "."));
}
/**
@@ -532,7 +594,8 @@
* Should not be <code>null</code>.
*/
public void addLoaderPackageRoot(String packageRoot) {
- loaderPackages.addElement(packageRoot + ".");
+ loaderPackages.addElement(packageRoot
+ + (packageRoot.endsWith(".") ? "" : "."));
}
/**
@@ -838,7 +901,7 @@
}
/**
- * Returns an inputstream to a given resource in the given file which may
+ * 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
@@ -849,7 +912,7 @@
* @return a stream to the required resource or <code>null</code> if the
* resource cannot be found in the given file object.
*/
- private URL getResourceURL(File file, String resourceName) {
+ protected URL getResourceURL(File file, String resourceName) {
try {
if (!file.exists()) {
return null;
@@ -909,8 +972,11 @@
* on the system classpath (when not in isolated mode) or this loader's
* classpath.
*/
- protected Class loadClass(String classname, boolean resolve)
+ protected synchronized Class loadClass(String classname, boolean resolve)
throws ClassNotFoundException {
+ // 'sync' is needed - otherwise 2 threads can load the same class
+ // twice, resulting in LinkageError: duplicated class definition.
+ // findLoadedClass avoids that, but without sync it won't work.
Class theClass = findLoadedClass(classname);
if (theClass != null) {
@@ -920,12 +986,12 @@
if (isParentFirst(classname)) {
try {
theClass = findBaseClass(classname);
- log("Class " + classname + " loaded from parent loader",
- Project.MSG_DEBUG);
+ log("Class " + classname + " loaded from parent loader "
+ + "(parentFirst)", Project.MSG_DEBUG);
} catch (ClassNotFoundException cnfe) {
theClass = findClass(classname);
- log("Class " + classname + " loaded from ant loader",
- Project.MSG_DEBUG);
+ log("Class " + classname + " loaded from ant loader "
+ + "(parentFirst)", Project.MSG_DEBUG);
}
} else {
try {
@@ -963,32 +1029,20 @@
}
/**
- * Reads a class definition from a stream.
+ * Define a class given its bytes
*
- * @param stream The stream from which the class is to be read.
- * 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 container from which the class data has been read
+ * may be a directory or a jar/zip file.
*
- * @return the Class object read from the stream.
+ * @param classData the bytecode data for the class
+ * @param classname the name of the class
*
- * @exception IOException if there is a problem reading the class from the
- * stream.
- * @exception SecurityException if there is a security problem while
- * reading the class from the stream.
+ * @return the Class instance created from the given data
+ *
+ * @throws IOException if the class data cannot be read.
*/
- private Class getClassFromStream(InputStream stream, String classname)
- throws IOException, SecurityException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int bytesRead = -1;
- byte[] buffer = new byte[BUFFER_SIZE];
-
- while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) != -1) {
- baos.write(buffer, 0, bytesRead);
- }
-
- byte[] classData = baos.toByteArray();
-
+ protected Class defineClassFromData(File container, byte[] classData,
+ String classname) throws IOException {
// Simply put:
// defineClass(classname, classData, 0, classData.length,
// Project.class.getProtectionDomain());
@@ -1019,6 +1073,37 @@
return defineClass(classname, classData, 0, classData.length);
}
}
+
+ /**
+ * Reads a class definition from a stream.
+ *
+ * @param stream The stream from which the class is to be read.
+ * 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.
+ *
+ * @exception IOException if there is a problem reading the class from the
+ * stream.
+ * @exception SecurityException if there is a security problem while
+ * reading the class from the stream.
+ */
+ private Class getClassFromStream(InputStream stream, String classname,
+ File container)
+ throws IOException, SecurityException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ int bytesRead = -1;
+ byte[] buffer = new byte[BUFFER_SIZE];
+
+ while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) != -1) {
+ baos.write(buffer, 0, bytesRead);
+ }
+
+ byte[] classData = baos.toByteArray();
+ return defineClassFromData(container, classData, classname);
+ }
/**
* Searches for and load a class on the classpath of this class loader.
@@ -1037,6 +1122,23 @@
return findClassInComponents(name);
}
+ /**
+ * Indicate if the given file is in this loader's path
+ *
+ * @param component the file which is to be checked
+ *
+ * @return true if the file is in the class path
+ */
+ protected boolean isInPath(File component) {
+ for (Enumeration e = pathComponents.elements(); e.hasMoreElements();) {
+ File pathComponent = (File) e.nextElement();
+ if (pathComponent.equals(component)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Finds a class on the given classpath.
@@ -1062,7 +1164,9 @@
try {
stream = getResourceStream(pathComponent, classFilename);
if (stream != null) {
- return getClassFromStream(stream, name);
+ log("Loaded from " + pathComponent + " "
+ + classFilename, Project.MSG_DEBUG);
+ return getClassFromStream(stream, name, pathComponent);
}
} catch (SecurityException se) {
throw se;
@@ -1112,7 +1216,7 @@
*/
public synchronized void cleanup() {
for (Enumeration e = zipFiles.elements(); e.hasMoreElements();) {
- ZipFile zipFile = (ZipFile)e.nextElement();
+ ZipFile zipFile = (ZipFile) e.nextElement();
try {
zipFile.close();
} catch (IOException ioe) {
@@ -1181,18 +1285,18 @@
*/
public void messageLogged(BuildEvent event) {
}
-
+
/**
* add any libraries that come with different java versions
* here
*/
- private void addJavaLibraries() {
- Vector packages=JavaEnvUtils.getJrePackages();
- Enumeration e=packages.elements();
- while(e.hasMoreElements()) {
- String packageName=(String)e.nextElement();
+ public void addJavaLibraries() {
+ Vector packages = JavaEnvUtils.getJrePackages();
+ Enumeration e = packages.elements();
+ while (e.hasMoreElements()) {
+ String packageName = (String) e.nextElement();
addSystemPackageRoot(packageName);
}
}
-
+
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>