Browse Source

Include jars from the manifest's classpath into the classloader

PR:	6921


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@273881 13f79535-47bb-0310-9956-ffa450edef68
master
Conor MacNeill 22 years ago
parent
commit
a506341591
2 changed files with 209 additions and 30 deletions
  1. +55
    -12
      src/main/org/apache/tools/ant/AntClassLoader.java
  2. +154
    -18
      src/main/org/apache/tools/ant/loader/AntClassLoader2.java

+ 55
- 12
src/main/org/apache/tools/ant/AntClassLoader.java View File

@@ -390,6 +390,8 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
/**
* 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 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
}

/**
* 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 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
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 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
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 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
*
* @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 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
* 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.
*
@@ -1096,6 +1122,23 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
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 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
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) {
@@ -1173,7 +1216,7 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
*/
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) {
@@ -1248,10 +1291,10 @@ public class AntClassLoader extends ClassLoader implements BuildListener {
* here
*/
public void addJavaLibraries() {
Vector packages=JavaEnvUtils.getJrePackages();
Enumeration e=packages.elements();
while(e.hasMoreElements()) {
String packageName=(String)e.nextElement();
Vector packages = JavaEnvUtils.getJrePackages();
Enumeration e = packages.elements();
while (e.hasMoreElements()) {
String packageName = (String) e.nextElement();
addSystemPackageRoot(packageName);
}
}


+ 154
- 18
src/main/org/apache/tools/ant/loader/AntClassLoader2.java View File

@@ -55,6 +55,9 @@ package org.apache.tools.ant.loader;

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,17 +66,85 @@ import java.util.jar.Attributes;
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 {

definePackage(container, className);
definePackage(container, className);
return defineClass(className, classData, 0, classData.length,
Project.class.getProtectionDomain());
Project.class.getProtectionDomain());
}

/**
* 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 @@ public class AntClassLoader2 extends AntClassLoader {
}
// 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;
@@ -180,7 +250,73 @@ public class AntClassLoader2 extends AntClassLoader {
definePackage(packageName, specificationTitle, specificationVersion,
specificationVendor, implementationTitle,
implementationVersion, implementationVendor, sealBase);
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);
}
}
}
}
}


Loading…
Cancel
Save