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]