StoryFinder.java
- package org.jbehave.core.io;
- import static java.util.Arrays.asList;
- import java.io.File;
- import java.net.URL;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.List;
- import java.util.stream.Collectors;
- import org.apache.commons.lang3.StringUtils;
- import org.codehaus.plexus.util.DirectoryScanner;
- import org.jbehave.core.configuration.Configuration;
- /**
- * <p>Finds stories by scanning source paths, which can be either filesystem
- * directories or jars. Jars are identified by paths ending in ".jar".</p>
- *
- * <p>Stories can be either in the form of class names or story paths.</p>
- *
- * <p>The default class name extension is ".java".</p>
- *
- * <p>Stories can be sorted by providing a sorting {@link Comparator}.
- * Alternatively, stories can be sorted at execution-time using the
- * {@link Configuration#useStoryExecutionComparator(Comparator)} instead.</p>
- */
- public class StoryFinder {
- private static final String JAR = ".jar";
- private static final String JAVA = ".java";
- private final String classNameExtension;
- private final Comparator<? super String> sortingComparator;
- /**
- * Creates default StoryFinder for ".java" class names and no sorting.
- */
- public StoryFinder() {
- this(JAVA);
- }
- /**
- * Creates a StoryFinder with a given class name extension and no sorting.
- *
- * @param classNameExtension the extension
- */
- public StoryFinder(String classNameExtension) {
- this(classNameExtension, null);
- }
- /**
- * Creates a StoryFinder with a given sorting comparator.
- *
- * @param sortingComparator comparator to sort stories by path
- */
- public StoryFinder(Comparator<? super String> sortingComparator) {
- this(JAVA, sortingComparator);
- }
- /**
- * Creates a StoryFinder with given class name extension and sorting comparator.
- *
- * @param classNameExtension class name extensions to find
- * @param sortingComparator comparator to sort stories by path
- */
- private StoryFinder(String classNameExtension, Comparator<? super String> sortingComparator) {
- this.classNameExtension = classNameExtension;
- this.sortingComparator = sortingComparator;
- }
- /**
- * Finds Java classes from a source path, allowing for includes/excludes, and converts them to class names.
- *
- * @param searchIn the path to search in
- * @param includes the List of include patterns, or <code>null</code> if none
- * @param excludes the List of exclude patterns, or <code>null</code> if none
- * @return A List of class names found
- */
- public List<String> findClassNames(String searchIn, List<String> includes, List<String> excludes) {
- return classNames(normalise(sort(scan(searchIn, includes, excludes))));
- }
- /**
- * Finds paths from a source URL, allowing for single include/exclude pattern. Paths found are normalised by
- * {@link StoryFinder#normalise(List)}.
- *
- * @param searchIn the source URL to search in
- * @param include the include pattern, or <code>""</code> if none
- * @param exclude the exclude pattern, or <code>""</code> if none
- * @return A List of paths found
- */
- public List<String> findPaths(URL searchIn, String include, String exclude) {
- return findPaths(CodeLocations.getPathFromURL(searchIn), asCSVList(include), asCSVList(exclude));
- }
- /**
- * Finds paths from a source URL, allowing for includes/excludes patterns. Paths found are normalised by
- * {@link StoryFinder#normalise(List)}.
- *
- * @param searchIn the source URL to search in
- * @param includes the Array of include patterns, or <code>null</code> if none
- * @param excludes the Array of exclude patterns, or <code>null</code> if none
- * @return A List of paths found
- */
- public List<String> findPaths(URL searchIn, String[] includes, String[] excludes) {
- return findPaths(CodeLocations.getPathFromURL(searchIn), asList(includes), asList(excludes));
- }
- /**
- * Finds paths from a source path, allowing for include/exclude patterns, which can be comma-separated values of
- * multiple patterns. Paths found are normalised by {@link StoryFinder#normalise(List)}.
- *
- * @param searchIn the source path to search in
- * @param include the CSV include pattern, or <code>null</code> if none
- * @param exclude the CSV exclude pattern, or <code>null</code> if none
- * @return A List of paths found
- */
- public List<String> findPaths(String searchIn, String include, String exclude) {
- return findPaths(searchIn, asCSVList(include), asCSVList(exclude));
- }
- /**
- * Finds paths from a source path, allowing for include/exclude patterns. Paths found are normalised by
- * {@link StoryFinder#normalise(List)}.
- *
- * @param searchIn the source path to search in
- * @param includes the Array of include patterns, or <code>null</code> if none
- * @param excludes the Array of exclude patterns, or <code>null</code> if none
- * @return A List of paths found
- */
- public List<String> findPaths(String searchIn, String[] includes, String[] excludes) {
- return findPaths(searchIn, asList(includes), asList(excludes));
- }
- /**
- * Finds paths from a source URL, allowing for includes/excludes patterns. Paths found are normalised by
- * {@link StoryFinder#normalise(List)}.
- *
- * @param searchIn the source URL to search in
- * @param includes the List of include patterns, or <code>null</code> if none
- * @param excludes the List of exclude patterns, or <code>null</code> if none
- * @return A List of paths found
- */
- public List<String> findPaths(URL searchIn, List<String> includes, List<String> excludes) {
- return findPaths(CodeLocations.getPathFromURL(searchIn), includes, excludes);
- }
- /**
- * Finds paths from a source path, allowing for include/exclude patterns. Paths found are normalised by
- * {@link StoryFinder#normalise(List)}.
- * .
- *
- * @param searchIn the source path to search in
- * @param includes the List of include patterns, or <code>null</code> if none
- * @param excludes the List of exclude patterns, or <code>null</code> if none
- * @return A List of paths found
- */
- public List<String> findPaths(String searchIn, List<String> includes, List<String> excludes) {
- return normalise(sort(scan(searchIn, includes, excludes)));
- }
- /**
- * Finds paths from a source path, allowing for includes/excludes. Paths found are prefixed with specified path by
- * {@link StoryFinder#prefix(String, List)} and normalised by {@link StoryFinder#normalise(List)}.
- *
- * @param searchIn the source path to search in
- * @param includes the List of include patterns, or <code>null</code> if none
- * @param excludes the List of exclude patterns, or <code>null</code> if none
- * @param prefixWith the root path prefixed to all paths found, or <code>null</code> if none
- * @return A List of paths found
- */
- public List<String> findPaths(String searchIn, List<String> includes, List<String> excludes, String prefixWith) {
- return normalise(prefix(prefixWith, sort(scan(searchIn, includes, excludes))));
- }
- protected List<String> normalise(List<String> paths) {
- return paths.stream().map(path -> path.replace('\\', '/')).collect(Collectors.toList());
- }
- protected List<String> prefix(final String prefixWith, List<String> paths) {
- if (StringUtils.isBlank(prefixWith)) {
- return paths;
- }
- return paths.stream().map(prefixWith::concat).collect(Collectors.toList());
- }
- protected List<String> classNames(List<String> paths) {
- return paths.stream().map(path -> {
- if (!StringUtils.endsWithIgnoreCase(path, classNameExtension())) {
- return path;
- }
- return StringUtils.removeEndIgnoreCase(path, classNameExtension()).replace('/', '.');
- }).collect(Collectors.toList());
- }
- protected String classNameExtension() {
- return classNameExtension;
- }
- protected List<String> sort(List<String> input) {
- List<String> sorted = new ArrayList<>(input);
- Collections.sort(sorted, sortingComparator());
- return sorted;
- }
- /**
- * Comparator used for sorting. A <code>null</code> comparator means that {@link Collections#sort(List)} will use
- * natural ordering.
- *
- * @return A Comparator or <code>null</code> for natural ordering.
- */
- protected Comparator<? super String> sortingComparator() {
- return sortingComparator;
- }
- protected List<String> scan(String source, List<String> includes, List<String> excludes) {
- if (source.endsWith(JAR)) {
- return scanJar(source, includes, excludes);
- }
- return scanDirectory(source, includes, excludes);
- }
- private List<String> asCSVList(String pattern) {
- List<String> list;
- if (pattern == null) {
- list = asList();
- } else {
- list = asList(pattern.split(","));
- }
- return list;
- }
- private List<String> scanDirectory(String basedir, List<String> includes, List<String> excludes) {
- DirectoryScanner scanner = new DirectoryScanner();
- if (!new File(basedir).exists()) {
- return new ArrayList<>();
- }
- scanner.setBasedir(basedir);
- if (includes != null) {
- scanner.setIncludes(includes.toArray(new String[includes.size()]));
- }
- if (excludes != null) {
- scanner.setExcludes(excludes.toArray(new String[excludes.size()]));
- }
- scanner.scan();
- return asList(scanner.getIncludedFiles());
- }
- protected List<String> scanJar(String jarPath, List<String> includes, List<String> excludes) {
- return new JarFileScanner(jarPath, includes, excludes).scan();
- }
- }