JarFileScanner.java

  1. package org.jbehave.core.io;

  2. import static java.util.Arrays.asList;
  3. import static org.apache.commons.lang3.StringUtils.isBlank;

  4. import java.io.File;
  5. import java.io.IOException;
  6. import java.net.URL;
  7. import java.util.ArrayList;
  8. import java.util.Arrays;
  9. import java.util.Enumeration;
  10. import java.util.List;
  11. import java.util.jar.JarEntry;
  12. import java.util.jar.JarFile;
  13. import java.util.stream.Collectors;

  14. import org.codehaus.plexus.util.SelectorUtils;

  15. /**
  16.  * Find all matching file entries in a jar.
  17.  */
  18. public class JarFileScanner {

  19.     private URL jarURL;
  20.     private List<String> includes;
  21.     private List<String> excludes;

  22.     public JarFileScanner(String jarPath, String includes, String excludes) {
  23.         this(jarPath, asList(includes), asList(excludes));
  24.     }

  25.     public JarFileScanner(String jarPath, List<String> includes, List<String> excludes) {
  26.         this(CodeLocations.codeLocationFromPath(jarPath), includes, excludes);
  27.     }

  28.     public JarFileScanner(URL jarURL, String includes, String excludes) {
  29.         this(jarURL, asList(includes), asList(excludes));
  30.     }

  31.     public JarFileScanner(URL jarURL, List<String> includes, List<String> excludes) {
  32.         this.jarURL = jarURL;
  33.         this.includes = includes != null ? toLocalPath(includes) : Arrays.<String>asList();
  34.         this.excludes = excludes != null ? toLocalPath(excludes) : Arrays.<String>asList();
  35.     }

  36.     /**
  37.      * Scans the jar file and returns the paths that match the includes and excludes.
  38.      *
  39.      * @return A List of paths
  40.      * @throws An IllegalStateException when an I/O error occurs in reading the jar file.
  41.      */
  42.     public List<String> scan() {
  43.         try {
  44.             JarFile jar = new JarFile(jarURL.getFile());
  45.             try {
  46.                 List<String> result = new ArrayList<>();
  47.                 Enumeration<JarEntry> en = jar.entries();
  48.                 while (en.hasMoreElements()) {
  49.                     JarEntry entry = en.nextElement();
  50.                     String path = entry.getName();
  51.                     boolean match = includes.size() == 0;
  52.                     if (!match) {
  53.                         for (String pattern : includes) {
  54.                             if (patternMatches(pattern, path)) {
  55.                                 match = true;
  56.                                 break;
  57.                             }
  58.                         }
  59.                     }
  60.                     if (match) {
  61.                         for (String pattern : excludes) {
  62.                             if (patternMatches(pattern, path)) {
  63.                                 match = false;
  64.                                 break;
  65.                             }
  66.                         }
  67.                     }
  68.                     if (match) {
  69.                         result.add(path);
  70.                     }
  71.                 }
  72.                 return result;
  73.             } finally {
  74.                 jar.close();
  75.             }
  76.         } catch (IOException e) {
  77.             throw new IllegalStateException(e);
  78.         }
  79.     }

  80.     private List<String> toLocalPath(List<String> patternList) {
  81.         return patternList.stream()
  82.                 .map(pattern -> pattern != null ? pattern.replace('/', File.separatorChar) : null)
  83.                 .collect(Collectors.toList());
  84.     }

  85.     private boolean patternMatches(String pattern, String path) {
  86.         if (isBlank(pattern)) {
  87.             return false;
  88.         }
  89.         // SelectorUtils assumes local path separator for path and pattern
  90.         String localPath = path.replace('/', File.separatorChar);
  91.         return SelectorUtils.matchPath(pattern, localPath);
  92.     }

  93. }