Return-Path: Delivered-To: apmail-jakarta-ant-dev-archive@apache.org Received: (qmail 69866 invoked from network); 25 Jan 2003 15:03:24 -0000 Received: from exchange.sun.com (192.18.33.10) by daedalus.apache.org with SMTP; 25 Jan 2003 15:03:24 -0000 Received: (qmail 24018 invoked by uid 97); 25 Jan 2003 15:04:47 -0000 Delivered-To: qmlist-jakarta-archive-ant-dev@jakarta.apache.org Received: (qmail 23968 invoked by uid 97); 25 Jan 2003 15:04:46 -0000 Mailing-List: contact ant-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Ant Developers List" Reply-To: "Ant Developers List" Delivered-To: mailing list ant-dev@jakarta.apache.org Received: (qmail 23950 invoked by uid 97); 25 Jan 2003 15:04:45 -0000 X-Antivirus: nagoya (v4218 created Aug 14 2002) Date: 25 Jan 2003 15:03:16 -0000 Message-ID: <20030125150316.288.qmail@icarus.apache.org> From: conor@apache.org To: jakarta-ant-cvs@apache.org Subject: cvs commit: jakarta-ant/src/main/org/apache/tools/ant/loader AntClassLoader2.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N conor 2003/01/25 07:03:16 Modified: src/main/org/apache/tools/ant AntClassLoader.java src/main/org/apache/tools/ant/loader AntClassLoader2.java Log: Include jars from the manifest's classpath into the classloader PR: 6921 Revision Changes Path 1.65 +55 -12 jakarta-ant/src/main/org/apache/tools/ant/AntClassLoader.java Index: AntClassLoader.java =================================================================== RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/AntClassLoader.java,v retrieving revision 1.64 retrieving revision 1.65 diff -u -w -u -r1.64 -r1.65 --- AntClassLoader.java 24 Jan 2003 14:18:20 -0000 1.64 +++ AntClassLoader.java 25 Jan 2003 15:03:15 -0000 1.65 @@ -390,6 +390,8 @@ /** * 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) { @@ -400,9 +402,12 @@ } /** - * Control whether class ookup is delegated to the parent loader first + * 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; @@ -472,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); } @@ -965,12 +986,12 @@ if (isParentFirst(classname)) { try { theClass = findBaseClass(classname); - log("Class " + classname + " loaded from parent loader ( parentFirst )", - 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 ( parentFirst )", - Project.MSG_DEBUG); + log("Class " + classname + " loaded from ant loader " + + "(parentFirst)", Project.MSG_DEBUG); } } else { try { @@ -1015,6 +1036,10 @@ * * @param classData the bytecode data for the class * @param classname the name of the class + * + * @return the Class instance created from the given data + * + * @throws IOException if the class data cannot be read. */ protected Class defineClassFromData(File container, byte[] classData, String classname) throws IOException { @@ -1056,6 +1081,7 @@ * Must not be null. * @param classname The name of the class in the stream. * Must not be null. + * @param container the file or directory containing the class. * * @return the Class object read from the stream. * @@ -1096,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. @@ -1121,8 +1164,8 @@ try { stream = getResourceStream(pathComponent, classFilename); if (stream != null) { - log("Loaded from " + pathComponent + " " + classFilename, - Project.MSG_DEBUG ); + log("Loaded from " + pathComponent + " " + + classFilename, Project.MSG_DEBUG); return getClassFromStream(stream, name, pathComponent); } } catch (SecurityException se) { 1.2 +154 -18 jakarta-ant/src/main/org/apache/tools/ant/loader/AntClassLoader2.java Index: AntClassLoader2.java =================================================================== RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/loader/AntClassLoader2.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -w -u -r1.1 -r1.2 --- AntClassLoader2.java 24 Jan 2003 14:18:20 -0000 1.1 +++ AntClassLoader2.java 25 Jan 2003 15:03:16 -0000 1.2 @@ -55,6 +55,9 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.Project; import java.util.jar.Manifest; @@ -63,8 +66,40 @@ import java.util.jar.Attributes.Name; import java.net.URL; import java.net.MalformedURLException; - +import java.util.zip.ZipEntry; +import java.util.StringTokenizer; +import org.apache.tools.ant.util.FileUtils; + +/** + * An implementation of the AntClassLoader suitable for use on post JDK 1.1 + * platforms + * + * @author Conor MacNeill + */ public class AntClassLoader2 extends AntClassLoader { + /** Instance of a utility class to use for file operations. */ + private FileUtils fileUtils; + + /** + * Constructor + */ + public AntClassLoader2() { + fileUtils = FileUtils.newFileUtils(); + } + + /** + * 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 + * + * @throws IOException if the class data cannot be read. + */ protected Class defineClassFromData(File container, byte[] classData, String className) throws IOException { @@ -74,6 +109,42 @@ } + /** + * Get the manifest from the given jar, if it is indeed a jar and it has a + * manifest + * + * @param container the File from which a manifest is required. + * + * @return the jar's manifest or null is the container is not a jar or it + * has no manifest. + * + * @exception IOException if the manifest cannot be read. + */ + private Manifest getJarManifest(File container) throws IOException { + if (container.isDirectory()) { + return null; + } + JarFile jarFile = null; + try { + jarFile = new JarFile(container); + return jarFile.getManifest(); + } finally { + if (jarFile != null) { + jarFile.close(); + } + } + } + + /** + * Define the package information associated with a class. + * + * @param container the file containing the class definition. + * @param className the class name of for which the package information + * is to be determined. + * + * @exception IOException if the package information cannot be read from the + * container. + */ protected void definePackage(File container, String className) throws IOException { int classIndex = className.lastIndexOf('.'); @@ -88,27 +159,26 @@ } // define the package now - Manifest manifest = null; - if (!container.isDirectory()) { - JarFile jarFile = null; - try { - jarFile = new JarFile(container); - manifest = jarFile.getManifest(); - } finally { - if (jarFile != null) { - jarFile.close(); - } - } - } + Manifest manifest = getJarManifest(container); if (manifest == null) { - definePackage(packageName, null, null, null, null, null, null, null); + definePackage(packageName, null, null, null, null, null, + null, null); } else { definePackage(container, packageName, manifest); } } - protected void definePackage(File container, String packageName, Manifest manifest) { + /** + * Define the package information when the class comes from a + * jar with a manifest + * + * @param container the jar file containing the manifest + * @param packageName the name of the package being defined. + * @param manifest the jar's manifest + */ + protected void definePackage(File container, String packageName, + Manifest manifest) { String sectionName = packageName.replace('.', '/') + "/"; String specificationTitle = null; @@ -181,6 +251,72 @@ definePackage(packageName, specificationTitle, specificationVersion, specificationVendor, implementationTitle, implementationVersion, implementationVendor, sealBase); + } + + + /** + * Add a file to the path. This classloader reads the manifest, if + * available, and adds any additional class path jars specified in the + * manifest. + * + * @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 { + super.addPathFile(pathComponent); + + if (pathComponent.isDirectory()) { + return; + } + + String classpath = null; + JarFile jarFile = null; + InputStream manifestStream = null; + try { + jarFile = new JarFile(pathComponent); + manifestStream + = jarFile.getInputStream(new ZipEntry("META-INF/MANIFEST.MF")); + + if (manifestStream == null) { + return; + } + Reader manifestReader = new InputStreamReader(manifestStream); + org.apache.tools.ant.taskdefs.Manifest manifest + = new org.apache.tools.ant.taskdefs.Manifest(manifestReader); + classpath + = manifest.getMainSection().getAttributeValue("Class-Path"); + + } catch (org.apache.tools.ant.taskdefs.ManifestException e) { + // ignore + } finally { + if (manifestStream != null) { + manifestStream.close(); + } + if (jarFile != null) { + jarFile.close(); + } + } + + if (classpath != null) { + URL baseURL = fileUtils.getFileURL(pathComponent); + StringTokenizer st = new StringTokenizer(classpath); + while (st.hasMoreTokens()) { + String classpathElement = st.nextToken(); + URL libraryURL = new URL(baseURL, classpathElement); + if (!libraryURL.getProtocol().equals("file")) { + log("Skipping jar library " + classpathElement + + " since only relative URLs are supported by this" + + " loader", Project.MSG_VERBOSE); + continue; + } + File libraryFile = new File(libraryURL.getFile()); + if (libraryFile.exists() && !isInPath(libraryFile)) { + addPathFile(libraryFile); + } + } + } } } -- To unsubscribe, e-mail: For additional commands, e-mail: