bodewig 2004/04/23 03:03:50 Modified: . build.xml src/main/org/apache/tools/ant/taskdefs Jar.java Java.java Added: src/testcases/org/apache/tools/ant/taskdefs ProtectedJarMethodsTest.java Log: Implement jar index for referenced jars, PR: 14255 Revision Changes Path 1.417 +2 -0 ant/build.xml Index: build.xml =================================================================== RCS file: /home/cvs/ant/build.xml,v retrieving revision 1.416 retrieving revision 1.417 diff -u -r1.416 -r1.417 --- build.xml 15 Apr 2004 13:53:47 -0000 1.416 +++ build.xml 23 Apr 2004 10:03:49 -0000 1.417 @@ -1551,6 +1551,8 @@ unless="tests.and.ant.share.classloader"/> <exclude name="${ant.package}/taskdefs/ProcessDestroyerTest.java" unless="tests.and.ant.share.classloader"/> + <exclude name="${ant.package}/taskdefs/ProtectedJarMethodsTest.java" + unless="tests.and.ant.share.classloader"/> <!-- can only run if cvs is installed on your machine enable by setting the property have.cvs 1.86 +201 -27 ant/src/main/org/apache/tools/ant/taskdefs/Jar.java Index: Jar.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Jar.java,v retrieving revision 1.85 retrieving revision 1.86 diff -u -r1.85 -r1.86 --- Jar.java 9 Mar 2004 16:48:05 -0000 1.85 +++ Jar.java 23 Apr 2004 10:03:49 -0000 1.86 @@ -29,7 +29,15 @@ import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; +import java.util.TreeMap; import java.util.Vector; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -37,10 +45,10 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.ZipFileSet; import org.apache.tools.zip.ZipOutputStream; - /** * Creates a JAR archive. * @@ -115,6 +123,13 @@ */ private Vector rootEntries; + /** + * Path containing jars that shall be indexed in addition to this archive. + * + * @since Ant 1.7 + */ + private Path indexJars; + /** constructor */ public Jar() { super(); @@ -304,6 +319,16 @@ super.addFileset(fs); } + /** + * @since Ant 1.7 + */ + public void addConfiguredIndexJars(Path p) { + if (indexJars == null) { + indexJars = new Path(getProject()); + } + indexJars.append(p); + } + protected void initZipOutputStream(ZipOutputStream zOut) throws IOException, BuildException { @@ -384,7 +409,7 @@ /** * Create the index list to speed up classloading. * This is a JDK 1.3+ specific feature and is enabled by default. See - * <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR+Index"> + * <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index"> * the JAR index specification</a> for more details. * * @param zOut the zip stream representing the jar being built. @@ -404,34 +429,38 @@ // header newline writer.println(zipFile.getName()); - // JarIndex is sorting the directories by ascending order. - // it's painful to do in JDK 1.1 and it has no value but cosmetic - // since it will be read into a hashtable by the classloader. - Enumeration e = addedDirs.keys(); - while (e.hasMoreElements()) { - String dir = (String) e.nextElement(); + writeIndexLikeList(new ArrayList(addedDirs.keySet()), + rootEntries, writer); + writer.println(); - // try to be smart, not to be fooled by a weird directory name - // @fixme do we need to check for directories starting by ./ ? - dir = dir.replace('\\', '/'); - int pos = dir.lastIndexOf('/'); - if (pos != -1) { - dir = dir.substring(0, pos); + if (indexJars != null) { + Manifest mf = createManifest(); + Manifest.Attribute classpath = + mf.getMainSection().getAttribute(Manifest.ATTRIBUTE_CLASSPATH); + String[] cpEntries = null; + if (classpath != null) { + StringTokenizer tok = new StringTokenizer(classpath.getValue(), + " "); + cpEntries = new String[tok.countTokens()]; + int c = 0; + while (tok.hasMoreTokens()) { + cpEntries[c++] = tok.nextToken(); + } } - - // looks like nothing from META-INF should be added - // and the check is not case insensitive. - // see sun.misc.JarIndex - if (dir.startsWith("META-INF")) { - continue; + String[] indexJarEntries = indexJars.list(); + for (int i = 0; i < indexJarEntries.length; i++) { + String name = findJarName(indexJarEntries[i], cpEntries); + if (name != null) { + ArrayList dirs = new ArrayList(); + ArrayList files = new ArrayList(); + grabFilesAndDirs(indexJarEntries[i], dirs, files); + if (dirs.size() + files.size() > 0) { + writer.println(name); + writeIndexLikeList(dirs, files, writer); + writer.println(); + } + } } - // name newline - writer.println(dir); - } - - e = rootEntries.elements(); - while (e.hasMoreElements()) { - writer.println(e.nextElement()); } writer.flush(); @@ -670,6 +699,151 @@ public static class FilesetManifestConfig extends EnumeratedAttribute { public String[] getValues() { return new String[] {"skip", "merge", "mergewithoutmain"}; + } + } + + /** + * Writes the directory entries from the first and the filenames + * from the second list to the given writer, one entry per line. + * + * @since Ant 1.7 + */ + protected final void writeIndexLikeList(List dirs, List files, + PrintWriter writer) + throws IOException { + // JarIndex is sorting the directories by ascending order. + // it has no value but cosmetic since it will be read into a + // hashtable by the classloader, but we'll do so anyway. + Collections.sort(dirs); + Collections.sort(files); + Iterator iter = dirs.iterator(); + while (iter.hasNext()) { + String dir = (String) iter.next(); + + // try to be smart, not to be fooled by a weird directory name + dir = dir.replace('\\', '/'); + if (dir.startsWith("./")) { + dir = dir.substring(2); + } + while (dir.startsWith("/")) { + dir = dir.substring(1); + } + int pos = dir.lastIndexOf('/'); + if (pos != -1) { + dir = dir.substring(0, pos); + } + + // looks like nothing from META-INF should be added + // and the check is not case insensitive. + // see sun.misc.JarIndex + if (dir.startsWith("META-INF")) { + continue; + } + // name newline + writer.println(dir); + } + + iter = files.iterator(); + while (iter.hasNext()) { + writer.println(iter.next()); + } + } + + /** + * try to guess the name of the given file. + * + * <p>If this jar has a classpath attribute in its manifest, we + * can assume that it will only require an index of jars listed + * there. try to find which classpath entry is most likely the + * one the given file name points to.</p> + * + * <p>In the absence of a classpath attribute, assume the other + * files will be placed inside the same directory as this jar and + * use their basename.</p> + * + * <p>if there is a classpath and the given file doesn't match any + * of its entries, return null.</p> + * + * @since Ant 1.7 + */ + protected static final String findJarName(String fileName, + String[] classpath) { + if (classpath == null) { + return (new File(fileName)).getName(); + } + fileName = fileName.replace(File.separatorChar, '/'); + TreeMap matches = new TreeMap(new Comparator() { + // longest match comes first + public int compare(Object o1, Object o2) { + if (o1 instanceof String && o2 instanceof String) { + return ((String) o2).length() + - ((String) o1).length(); + } + return 0; + } + }); + + for (int i = 0; i < classpath.length; i++) { + if (fileName.endsWith(classpath[i])) { + matches.put(classpath[i], classpath[i]); + } else { + int slash = classpath[i].indexOf("/"); + String candidate = classpath[i]; + while (slash > -1) { + candidate = candidate.substring(slash + 1); + if (fileName.endsWith(candidate)) { + matches.put(candidate, classpath[i]); + break; + } + slash = candidate.indexOf("/"); + } + } + } + + return matches.size() == 0 + ? null : (String) matches.get(matches.firstKey()); + } + + /** + * Grab lists of all root-level files and all directories + * contained in the given archive. + * + * @since Ant 1.7 + */ + protected static final void grabFilesAndDirs(String file, List dirs, + List files) + throws IOException { + org.apache.tools.zip.ZipFile zf = null; + try { + zf = new org.apache.tools.zip.ZipFile(file, "utf-8"); + Enumeration entries = zf.getEntries(); + HashSet dirSet = new HashSet(); + while (entries.hasMoreElements()) { + org.apache.tools.zip.ZipEntry ze = + (org.apache.tools.zip.ZipEntry) entries.nextElement(); + String name = ze.getName(); + // META-INF would be skipped anyway, avoid index for + // manifest-only jars. + if (!name.startsWith("META-INF/")) { + if (ze.isDirectory()) { + dirSet.add(name); + } else if (name.indexOf("/") == -1) { + files.add(name); + } else { + // a file, not in the root + // since the jar may be one without directory + // entries, add the parent dir of this file as + // well. + dirSet.add(name.substring(0, + name.lastIndexOf("/") + 1)); + } + } + } + dirs.addAll(dirSet); + } finally { + if (zf != null) { + zf.close(); + } } } } 1.93 +1 -0 ant/src/main/org/apache/tools/ant/taskdefs/Java.java Index: Java.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Java.java,v retrieving revision 1.92 retrieving revision 1.93 diff -u -r1.92 -r1.93 --- Java.java 23 Apr 2004 07:33:51 -0000 1.92 +++ Java.java 23 Apr 2004 10:03:49 -0000 1.93 @@ -417,6 +417,7 @@ failOnError = fail; incompatibleWithSpawn |= fail; } + /** * The working directory of the process * 1.1 ant/src/testcases/org/apache/tools/ant/taskdefs/ProtectedJarMethodsTest.java Index: ProtectedJarMethodsTest.java =================================================================== /* * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.taskdefs; import java.io.File; import java.io.IOException; import java.util.ArrayList; import org.apache.tools.ant.BuildFileTest; /** */ public class ProtectedJarMethodsTest extends BuildFileTest { private static String tempJar = "tmp.jar"; public ProtectedJarMethodsTest(String name) { super(name); } public void setUp() { configureProject("src/etc/testcases/taskdefs/jar.xml"); } public void tearDown() { executeTarget("cleanup"); } public void testGrabFilesAndDirs() throws IOException { executeTarget("testIndexTests"); String archive = getProject().resolveFile(tempJar).getAbsolutePath(); ArrayList dirs = new ArrayList(); ArrayList files = new ArrayList(); String[] expectedDirs = new String[] { "sub/", }; String[] expectedFiles = new String[] { "foo", }; Jar.grabFilesAndDirs(archive, dirs, files); assertEquals(expectedDirs.length, dirs.size()); for (int i = 0; i < expectedDirs.length; i++) { assertTrue("Found " + expectedDirs[i], dirs.contains(expectedDirs[i])); } assertEquals(expectedFiles.length, files.size()); for (int i = 0; i < expectedFiles.length; i++) { assertTrue("Found " + expectedFiles[i], files.contains(expectedFiles[i])); } } public void testFindJarNameNoClasspath() { assertEquals("foo", Jar.findJarName("foo", null)); assertEquals("foo", Jar.findJarName("lib" + File.separatorChar + "foo", null)); } public void testFindJarNameNoMatch() { assertNull(Jar.findJarName("foo", new String[] {"bar"})); } public void testFindJarNameSimpleMatches() { assertEquals("foo", Jar.findJarName("foo", new String[] {"foo"})); assertEquals("lib/foo", Jar.findJarName("foo", new String[] {"lib/foo"})); assertEquals("foo", Jar.findJarName("bar" + File.separatorChar + "foo", new String[] {"foo"})); assertEquals("lib/foo", Jar.findJarName("bar" + File.separatorChar + "foo", new String[] {"lib/foo"})); } public void testFindJarNameLongestMatchWins() { assertEquals("lib/foo", Jar.findJarName("lib/foo", new String[] {"foo", "lib/foo", "lib/bar/foo"})); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]