diff --git a/src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java b/src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java index e14a7ebe2..90c970bc3 100644 --- a/src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java +++ b/src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java @@ -18,11 +18,13 @@ import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.Charset; import java.util.Enumeration; import java.util.Iterator; +import java.util.jar.JarFile; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; import org.codehaus.plexus.components.io.functions.SymlinkDestinationSupplier; @@ -84,9 +86,10 @@ public URL getResource( String name ) }; final URL url = new URL( "jar:" + f.toURI().toURL() + "!/" ); + final JarFile jarFile = new JarFile( f ); final ZipFile zipFile = new ZipFile( f, charset != null ? charset.name() : "UTF8" ); final Enumeration en = zipFile.getEntriesInPhysicalOrder(); - return new ZipFileResourceIterator( en, url, zipFile, urlClassLoader ); + return new ZipFileResourceIterator( en, url, jarFile, zipFile, urlClassLoader ); } private static class ZipFileResourceIterator @@ -96,14 +99,35 @@ private static class ZipFileResourceIterator private class ZipFileResource extends PlexusIoURLResource { + private final JarFile jarFile; - private ZipFileResource( ZipArchiveEntry entry ) + private ZipFileResource( JarFile jarFile, ZipArchiveEntry entry ) { super( entry.getName(), entry.getTime() == -1 ? PlexusIoResource.UNKNOWN_MODIFICATION_DATE : entry.getTime(), entry.isDirectory() ? PlexusIoResource.UNKNOWN_RESOURCE_SIZE : entry.getSize(), !entry.isDirectory(), entry.isDirectory(), true ); + this.jarFile = jarFile; + } + + @Override + public InputStream getContents() throws IOException { + // Uses the JarFile to get the input stream for the entry. + // The super method will do the same, why overriding it? + // But it will create new JarFile for every entry + // and that could be very expensive in some cases (when the JAR is signed). + // Enabling the URLConnection cache would solve the problem + // but the cache is global and shared during the build so + // if the AJR file changed during the causes another problem + // (see plexus-io#2). + // Using local JarFile instance solves the two issues - + // JarFile is initialized once so there is no performance penalty + // and it is local so if the file changed during the build + // would not be a problem. + // And we know the URL returned by getURL is part of the JAR + // because that is how we constructed it. + return jarFile.getInputStream( jarFile.getEntry( getName() ) ); } @Override @@ -131,9 +155,9 @@ private class ZipFileSymlinkResource private final ZipArchiveEntry entry; - private ZipFileSymlinkResource( ZipArchiveEntry entry ) + private ZipFileSymlinkResource( JarFile jarFile, ZipArchiveEntry entry ) { - super( entry ); + super( jarFile, entry ); this.entry = entry; } @@ -157,15 +181,18 @@ public boolean isSymbolicLink() private final URL url; + private final JarFile jarFile; + private final ZipFile zipFile; private final URLClassLoader urlClassLoader; - public ZipFileResourceIterator( Enumeration en, URL url, ZipFile zipFile, + public ZipFileResourceIterator( Enumeration en, URL url, JarFile jarFile, ZipFile zipFile, URLClassLoader urlClassLoader ) { this.en = en; this.url = url; + this.jarFile = jarFile; this.zipFile = zipFile; this.urlClassLoader = urlClassLoader; } @@ -181,8 +208,8 @@ public PlexusIoResource next() { final ZipArchiveEntry entry = en.nextElement(); return entry.isUnixSymlink() - ? new ZipFileSymlinkResource( entry ) - : new ZipFileResource( entry ); + ? new ZipFileSymlinkResource( jarFile, entry ) + : new ZipFileResource( jarFile, entry ); } @@ -202,7 +229,14 @@ public void close() } finally { - zipFile.close(); + try + { + zipFile.close(); + } finally + { + jarFile.close(); + } + } }