/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* !#
*/
package net.ontopia.utils;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class ResourcesDirectoryReader {
private static final boolean SEARCHSUBDIRECTORIESDEFAULTVALUE = false;
private final ClassLoader classLoader;
private final String directoryPath;
private final boolean searchSubdirectories;
private Set<ResourcesFilterIF> filters;
private Set<String> resources = null;
public ResourcesDirectoryReader(ClassLoader classLoader, String directoryPath) {
this(classLoader, directoryPath, SEARCHSUBDIRECTORIESDEFAULTVALUE);
}
public ResourcesDirectoryReader(ClassLoader classLoader, String directoryPath, boolean searchSubdirectories) {
this.classLoader = classLoader;
this.directoryPath = (directoryPath.endsWith("/")) ? directoryPath : (directoryPath + "/");
this.searchSubdirectories = searchSubdirectories;
this.filters = new HashSet<ResourcesFilterIF>();
}
// Constructors without classloader default to Thread.currentThread().getContextClassLoader()
public ResourcesDirectoryReader(String directoryPath) {
this(directoryPath, SEARCHSUBDIRECTORIESDEFAULTVALUE);
}
public ResourcesDirectoryReader(String directoryPath, boolean searchSubdirectories) {
this(Thread.currentThread().getContextClassLoader(), directoryPath, searchSubdirectories);
}
// Constructors with filter
public ResourcesDirectoryReader(String directoryPath, ResourcesFilterIF filter) {
this(directoryPath, SEARCHSUBDIRECTORIESDEFAULTVALUE, filter);
}
public ResourcesDirectoryReader(String directoryPath, boolean searchSubdirectories, ResourcesFilterIF filter) {
this(Thread.currentThread().getContextClassLoader(), directoryPath, searchSubdirectories, filter);
}
public ResourcesDirectoryReader(ClassLoader classLoader, String directoryPath, ResourcesFilterIF filter) {
this(classLoader, directoryPath, SEARCHSUBDIRECTORIESDEFAULTVALUE, filter);
}
public ResourcesDirectoryReader(ClassLoader classLoader, String directoryPath, boolean searchSubdirectories, ResourcesFilterIF filter) {
this(classLoader, directoryPath, searchSubdirectories);
addFilter(filter);
}
// Constructors with FilenameExtensionFilter shortcuts
public ResourcesDirectoryReader(String directoryPath, String filenameFilter) {
this(directoryPath, SEARCHSUBDIRECTORIESDEFAULTVALUE, filenameFilter);
}
public ResourcesDirectoryReader(String directoryPath, boolean searchSubdirectories, String filenameFilter) {
this(Thread.currentThread().getContextClassLoader(), directoryPath, searchSubdirectories, filenameFilter);
}
public ResourcesDirectoryReader(ClassLoader classLoader, String directoryPath, String filenameFilter) {
this(classLoader, directoryPath, SEARCHSUBDIRECTORIESDEFAULTVALUE, filenameFilter);
}
public ResourcesDirectoryReader(ClassLoader classLoader, String directoryPath, boolean searchSubdirectories, String filenameFilter) {
this(classLoader, directoryPath, searchSubdirectories);
String[] filenameFilters = filenameFilter.split("\\|");
for (String filter : filenameFilters) {
addFilter(new FilenameExtensionFilter(filter));
}
}
public void addFilter(ResourcesFilterIF filter) {
this.filters.add(filter);
}
public Set<String> getResources() {
if (resources == null) {
findResources();
}
return resources;
}
public Set<InputStream> getResourcesAsStreams() {
Set<InputStream> streams = new HashSet<InputStream>();
for (String resource : resources) {
streams.add(classLoader.getResourceAsStream(resource));
}
return streams;
}
private void findResources() {
resources = new TreeSet<String>();
for (URL directoryURL : getResourceDirectories()) {
String protocol = directoryURL.getProtocol();
if ("file".equals(protocol)) {
findResourcesFromFile(directoryURL);
} else if ("jar".equals(protocol)) {
findResourcesFromJar(directoryURL);
} // other protocols not yet supported
}
}
private List<URL> getResourceDirectories() {
try {
Enumeration<URL> directories = classLoader.getResources(directoryPath);
return Collections.list(directories);
} catch (IOException e) {
return Collections.emptyList();
}
}
private void findResourcesFromFile(URL filePath) {
findResourcesFromFile(new File(filePath.getFile()), directoryPath);
}
private void findResourcesFromFile(File directoryFile, String path) {
if (directoryFile.isDirectory()) {
for (File file : directoryFile.listFiles()) {
if (file.isDirectory()) {
if (searchSubdirectories) {
findResourcesFromFile(file, path + file.getName() + "/");
}
} else {
String resourcePath = path + file.getName();
if (filtersApply(resourcePath)) {
resources.add(resourcePath);
}
}
}
}
}
private void findResourcesFromJar(URL jarPath) {
try {
JarURLConnection jarConnection = (JarURLConnection) jarPath.openConnection();
JarFile jarFile = jarConnection.getJarFile();
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String resourcePath = entry.getName();
if ((!entry.isDirectory())
&& (resourcePath.startsWith(directoryPath))
&& (searchSubdirectories || !resourcePath.substring(directoryPath.length()).contains("/"))
&& (filtersApply(resourcePath))) {
resources.add(resourcePath);
}
}
} catch (IOException e) { }
}
private boolean filtersApply(String resourcePath) {
for (ResourcesFilterIF filter : filters) {
if (filter.ok(resourcePath)) {
return true;
}
}
return filters.isEmpty();
}
public interface ResourcesFilterIF {
public boolean ok(String resourcePath);
}
public class FilenameExtensionFilter implements ResourcesFilterIF {
private final String filenameFilter;
public FilenameExtensionFilter(String filenameFilter) {
this.filenameFilter = filenameFilter;
}
public boolean ok(String resourcePath) {
return resourcePath.endsWith(filenameFilter);
}
}
}