Coverage Report - org.jbehave.core.io.StoryFinder
 
Classes in this File Line Coverage Branch Coverage Complexity
StoryFinder
97%
45/46
100%
10/10
1.455
StoryFinder$1
100%
3/3
N/A
1.455
StoryFinder$2
100%
3/3
N/A
1.455
StoryFinder$3
100%
5/5
100%
2/2
1.455
 
 1  
 package org.jbehave.core.io;
 2  
 
 3  
 import static java.util.Arrays.asList;
 4  
 
 5  
 import java.io.File;
 6  
 import java.net.URL;
 7  
 import java.util.ArrayList;
 8  
 import java.util.Collections;
 9  
 import java.util.Comparator;
 10  
 import java.util.List;
 11  
 
 12  
 import org.apache.commons.collections.CollectionUtils;
 13  
 import org.apache.commons.collections.Transformer;
 14  
 import org.apache.commons.lang.StringUtils;
 15  
 import org.codehaus.plexus.util.DirectoryScanner;
 16  
 
 17  
 /**
 18  
  * Finds stories by scanning source paths, which can be either filesystem
 19  
  * directories or jars. Jars are identified by paths ending in ".jar".
 20  
  * 
 21  
  * Stories can be either in the form of class names or story paths.
 22  
  * 
 23  
  * Stories can be sorted by providing a sorting comparator.
 24  
  */
 25  
 public class StoryFinder {
 26  
 
 27  
     private static final String JAR = ".jar";
 28  
     private static final String JAVA = ".java";
 29  
     private final String classNameExtension;
 30  
     private final Comparator<? super String> sortingComparator;
 31  
 
 32  
     public StoryFinder() {
 33  14
         this(JAVA);
 34  14
     }
 35  
 
 36  
     public StoryFinder(String classNameExtension) {
 37  15
         this(classNameExtension, null);
 38  15
     }
 39  
 
 40  
     public StoryFinder(Comparator<? super String> sortingComparator) {
 41  1
         this(JAVA, sortingComparator);
 42  1
     }
 43  
 
 44  16
     private StoryFinder(String classNameExtension, Comparator<? super String> sortingComparator) {
 45  16
         this.classNameExtension = classNameExtension;
 46  16
         this.sortingComparator = sortingComparator;
 47  16
     }
 48  
 
 49  
     /**
 50  
      * Finds Java classes from a source path, allowing for includes/excludes,
 51  
      * and converts them to class names.
 52  
      * 
 53  
      * @param searchIn the path to search in
 54  
      * @param includes the List of include patterns, or <code>null</code> if
 55  
      *            none
 56  
      * @param excludes the List of exclude patterns, or <code>null</code> if
 57  
      *            none
 58  
      * @return A List of class names found
 59  
      */
 60  
     public List<String> findClassNames(String searchIn, List<String> includes, List<String> excludes) {
 61  4
         return classNames(normalise(sort(scan(searchIn, includes, excludes))));
 62  
     }
 63  
 
 64  
     /**
 65  
      * Finds paths from a source URL, allowing for single include/exclude
 66  
      * pattern. Paths found are normalised by {@link
 67  
      * StoryFinder#normalise(List<String>)}
 68  
      * 
 69  
      * @param searchIn the source URL to search in
 70  
      * @param include the include pattern, or <code>""</code> if none
 71  
      * @param exclude the exclude pattern, or <code>""</code> if none
 72  
      * @return A List of paths found
 73  
      */
 74  
     public List<String> findPaths(URL searchIn, String include, String exclude) {
 75  2
         return findPaths(CodeLocations.getPathFromURL(searchIn), asList(include), asList(exclude));
 76  
     }
 77  
 
 78  
     /**
 79  
      * Finds paths from a source URL, allowing for includes/excludes,
 80  
      * pattern. Paths found are normalised by {@link
 81  
      * StoryFinder#normalise(List<String>)}
 82  
      * 
 83  
      * @param searchIn the source URL to search in
 84  
      * @param includes the List of include patterns, or <code>null</code> if
 85  
      *            none
 86  
      * @param excludes the List of exclude patterns, or <code>null</code> if
 87  
      *            none
 88  
      * @return A List of paths found
 89  
      */
 90  
     public List<String> findPaths(URL searchIn, List<String> includes, List<String> excludes) {
 91  0
         return findPaths(CodeLocations.getPathFromURL(searchIn), includes, excludes);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Finds paths from a source path, allowing for single include/exclude
 96  
      * pattern. Paths found are normalised by {@link
 97  
      * StoryFinder#normalise(List<String>)}
 98  
      * 
 99  
      * @param searchIn the source path to search in
 100  
      * @param include the include pattern, or <code>""</code> if none
 101  
      * @param exclude the exclude pattern, or <code>""</code> if none
 102  
      * @return A List of paths found
 103  
      */
 104  
     public List<String> findPaths(String searchIn, String include, String exclude) {
 105  1
         return findPaths(searchIn, asList(include), asList(exclude));
 106  
     }
 107  
 
 108  
     /**
 109  
      * Finds paths from a source path, allowing for includes/excludes. Paths
 110  
      * found are normalised by {@link StoryFinder#normalise(List<String>)}.
 111  
      * 
 112  
      * @param searchIn the source path to search in
 113  
      * @param includes the List of include patterns, or <code>null</code> if
 114  
      *            none
 115  
      * @param excludes the List of exclude patterns, or <code>null</code> if
 116  
      *            none
 117  
      * @return A List of paths found
 118  
      */
 119  
     public List<String> findPaths(String searchIn, List<String> includes, List<String> excludes) {
 120  7
         return normalise(sort(scan(searchIn, includes, excludes)));
 121  
     }
 122  
 
 123  
     /**
 124  
      * Finds paths from a source path, allowing for includes/excludes. Paths
 125  
      * found are prefixed with specified path by {@link
 126  
      * StoryFinder#prefix(String, List<String>)} and normalised by {@link
 127  
      * StoryFinder#normalise(List<String>)}.
 128  
      * 
 129  
      * @param searchIn the source path to search in
 130  
      * @param includes the List of include patterns, or <code>null</code> if
 131  
      *            none
 132  
      * @param excludes the List of exclude patterns, or <code>null</code> if
 133  
      *            none
 134  
      * @param prefixWith the root path prefixed to all paths found, or
 135  
      *            <code>null</code> if none
 136  
      * @return A List of paths found
 137  
      */
 138  
     public List<String> findPaths(String searchIn, List<String> includes, List<String> excludes, String prefixWith) {
 139  2
         return normalise(prefix(prefixWith, sort(scan(searchIn, includes, excludes))));
 140  
     }
 141  
 
 142  
     protected List<String> normalise(List<String> paths) {
 143  15
         List<String> transformed = new ArrayList<String>(paths);
 144  15
         CollectionUtils.transform(transformed, new Transformer() {
 145  
             public Object transform(Object input) {
 146  127
                 String path = (String) input;
 147  127
                 return path.replace('\\', '/');
 148  
             }
 149  
         });
 150  15
         return transformed;
 151  
     }
 152  
 
 153  
     protected List<String> prefix(final String prefixWith, List<String> paths) {
 154  2
         if (StringUtils.isBlank(prefixWith)) {
 155  1
             return paths;
 156  
         }
 157  1
         List<String> transformed = new ArrayList<String>(paths);
 158  1
         CollectionUtils.transform(transformed, new Transformer() {
 159  
             public Object transform(Object input) {
 160  4
                 String path = (String) input;
 161  4
                 return prefixWith + path;
 162  
             }
 163  
         });
 164  1
         return transformed;
 165  
     }
 166  
 
 167  
     protected List<String> classNames(List<String> paths) {
 168  4
         List<String> trasformed = new ArrayList<String>(paths);
 169  4
         CollectionUtils.transform(trasformed, new Transformer() {
 170  
             public Object transform(Object input) {
 171  8
                 String path = (String) input;
 172  8
                 if (!StringUtils.endsWithIgnoreCase(path, classNameExtension())) {
 173  1
                     return input;
 174  
                 }
 175  7
                 return StringUtils.removeEndIgnoreCase(path, classNameExtension()).replace('/', '.');
 176  
             }
 177  
         });
 178  4
         return trasformed;
 179  
     }
 180  
 
 181  
     protected String classNameExtension() {
 182  15
         return classNameExtension;
 183  
     }
 184  
 
 185  
     protected List<String> sort(List<String> input) {
 186  13
         List<String> sorted = new ArrayList<String>(input);
 187  13
         Collections.sort(sorted, sortingComparator());
 188  13
         return sorted;
 189  
     }
 190  
 
 191  
     /**
 192  
      * Comparator used for sorting. A <code>null</code> comparator means that
 193  
      * {@link Collections#sort()} will use natural ordering.
 194  
      * 
 195  
      * @return A Comparator or <code>null</code> for natural ordering.
 196  
      */
 197  
     protected Comparator<? super String> sortingComparator() {
 198  13
         return sortingComparator;
 199  
     }
 200  
 
 201  
     protected List<String> scan(String source, List<String> includes, List<String> excludes) {
 202  13
         if (source.endsWith(JAR)) {
 203  2
             return scanJar(source, includes, excludes);
 204  
         }
 205  11
         return scanDirectory(source, includes, excludes);
 206  
     }
 207  
 
 208  
     private List<String> scanDirectory(String basedir, List<String> includes, List<String> excludes) {
 209  11
         DirectoryScanner scanner = new DirectoryScanner();
 210  11
         if (!new File(basedir).exists()) {
 211  1
             return new ArrayList<String>();
 212  
         }
 213  10
         scanner.setBasedir(basedir);
 214  10
         if (includes != null) {
 215  9
             scanner.setIncludes(includes.toArray(new String[includes.size()]));
 216  
         }
 217  10
         if (excludes != null) {
 218  9
             scanner.setExcludes(excludes.toArray(new String[excludes.size()]));
 219  
         }
 220  10
         scanner.scan();
 221  10
         return asList(scanner.getIncludedFiles());
 222  
     }
 223  
 
 224  
     protected List<String> scanJar(String jarPath, List<String> includes, List<String> excludes) {
 225  2
         return new JarFileScanner(jarPath, includes, excludes).scan();
 226  
     }
 227  
 
 228  
 }