JarFileScanner.java
package org.jbehave.core.io;
import static java.util.Arrays.asList;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import org.codehaus.plexus.util.SelectorUtils;
/**
* Find all matching file entries in a jar.
*/
public class JarFileScanner {
private URL jarURL;
private List<String> includes;
private List<String> excludes;
public JarFileScanner(String jarPath, String includes, String excludes) {
this(jarPath, asList(includes), asList(excludes));
}
public JarFileScanner(String jarPath, List<String> includes, List<String> excludes) {
this(CodeLocations.codeLocationFromPath(jarPath), includes, excludes);
}
public JarFileScanner(URL jarURL, String includes, String excludes) {
this(jarURL, asList(includes), asList(excludes));
}
public JarFileScanner(URL jarURL, List<String> includes, List<String> excludes) {
this.jarURL = jarURL;
this.includes = includes != null ? toLocalPath(includes) : Arrays.<String>asList();
this.excludes = excludes != null ? toLocalPath(excludes) : Arrays.<String>asList();
}
/**
* Scans the jar file and returns the paths that match the includes and excludes.
*
* @return A List of paths
* @throws An IllegalStateException when an I/O error occurs in reading the jar file.
*/
public List<String> scan() {
try {
JarFile jar = new JarFile(jarURL.getFile());
try {
List<String> result = new ArrayList<>();
Enumeration<JarEntry> en = jar.entries();
while (en.hasMoreElements()) {
JarEntry entry = en.nextElement();
String path = entry.getName();
boolean match = includes.size() == 0;
if (!match) {
for (String pattern : includes) {
if (patternMatches(pattern, path)) {
match = true;
break;
}
}
}
if (match) {
for (String pattern : excludes) {
if (patternMatches(pattern, path)) {
match = false;
break;
}
}
}
if (match) {
result.add(path);
}
}
return result;
} finally {
jar.close();
}
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
private List<String> toLocalPath(List<String> patternList) {
return patternList.stream()
.map(pattern -> pattern != null ? pattern.replace('/', File.separatorChar) : null)
.collect(Collectors.toList());
}
private boolean patternMatches(String pattern, String path) {
if (isBlank(pattern)) {
return false;
}
// SelectorUtils assumes local path separator for path and pattern
String localPath = path.replace('/', File.separatorChar);
return SelectorUtils.matchPath(pattern, localPath);
}
}