Class NestedJarHandler
- java.lang.Object
-
- io.github.lukehutch.fastclasspathscanner.utils.NestedJarHandler
-
public class NestedJarHandler extends Object
Unzip a jarfile within a jarfile to a temporary file on disk. Also handles the download of jars from http(s) URLs to temp files.Somewhat paradoxically, the fastest way to support scanning zipfiles-within-zipfiles is to unzip the inner zipfile to a temporary file on disk, because the inner zipfile can only be read using ZipInputStream, not ZipFile (the ZipFile constructors only take a File argument). ZipInputStream doesn't have methods for reading the zip directory at the beginning of the stream, so using ZipInputStream rather than ZipFile, you have to decompress the entire zipfile to read all the directory entries. However, there may be many non-whitelisted entries in the zipfile, so this could be a lot of wasted work.
FastClasspathScanner makes two passes, one to read the zipfile directory, which whitelist and blacklist criteria are applied to (this is a fast operation when using ZipFile), and then an additional pass to read only whitelisted (non-blacklisted) entries. Therefore, in the general case, the ZipFile API is always going to be faster than ZipInputStream. Therefore, decompressing the inner zipfile to disk is the only efficient option.
-
-
Field Summary
Fields Modifier and Type Field Description static String
TEMP_FILENAME_LEAF_SEPARATOR
-
Constructor Summary
Constructors Constructor Description NestedJarHandler(ScanSpec scanSpec, InterruptionChecker interruptionChecker, LogNode log)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description void
close(LogNode log)
Delete temporary files and release other resources.Map.Entry<File,Set<String>>
getInnermostNestedJar(String nestedJarPath, LogNode log)
Get a File for a given (possibly nested) jarfile path, unzipping the first N-1 segments of an N-segment '!'-delimited path to temporary files, then returning the File reference for the N-th temporary file.JarfileMetadataReader
getJarfileMetadataReader(File zipFile, String jarfilePackageRoot, LogNode log)
Get aJarfileMetadataReader
singleton for a given jarfile (so that the manifest and ZipEntries will only be read once).Recycler<ModuleReaderProxy,IOException>
getModuleReaderProxyRecycler(ModuleRef moduleRef, LogNode log)
Get a ModuleReaderProxy recycler given a ModuleRef.File
getOutermostJar(File jarFile)
Given a File reference for an inner nested jarfile, find the outermost jarfile it was extracted from.Recycler<ZipFile,IOException>
getZipFileRecycler(File zipFile, LogNode log)
Get a ZipFile recycler given the (non-nested) canonical path of a jarfile.String
sanitizeFilename(String filename)
File
unzipToTempDir(File jarFile, String packageRoot, LogNode log)
Unzip a given package root within a zipfile to a temporary directory, starting several more threads to perform the unzip in parallel, then return the temporary directory.
-
-
-
Field Detail
-
TEMP_FILENAME_LEAF_SEPARATOR
public static final String TEMP_FILENAME_LEAF_SEPARATOR
- See Also:
- Constant Field Values
-
-
Constructor Detail
-
NestedJarHandler
public NestedJarHandler(ScanSpec scanSpec, InterruptionChecker interruptionChecker, LogNode log)
-
-
Method Detail
-
getZipFileRecycler
public Recycler<ZipFile,IOException> getZipFileRecycler(File zipFile, LogNode log) throws Exception
Get a ZipFile recycler given the (non-nested) canonical path of a jarfile.- Returns:
- The ZipFile recycler.
- Throws:
Exception
-
getJarfileMetadataReader
public JarfileMetadataReader getJarfileMetadataReader(File zipFile, String jarfilePackageRoot, LogNode log) throws Exception
Get aJarfileMetadataReader
singleton for a given jarfile (so that the manifest and ZipEntries will only be read once).- Throws:
Exception
-
getModuleReaderProxyRecycler
public Recycler<ModuleReaderProxy,IOException> getModuleReaderProxyRecycler(ModuleRef moduleRef, LogNode log) throws Exception
Get a ModuleReaderProxy recycler given a ModuleRef.- Returns:
- The ModuleReaderProxy recycler.
- Throws:
Exception
-
getInnermostNestedJar
public Map.Entry<File,Set<String>> getInnermostNestedJar(String nestedJarPath, LogNode log) throws Exception
Get a File for a given (possibly nested) jarfile path, unzipping the first N-1 segments of an N-segment '!'-delimited path to temporary files, then returning the File reference for the N-th temporary file.If the path does not contain '!', returns the File represented by the path.
All path segments should end in a jarfile extension, e.g. ".jar" or ".zip".
- Returns:
- An
Entry<File, Set<String>>
, where theFile
is the innermost jar, and theSet<String>
is the set of all relative paths of scanning roots within the innermost jar (may be empty, or may contain strings like "target/classes" or similar). If there was an issue with the path, returns null. - Throws:
Exception
-
getOutermostJar
public File getOutermostJar(File jarFile)
Given a File reference for an inner nested jarfile, find the outermost jarfile it was extracted from.
-
unzipToTempDir
public File unzipToTempDir(File jarFile, String packageRoot, LogNode log) throws IOException
Unzip a given package root within a zipfile to a temporary directory, starting several more threads to perform the unzip in parallel, then return the temporary directory. The temporary directory and all of its contents will be removed whenNestedJarHandler#close())
is called.N.B. standalone code for parallel unzip can be found at https://github.com/lukehutch/quickunzip
- Throws:
IOException
-
close
public void close(LogNode log)
Delete temporary files and release other resources.
-
-