Skip to content

Commit 2ab62eb

Browse files
committed
Improve PlexusIoZipFileResourceCollection performance by using JarFile
Currently `PlexusIoZipFileResourceCollection` uses `PlexusIoURLResource` to get the `InputStream` of the JAR entries. `PlexusIoURLResource` uses `URL` and `URLConnection` to get the input stream. The problem is that they create a new `JarFile` for every entry and in some cases the `JarFile` initialization could be expensive (for example when he JAR is signed). Using the `URLConnection` cache would solve the performance issues but opens new one. The cache is global for the build so if the JAR file have changed during the build you may get the cached instance (see plexus-io#2). Modify `PlexusIoZipFileResourceCollection` to use `JarFile` directly instead of using `PlexusIoURLResource`. That would solve 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 the latest version will be picked up. Under the hood `PlexusIoURLResource` uses `JarFile` as well and keeping `ZipFileResource` extending `PlexusIoURLResource` would both keep the behaviour and interface backward compatible. Closes #106
1 parent c277286 commit 2ab62eb

File tree

1 file changed

+42
-8
lines changed

1 file changed

+42
-8
lines changed

src/main/java/org/codehaus/plexus/archiver/zip/PlexusIoZipFileResourceCollection.java

+42-8
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
import java.io.Closeable;
1919
import java.io.File;
2020
import java.io.IOException;
21+
import java.io.InputStream;
2122
import java.net.URL;
2223
import java.net.URLClassLoader;
2324
import java.nio.charset.Charset;
2425
import java.util.Enumeration;
2526
import java.util.Iterator;
27+
import java.util.jar.JarFile;
2628
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
2729
import org.apache.commons.compress.archivers.zip.ZipFile;
2830
import org.codehaus.plexus.components.io.functions.SymlinkDestinationSupplier;
@@ -84,9 +86,10 @@ public URL getResource( String name )
8486
};
8587

8688
final URL url = new URL( "jar:" + f.toURI().toURL() + "!/" );
89+
final JarFile jarFile = new JarFile( f );
8790
final ZipFile zipFile = new ZipFile( f, charset != null ? charset.name() : "UTF8" );
8891
final Enumeration<ZipArchiveEntry> en = zipFile.getEntriesInPhysicalOrder();
89-
return new ZipFileResourceIterator( en, url, zipFile, urlClassLoader );
92+
return new ZipFileResourceIterator( en, url, jarFile, zipFile, urlClassLoader );
9093
}
9194

9295
private static class ZipFileResourceIterator
@@ -96,14 +99,35 @@ private static class ZipFileResourceIterator
9699
private class ZipFileResource
97100
extends PlexusIoURLResource
98101
{
102+
private final JarFile jarFile;
99103

100-
private ZipFileResource( ZipArchiveEntry entry )
104+
private ZipFileResource( JarFile jarFile, ZipArchiveEntry entry )
101105
{
102106
super( entry.getName(),
103107
entry.getTime() == -1 ? PlexusIoResource.UNKNOWN_MODIFICATION_DATE : entry.getTime(),
104108
entry.isDirectory() ? PlexusIoResource.UNKNOWN_RESOURCE_SIZE : entry.getSize(),
105109
!entry.isDirectory(), entry.isDirectory(), true );
106110

111+
this.jarFile = jarFile;
112+
}
113+
114+
@Override
115+
public InputStream getContents() throws IOException {
116+
// Uses the JarFile to get the input stream for the entry.
117+
// The super method will do the same, why overriding it?
118+
// But it will create new JarFile for every entry
119+
// and that could be very expensive in some cases (when the JAR is signed).
120+
// Enabling the URLConnection cache would solve the problem
121+
// but the cache is global and shared during the build so
122+
// if the AJR file changed during the causes another problem
123+
// (see plexus-io#2).
124+
// Using local JarFile instance solves the two issues -
125+
// JarFile is initialized once so there is no performance penalty
126+
// and it is local so if the file changed during the build
127+
// would not be a problem.
128+
// And we know the URL returned by getURL is part of the JAR
129+
// because that is how we constructed it.
130+
return jarFile.getInputStream( jarFile.getEntry( getName() ) );
107131
}
108132

109133
@Override
@@ -131,9 +155,9 @@ private class ZipFileSymlinkResource
131155

132156
private final ZipArchiveEntry entry;
133157

134-
private ZipFileSymlinkResource( ZipArchiveEntry entry )
158+
private ZipFileSymlinkResource( JarFile jarFile, ZipArchiveEntry entry )
135159
{
136-
super( entry );
160+
super( jarFile, entry );
137161

138162
this.entry = entry;
139163
}
@@ -157,15 +181,18 @@ public boolean isSymbolicLink()
157181

158182
private final URL url;
159183

184+
private final JarFile jarFile;
185+
160186
private final ZipFile zipFile;
161187

162188
private final URLClassLoader urlClassLoader;
163189

164-
public ZipFileResourceIterator( Enumeration<ZipArchiveEntry> en, URL url, ZipFile zipFile,
190+
public ZipFileResourceIterator( Enumeration<ZipArchiveEntry> en, URL url, JarFile jarFile, ZipFile zipFile,
165191
URLClassLoader urlClassLoader )
166192
{
167193
this.en = en;
168194
this.url = url;
195+
this.jarFile = jarFile;
169196
this.zipFile = zipFile;
170197
this.urlClassLoader = urlClassLoader;
171198
}
@@ -181,8 +208,8 @@ public PlexusIoResource next()
181208
{
182209
final ZipArchiveEntry entry = en.nextElement();
183210
return entry.isUnixSymlink()
184-
? new ZipFileSymlinkResource( entry )
185-
: new ZipFileResource( entry );
211+
? new ZipFileSymlinkResource( jarFile, entry )
212+
: new ZipFileResource( jarFile, entry );
186213

187214
}
188215

@@ -202,7 +229,14 @@ public void close()
202229
}
203230
finally
204231
{
205-
zipFile.close();
232+
try
233+
{
234+
zipFile.close();
235+
} finally
236+
{
237+
jarFile.close();
238+
}
239+
206240
}
207241
}
208242

0 commit comments

Comments
 (0)