Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@arey
Created January 21, 2014 11:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arey/8538107 to your computer and use it in GitHub Desktop.
Save arey/8538107 to your computer and use it in GitHub Desktop.
Flyway JarFileRecursiveClassPathLocationScanner for jar files opening all war and jar recursively.
package com.googlecode.flyway.core.util.scanner.classpath;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Set;
import java.util.TreeSet;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
/**
* JarFileRecursiveClassPathLocationScanner for jar files opening all war and jar recursively.
*/
public class JarFileClassPathLocationScanner implements ClassPathLocationScanner {
public Set<String> findResourceNames(String location, URL locationUrl) throws IOException {
JarFile jarFile = getJarFromUrl(locationUrl);
try {
return findResourceNamesRecursivelyFromJarFile(jarFile, location);
} finally {
jarFile.close();
}
}
/**
* Retrieves the Jar file represented by this URL.
*
* @param locationUrl The URL of the jar.
* @return The jar file.
* @throws IOException when the jar could not be resolved.
*/
private JarFile getJarFromUrl(URL locationUrl) throws IOException {
URLConnection con = locationUrl.openConnection();
if (con instanceof JarURLConnection) {
// Should usually be the case for traditional JAR files.
JarURLConnection jarCon = (JarURLConnection) con;
jarCon.setUseCaches(false);
return jarCon.getJarFile();
}
// No JarURLConnection -> need to resort to URL file parsing.
// We'll assume URLs of the format "jar:path!/entry", with the protocol
// being arbitrary as long as following the entry format.
// We'll also handle paths with and without leading "file:" prefix.
String urlFile = locationUrl.getFile();
int separatorIndex = urlFile.indexOf("!/");
if (separatorIndex != -1) {
String jarFileUrl = urlFile.substring(0, separatorIndex);
if (jarFileUrl.startsWith("file:")) {
try {
return new JarFile(new URL(jarFileUrl).toURI().getSchemeSpecificPart());
} catch (URISyntaxException ex) {
// Fallback for URLs that are not valid URIs (should hardly ever happen).
return new JarFile(jarFileUrl.substring("file:".length()));
}
}
return new JarFile(jarFileUrl);
}
return new JarFile(urlFile);
}
/**
* Finds all the resource names contained in this directory within this jar file.
*
* @param jarFile The jar file.
* @param location The location to look under.
* @return The resource names.
* @throws java.io.IOException when reading the jar file failed.
*/
private Set<String> findResourceNamesRecursivelyFromJarFile(JarFile jarFile, String location) throws IOException {
Set<String> resourceNames = new TreeSet<String>();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
//read entry recursively : if filename ends with .war or .jar, its content is opened
readEntry(jarFile.getInputStream(entry), resourceNames, entry, location);
}
return resourceNames;
}
private void readEntry(InputStream containerInputStream, Set<String> resourceNames, ZipEntry entry, String location) throws IOException {
String entryName = entry.getName();
if (entryName.startsWith(location)) {
resourceNames.add(entryName);
return;
}
if (!entry.isDirectory() && (entryName.endsWith(".war") || entryName.endsWith(".jar"))) {
findResourceNamesFromCompressedEntry(containerInputStream, resourceNames, location);
}
}
private void findResourceNamesFromCompressedEntry(InputStream containerInputStream, Set<String> resourceNames, String location) throws IOException {
// opening jar sub jar inputstream from container inputstream
JarInputStream jarIn = new JarInputStream(containerInputStream);
while (true) {
ZipEntry jarContentEntry = jarIn.getNextEntry();
if (jarContentEntry == null) {
break;
}
readEntry(jarIn, resourceNames, jarContentEntry, location);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment