|
|
@@ -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); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|