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]>