package info.freelibrary.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* A small collection of Jar file utilities.
*
* @author <a href="mailto:ksclarke@ksclarke.io">Kevin S. Clarke</a>
*/
public class JarUtils {
private static final String JAR_URL_PROTOCOL = "jar:file://";
private JarUtils() {
}
/**
* Gets a list of jar files in the classpath (this includes jars in jars, one level deep).
*
* @return An array of {@link URL}s found in the classpath
* @throws IOException If there is trouble reading the classpath
*/
public static URL[] getJarURLs() throws IOException {
final List<URL> urlList = new LinkedList<>();
for (final JarFile jarFile : ClasspathUtils.getJarFiles()) {
final Manifest manifest = jarFile.getManifest();
final URL jarURL = new URL(JAR_URL_PROTOCOL + jarFile.getName() + "!/");
urlList.add(jarURL);
if (manifest != null) {
final Attributes attributes = manifest.getMainAttributes();
if (attributes != null) {
final String classpath = attributes.getValue("Class-Path");
if (classpath != null) {
final StringTokenizer tokenizer = new StringTokenizer(classpath);
while (tokenizer.hasMoreTokens()) {
final String jarPath = tokenizer.nextToken();
if (jarPath.endsWith(".jar")) {
urlList.add(new URL(jarURL.toExternalForm() + jarPath));
}
}
}
}
}
jarFile.close();
}
return urlList.toArray(new URL[urlList.size()]);
}
/**
* Extract a particular path from a supplied Jar file to a supplied {@link java.io.File} location.
*
* @param aJarFilePath A path to a Jar file from which to extract
* @param aFilePath The Jar file path of the file to extract
* @param aDestDir The destination directory into which the file should be extracted
* @throws IOException If there is an exception thrown while reading or writing the file
*/
public static final void extract(final String aJarFilePath, final String aFilePath, final File aDestDir)
throws IOException {
File file;
try {
// Opening the URL connection just parses location, it doesn't really "open" in the I/O sense
final JarURLConnection connection = (JarURLConnection) new URL(aJarFilePath).openConnection();
file = new File(connection.getJarFileURL().getFile());
} catch (final MalformedURLException details) {
file = new File(aJarFilePath);
}
extract(file, aFilePath, aDestDir);
}
/**
* Extract a particular path from a supplied Jar file to a supplied {@link java.io.File} location.
*
* @param aJarFile A Jar file from which to extract
* @param aFilePath The Jar file path of the file to extract
* @param aDestDir The destination directory into which the file should be extracted
* @throws IOException If there is an exception thrown while reading or writing the file
*/
public static final void extract(final File aJarFile, final String aFilePath, final File aDestDir)
throws IOException {
extract(new JarFile(aJarFile), aFilePath, aDestDir);
}
/**
* Extract a particular path from a supplied Jar file to a supplied {@link java.io.File} location.
*
* @param aJarFile A Jar file from which to extract
* @param aFilePath The Jar file path of the file to extract
* @param aDestDir The destination directory into which the file should be extracted
* @throws IOException If there is an exception thrown while reading or writing the file
*/
public static final void extract(final JarFile aJarFile, final String aFilePath, final File aDestDir)
throws IOException {
final Enumeration<JarEntry> entries = aJarFile.entries();
try {
while (entries.hasMoreElements()) {
final JarEntry entry = entries.nextElement();
final String entryName = entry.getName();
final File file = new File(aDestDir + File.separator + entryName);
if (entryName.equals(aFilePath)) {
final File parent = file.getParentFile();
if (!parent.exists() && !parent.mkdirs()) {
throw new IOException("Unable to create directory structure for: " + file);
}
final InputStream inputStream = aJarFile.getInputStream(entry);
final FileOutputStream outputStream = new FileOutputStream(file);
IOUtils.copyStream(inputStream, outputStream);
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
} finally {
aJarFile.close();
}
}
}