package org.jbehave.core.io; 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 org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.Transformer; import org.codehaus.plexus.util.SelectorUtils; import static java.util.Arrays.asList; import static org.apache.commons.lang3.StringUtils.isBlank; /** * 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<String>(); 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) { List<String> transformed = new ArrayList<String>(patternList); CollectionUtils.transform(transformed, new Transformer<String, String>() { public String transform(String pattern) { return pattern!=null ? pattern.replace('/', File.separatorChar) : null; } }); return transformed; } 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); } }