Created
January 21, 2014 11:04
-
-
Save arey/8538107 to your computer and use it in GitHub Desktop.
Flyway JarFileRecursiveClassPathLocationScanner for jar files opening all war and jar recursively.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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