package net.thucydides.core.resources;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* Utility class to read report resources from the classpath. This way, report
* resources such as images and stylesheets can be shipped in a separate JAR
* file.
*/
public class ResourceList {
private static final List<String> UNREQUIRED_FILES = Arrays.asList("pom.xml");
private static final String PATH_SEPARATOR = System.getProperty("path.separator");
private final Pattern pattern;
public static ResourceList forResources(final Pattern pattern) {
return new ResourceList(pattern);
}
protected ResourceList(final Pattern pattern) {
this.pattern = pattern;
}
/**
* Find a list of resources matching a given path on the classpath. for all
* elements of java.class.path get a Collection of resources Pattern pattern
* = Pattern.compile(".*"); gets all resources
*
* @return the resources in the order they are found
*/
public Collection<String> list() {
final ArrayList<String> resources = new ArrayList<String>();
resources.addAll(systemPropertiesClasspathElements());
ClassLoader classLoader = getClass().getClassLoader();
if (classLoader instanceof URLClassLoader) {
addResourcesFromUrlClassLoader(resources, (URLClassLoader) classLoader);
}
return resources;
}
private void addResourcesFromUrlClassLoader(ArrayList<String> resources, URLClassLoader classLoader) {
URL[] classPathElements = classLoader.getURLs();
for(URL classPathElement : classPathElements) {
resources.addAll(getResources(classPathElement.getFile(), pattern));
}
}
public Collection<String> systemPropertiesClasspathElements() {
final ArrayList<String> resources = new ArrayList<String>();
final String classPath = System.getProperty("java.class.path", ".");
final String[] classPathElements = classPath.split(PATH_SEPARATOR);
for (final String element : classPathElements) {
resources.addAll(getResources(element, pattern));
}
return resources;
}
private Collection<String> getResources(final String element, final Pattern pattern) {
final ArrayList<String> resources = new ArrayList<String>();
final File file = new File(element);
if (isAJarFile(file)) {
resources.addAll(getResourcesFromJarFile(file, pattern));
} else {
resources.addAll(getResourcesFromDirectory(file, pattern));
}
return removeUnnecessaryFilesFrom(resources);
}
private Collection<String> removeUnnecessaryFilesFrom(final Collection<String> resources) {
final Collection<String> cleanedResources = new ArrayList<String>();
for (String filepath : resources) {
String filename = new File(filepath).getName();
if (!UNREQUIRED_FILES.contains(filename)) {
cleanedResources.add(filepath);
}
}
return cleanedResources;
}
private boolean isAJarFile(final File file) {
if (file.isDirectory()) {
return false;
} else {
return (file.getName().endsWith(".jar"));
}
}
protected ZipFile zipFileFor(final File file) throws IOException {
return new ZipFile(file);
}
private Collection<String> getResourcesFromJarFile(final File file, final Pattern pattern) {
final ArrayList<String> retval = new ArrayList<String>();
if (file.exists()) {
ZipFile zf;
try {
zf = zipFileFor(file);
} catch (final IOException e) {
throw new ResourceCopyingError("Could not read from the JAR file", e);
}
@SuppressWarnings("rawtypes")
final Enumeration e = zf.entries();
while (e.hasMoreElements()) {
final ZipEntry ze = (ZipEntry) e.nextElement();
final String fileName = ze.getName();
final boolean accept = pattern.matcher(fileName).matches();
if (accept) {
retval.add(fileName);
}
}
try {
zf.close();
} catch (final IOException e1) {
throw new ResourceCopyingError("Couldn't close the zip file", e1);
}
}
return retval;
}
private Collection<String> getResourcesFromDirectory(final File directory,
final Pattern pattern) {
final ArrayList<String> retval = new ArrayList<String>();
final File[] fileList = directory.listFiles();
if (fileList != null) {
for (final File file : fileList) {
if (file.isDirectory() && (file.exists())) {
retval.addAll(getResourcesFromDirectory(file, pattern));
} else {
if (file.exists()) {
try {
final String fileName = file.getCanonicalPath();
final boolean accept = pattern.matcher(fileName).matches();
if (accept) {
retval.add(fileName);
}
} catch (final IOException e) {
throw new ResourceCopyingError("Could not read from the JAR file", e);
}
}
}
}
}
return retval;
}
}