You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by co...@apache.org on 2003/01/25 16:03:16 UTC
cvs commit: jakarta-ant/src/main/org/apache/tools/ant/loader AntClassLoader2.java
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 <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 @@
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: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>