diff --git a/src/main/org/apache/tools/ant/taskdefs/Jar.java b/src/main/org/apache/tools/ant/taskdefs/Jar.java index bce6c5c66..54d7aa199 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Jar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Jar.java @@ -60,14 +60,9 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.types.ZipFileSet; import org.apache.tools.zip.ZipOutputStream; -import java.io.IOException; -import java.io.File; -import java.io.InputStream; -import java.io.FileInputStream; -import java.io.ByteArrayOutputStream; -import java.io.PrintWriter; -import java.io.ByteArrayInputStream; +import java.io.*; import java.util.Enumeration; +import java.util.Vector; /** * Creates a JAR archive. @@ -75,6 +70,8 @@ import java.util.Enumeration; * @author James Davidson duncan@x180.com */ public class Jar extends Zip { + /** The index file name. */ + private final static String INDEX_NAME = "META-INF/INDEX.LIST"; private File manifestFile; private Manifest manifest; @@ -82,7 +79,11 @@ public class Jar extends Zip { /** true if a manifest has been specified in the task */ private boolean buildFileManifest = false; - + + /** jar index is JDK 1.3+ only */ + private boolean index = false; + + /** constructor */ public Jar() { super(); archiveType = "jar"; @@ -90,11 +91,22 @@ public class Jar extends Zip { setEncoding("UTF8"); } + /** + * @deprecated use setFile(File) instead. + */ public void setJarfile(File jarFile) { log("DEPRECATED - The jarfile attribute is deprecated. Use file attribute instead."); setFile(jarFile); } + /** + * Set whether or not to create an index list for classes + * to speed up classloading. + */ + public void setIndex(boolean flag){ + index = flag; + } + public void addConfiguredManifest(Manifest newManifest) throws ManifestException { if (manifest == null) { manifest = getDefaultManifest(); @@ -174,7 +186,67 @@ public class Jar extends Zip { throw new BuildException("Invalid Manifest", e, getLocation()); } } - + + protected void finalizeZipOutputStream(ZipOutputStream zOut) + throws IOException, BuildException { + if (index) { + createIndexList(zOut); + } + } + + /** + * Create the index list to speed up classloading. + * This is a JDK 1.3+ specific feature and is enabled by default. + * {@link http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index} + * @param zOut the zip stream representing the jar being built. + * @throws IOException thrown if there is an error while creating the + * index and adding it to the zip stream. + */ + private void createIndexList(ZipOutputStream zOut) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // encoding must be UTF8 as specified in the specs. + PrintWriter writer = new PrintWriter(new OutputStreamWriter(baos, "UTF8")); + + // version-info blankline + writer.println("JarIndex-Version: 1.0"); + writer.println(); + + // 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 enum = addedDirs.keys(); + while (enum.hasMoreElements()) { + String dir = (String)enum.nextElement(); + + // 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); + } + + // 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); + } + + writer.flush(); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + super.zipFile(bais, zOut, INDEX_NAME, System.currentTimeMillis()); + } + + + + private Manifest getDefaultManifest() { try { String s = "/org/apache/tools/ant/defaultManifest.mf"; diff --git a/src/main/org/apache/tools/ant/taskdefs/Zip.java b/src/main/org/apache/tools/ant/taskdefs/Zip.java index 000606e11..8cbc4bb96 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Zip.java +++ b/src/main/org/apache/tools/ant/taskdefs/Zip.java @@ -90,17 +90,18 @@ import org.apache.tools.zip.ZipEntry; */ public class Zip extends MatchingTask { - private File zipFile; + protected File zipFile; private File baseDir; private boolean doCompress = true; private boolean doUpdate = false; private boolean doFilesonly = false; protected String archiveType = "zip"; + // For directories: - private static long emptyCrc = new CRC32 ().getValue (); + private final static long EMPTY_CRC = new CRC32 ().getValue (); protected String emptyBehavior = "skip"; private Vector filesets = new Vector (); - private Hashtable addedDirs = new Hashtable(); + protected Hashtable addedDirs = new Hashtable(); private Vector addedFiles = new Vector(); /** true when we are adding new files into the Zip file, as opposed to @@ -596,7 +597,7 @@ public class Zip extends MatchingTask { ze.setSize (0); ze.setMethod (ZipEntry.STORED); // This is faintly ridiculous: - ze.setCrc (emptyCrc); + ze.setCrc (EMPTY_CRC); // this is 040775 | MS-DOS directory flag in reverse byte order ze.setExternalAttributes(0x41FD0010L);