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

Reply via email to