jglick 2005/03/29 11:56:15 Modified: src/main/org/apache/tools/ant AntClassLoader.java Project.java src/main/org/apache/tools/ant/loader AntClassLoader2.java Log: #27285: simplify AntClassLoader by removing reflection hacks (and separate ACL2) only needed for JDK 1.1 support. Revision Changes Path 1.93 +226 -59 ant/src/main/org/apache/tools/ant/AntClassLoader.java Index: AntClassLoader.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/AntClassLoader.java,v retrieving revision 1.92 retrieving revision 1.93 diff -u -r1.92 -r1.93 --- AntClassLoader.java 14 Mar 2005 09:19:27 -0000 1.92 +++ AntClassLoader.java 29 Mar 2005 19:56:15 -0000 1.93 @@ -14,6 +14,7 @@ * limitations under the License. * */ + package org.apache.tools.ant; import java.io.ByteArrayOutputStream; @@ -21,14 +22,22 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; import java.util.Enumeration; +import java.util.HashMap; import java.util.Hashtable; +import java.util.Map; +import java.util.StringTokenizer; import java.util.Vector; +import java.util.jar.Attributes; +import java.util.jar.Attributes.Name; +import java.util.jar.JarFile; +import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.tools.ant.types.Path; @@ -192,6 +201,9 @@ */ private Hashtable zipFiles = new Hashtable(); + /** Static map of jar file/time to manifiest class-path entries */ + private static Map/*<String,String>*/ pathMap = Collections.synchronizedMap(new HashMap()); + /** * The context loader saved when setting the thread's current * context loader. @@ -203,36 +215,6 @@ private boolean isContextLoaderSaved = false; /** - * Reflection method reference for getProtectionDomain; - * used to avoid 1.1-compatibility problems. - */ - private static Method getProtectionDomain = null; - - /** - * Reflection method reference for defineClassProtectionDomain; - * used to avoid 1.1-compatibility problems. - */ - private static Method defineClassProtectionDomain = null; - - - // Set up the reflection-based Java2 methods if possible - static { - try { - getProtectionDomain - = Class.class.getMethod("getProtectionDomain", new Class[0]); - Class protectionDomain - = Class.forName("java.security.ProtectionDomain"); - Class[] args = new Class[] {String.class, byte[].class, - Integer.TYPE, Integer.TYPE, protectionDomain}; - defineClassProtectionDomain - = ClassLoader.class.getDeclaredMethod("defineClass", args); - } catch (Exception e) { - // ignore failure to get access to 1.2+ methods - } - } - - - /** * Create an Ant Class Loader */ public AntClassLoader() { @@ -452,7 +434,9 @@ } /** - * Add a file to the path + * Add a file to the path. + * 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 @@ -461,6 +445,66 @@ */ protected void addPathFile(File pathComponent) throws IOException { pathComponents.addElement(pathComponent); + if (pathComponent.isDirectory()) { + return; + } + + String absPathPlusTimeAndLength = + pathComponent.getAbsolutePath() + pathComponent.lastModified() + "-" + + pathComponent.length(); + String classpath = (String) pathMap.get(absPathPlusTimeAndLength); + if (classpath == null) { + ZipFile jarFile = null; + InputStream manifestStream = null; + try { + jarFile = new ZipFile(pathComponent); + manifestStream + = jarFile.getInputStream(new ZipEntry("META-INF/MANIFEST.MF")); + + if (manifestStream == null) { + return; + } + Reader manifestReader + = new InputStreamReader(manifestStream, "UTF-8"); + 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) { + classpath = ""; + } + pathMap.put(absPathPlusTimeAndLength, classpath); + } + + if (!"".equals(classpath)) { + URL baseURL = FILE_UTILS.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); + } + } + } } /** @@ -1029,37 +1073,160 @@ */ protected Class defineClassFromData(File container, byte[] classData, String classname) throws IOException { - // Simply put: - // defineClass(classname, classData, 0, classData.length, - // Project.class.getProtectionDomain()); - // Made more elaborate to be 1.1-safe. - if (defineClassProtectionDomain != null) { + definePackage(container, classname); + // XXX should instead make a new ProtectionDomain with a CodeSource + // corresponding to container.toURI().toURL() and the same + // PermissionCollection as Project.class.protectionDomain had + return defineClass(classname, classData, 0, classData.length, + Project.class.getProtectionDomain()); + } + + /** + * 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('.'); + if (classIndex == -1) { + return; + } + + String packageName = className.substring(0, classIndex); + if (getPackage(packageName) != null) { + // already defined + return; + } + + // define the package now + Manifest manifest = getJarManifest(container); + + if (manifest == null) { + definePackage(packageName, null, null, null, null, null, + null, null); + } else { + definePackage(container, packageName, manifest); + } + } + + /** + * 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 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; + String specificationVendor = null; + String specificationVersion = null; + String implementationTitle = null; + String implementationVendor = null; + String implementationVersion = null; + String sealedString = null; + URL sealBase = null; + + Attributes sectionAttributes = manifest.getAttributes(sectionName); + if (sectionAttributes != null) { + specificationTitle + = sectionAttributes.getValue(Name.SPECIFICATION_TITLE); + specificationVendor + = sectionAttributes.getValue(Name.SPECIFICATION_VENDOR); + specificationVersion + = sectionAttributes.getValue(Name.SPECIFICATION_VERSION); + implementationTitle + = sectionAttributes.getValue(Name.IMPLEMENTATION_TITLE); + implementationVendor + = sectionAttributes.getValue(Name.IMPLEMENTATION_VENDOR); + implementationVersion + = sectionAttributes.getValue(Name.IMPLEMENTATION_VERSION); + sealedString + = sectionAttributes.getValue(Name.SEALED); + } + + Attributes mainAttributes = manifest.getMainAttributes(); + if (mainAttributes != null) { + if (specificationTitle == null) { + specificationTitle + = mainAttributes.getValue(Name.SPECIFICATION_TITLE); + } + if (specificationVendor == null) { + specificationVendor + = mainAttributes.getValue(Name.SPECIFICATION_VENDOR); + } + if (specificationVersion == null) { + specificationVersion + = mainAttributes.getValue(Name.SPECIFICATION_VERSION); + } + if (implementationTitle == null) { + implementationTitle + = mainAttributes.getValue(Name.IMPLEMENTATION_TITLE); + } + if (implementationVendor == null) { + implementationVendor + = mainAttributes.getValue(Name.IMPLEMENTATION_VENDOR); + } + if (implementationVersion == null) { + implementationVersion + = mainAttributes.getValue(Name.IMPLEMENTATION_VERSION); + } + if (sealedString == null) { + sealedString + = mainAttributes.getValue(Name.SEALED); + } + } + + if (sealedString != null && sealedString.equalsIgnoreCase("true")) { try { - Object domain - = getProtectionDomain.invoke(Project.class, new Object[0]); - Object[] args - = new Object[] {classname, classData, new Integer(0), - new Integer(classData.length), domain}; - return (Class) defineClassProtectionDomain.invoke(this, args); - } catch (InvocationTargetException ite) { - Throwable t = ite.getTargetException(); - if (t instanceof ClassFormatError) { - throw (ClassFormatError) t; - } else if (t instanceof NoClassDefFoundError) { - throw (NoClassDefFoundError) t; - } else if (t instanceof SecurityException) { - throw (SecurityException) t; - } else { - throw new IOException(t.toString()); - } - } catch (Exception e) { - throw new IOException(e.toString()); + // XXX should be using FileUtils! + sealBase = new URL("file:" + container.getPath()); + } catch (MalformedURLException e) { + // ignore } - } else { - return defineClass(classname, classData, 0, classData.length); } + + definePackage(packageName, specificationTitle, specificationVersion, + specificationVendor, implementationTitle, + implementationVersion, implementationVendor, sealBase); } + /** * Reads a class definition from a stream. * 1.189 +1 -4 ant/src/main/org/apache/tools/ant/Project.java Index: Project.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Project.java,v retrieving revision 1.188 retrieving revision 1.189 diff -u -r1.188 -r1.189 --- Project.java 9 Mar 2005 00:20:42 -0000 1.188 +++ Project.java 29 Mar 2005 19:56:15 -0000 1.189 @@ -33,7 +33,6 @@ import java.util.HashSet; import org.apache.tools.ant.input.DefaultInputHandler; import org.apache.tools.ant.input.InputHandler; -import org.apache.tools.ant.loader.AntClassLoader2; import org.apache.tools.ant.helper.DefaultExecutor; import org.apache.tools.ant.helper.KeepGoingExecutor; import org.apache.tools.ant.types.FilterSet; @@ -44,7 +43,6 @@ import org.apache.tools.ant.util.JavaEnvUtils; import org.apache.tools.ant.util.StringUtils; - /** * Central representation of an Ant project. This class defines an * Ant project with all of its targets, tasks and various other @@ -56,7 +54,6 @@ * file paths at runtime. * */ - public class Project { /** Message priority of "error". */ public static final int MSG_ERR = 0; @@ -270,7 +267,7 @@ * @return an appropriate classloader. */ public AntClassLoader createClassLoader(Path path) { - AntClassLoader loader = new AntClassLoader2(); + AntClassLoader loader = new AntClassLoader(); loader.setProject(this); loader.setClassPath(path); return loader; 1.14 +3 -276 ant/src/main/org/apache/tools/ant/loader/AntClassLoader2.java Index: AntClassLoader2.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/loader/AntClassLoader2.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- AntClassLoader2.java 6 Jan 2005 12:05:10 -0000 1.13 +++ AntClassLoader2.java 29 Mar 2005 19:56:15 -0000 1.14 @@ -14,287 +14,14 @@ * limitations under the License. * */ + 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; -import java.util.jar.JarFile; -import java.util.zip.ZipFile; -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.Collections; -import java.util.HashMap; -import java.util.Map; -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 - * + * @deprecated Just use [EMAIL PROTECTED] AntClassLoader} itself. */ public class AntClassLoader2 extends AntClassLoader { - /** Instance of a utility class to use for file operations. */ - private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); - - /** Static map of jar file/time to manifiest class-path entries */ - private static Map pathMap = Collections.synchronizedMap(new HashMap()); - - /** - * Constructor - */ - public AntClassLoader2() { - } - - /** - * 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); - return defineClass(className, classData, 0, classData.length, - 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('.'); - if (classIndex == -1) { - return; - } - - String packageName = className.substring(0, classIndex); - if (getPackage(packageName) != null) { - // already defined - return; - } - - // define the package now - Manifest manifest = getJarManifest(container); - - if (manifest == null) { - definePackage(packageName, null, null, null, null, null, - null, null); - } else { - definePackage(container, packageName, 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; - String specificationVendor = null; - String specificationVersion = null; - String implementationTitle = null; - String implementationVendor = null; - String implementationVersion = null; - String sealedString = null; - URL sealBase = null; - - Attributes sectionAttributes = manifest.getAttributes(sectionName); - if (sectionAttributes != null) { - specificationTitle - = sectionAttributes.getValue(Name.SPECIFICATION_TITLE); - specificationVendor - = sectionAttributes.getValue(Name.SPECIFICATION_VENDOR); - specificationVersion - = sectionAttributes.getValue(Name.SPECIFICATION_VERSION); - implementationTitle - = sectionAttributes.getValue(Name.IMPLEMENTATION_TITLE); - implementationVendor - = sectionAttributes.getValue(Name.IMPLEMENTATION_VENDOR); - implementationVersion - = sectionAttributes.getValue(Name.IMPLEMENTATION_VERSION); - sealedString - = sectionAttributes.getValue(Name.SEALED); - } - - Attributes mainAttributes = manifest.getMainAttributes(); - if (mainAttributes != null) { - if (specificationTitle == null) { - specificationTitle - = mainAttributes.getValue(Name.SPECIFICATION_TITLE); - } - if (specificationVendor == null) { - specificationVendor - = mainAttributes.getValue(Name.SPECIFICATION_VENDOR); - } - if (specificationVersion == null) { - specificationVersion - = mainAttributes.getValue(Name.SPECIFICATION_VERSION); - } - if (implementationTitle == null) { - implementationTitle - = mainAttributes.getValue(Name.IMPLEMENTATION_TITLE); - } - if (implementationVendor == null) { - implementationVendor - = mainAttributes.getValue(Name.IMPLEMENTATION_VENDOR); - } - if (implementationVersion == null) { - implementationVersion - = mainAttributes.getValue(Name.IMPLEMENTATION_VERSION); - } - if (sealedString == null) { - sealedString - = mainAttributes.getValue(Name.SEALED); - } - } - - if (sealedString != null && sealedString.equalsIgnoreCase("true")) { - try { - sealBase = new URL("file:" + container.getPath()); - } catch (MalformedURLException e) { - // ignore - } - } - - 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 absPathPlusTimeAndLength = - pathComponent.getAbsolutePath() + pathComponent.lastModified() + "-" - + pathComponent.length(); - String classpath = (String) pathMap.get(absPathPlusTimeAndLength); - if (classpath == null) { - ZipFile jarFile = null; - InputStream manifestStream = null; - try { - jarFile = new ZipFile(pathComponent); - manifestStream - = jarFile.getInputStream(new ZipEntry("META-INF/MANIFEST.MF")); - - if (manifestStream == null) { - return; - } - Reader manifestReader - = new InputStreamReader(manifestStream, "UTF-8"); - 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) { - classpath = ""; - } - pathMap.put(absPathPlusTimeAndLength, classpath); - } - - if (!"".equals(classpath)) { - URL baseURL = FILE_UTILS.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); - } - } - } - } + public AntClassLoader2() {} } -
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]