package fr.ens.biologie.genomique.eoulsan.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static fr.ens.biologie.genomique.eoulsan.EoulsanLogger.getLogger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceConfigurationError;
import fr.ens.biologie.genomique.eoulsan.EoulsanException;
import fr.ens.biologie.genomique.eoulsan.data.DataFile;
/**
* This class allow to define a resource loader for files.
* @param <S> Type of the data to load
* @author Laurent Jourdren
* @since 2.0
*/
public abstract class FileResourceLoader<S> extends AbstractResourceLoader<S> {
private final static String INDEX_FILE = "INDEX";
private final Class<S> clazz;
private final List<DataFile> directories = new ArrayList<>();
//
// Abstract methods
//
/**
* Get the extension of the files to load.
* @return the extension of the files to load
*/
protected abstract String getExtension();
//
// Resources loading
//
@Override
protected InputStream getResourceAsStream(final String resourcePath)
throws IOException {
checkNotNull(resourcePath, "resourcePath argument cannot be null");
return new DataFile(resourcePath).open();
}
@Override
public void reload() {
if (this.directories.isEmpty()) {
return;
}
try {
for (DataFile directory : this.directories) {
for (String filename : findResourcePaths(directory)) {
getLogger().fine("Try to load "
+ this.clazz.getSimpleName() + " from " + filename + " resource");
final DataFile file = new DataFile(directory, filename);
final S resource = load(file.open(), file.getSource());
if (resource == null) {
throw new EoulsanException("Cannot load resource: " + file);
}
final String resourceName = getResourceName(resource);
if (resourceName == null) {
throw new EoulsanException(
"Cannot get resource name for resource: " + resource);
}
addResource(resourceName, file.getSource());
}
}
} catch (IOException | EoulsanException e) {
throw new ServiceConfigurationError("Unable to load resource", e);
}
}
/**
* Find the resource to load.
* @param directory the directory where loading the resources
* @return a list of relative paths
* @throws IOException if an error occrs while finding the resource
*/
private List<String> findResourcePaths(final DataFile directory)
throws IOException {
final DataFile indexFile = new DataFile(directory, INDEX_FILE);
if (indexFile.exists()) {
return findResourcePathInIndexFile(indexFile);
}
return findResourcePathInDirectory(directory);
}
/**
* Find resources in an index file.
* @param indexFile the index where getting resources
* @return a list with the list of the resources to load
*/
private List<String> findResourcePathInIndexFile(final DataFile indexFile)
throws IOException {
final List<String> result = new ArrayList<>();
try (BufferedReader reader =
FileUtils.createBufferedReader(indexFile.open())) {
String line = null;
while ((line = reader.readLine()) != null) {
final String trimLine = line.trim();
if ("".equals(trimLine) || trimLine.startsWith("#")) {
continue;
}
result.add(trimLine);
}
}
return result;
}
/**
* Find resources in a directory.
* @param directory the directory where search resources
* @return a list with the list of the resources to load
*/
private List<String> findResourcePathInDirectory(final DataFile directory) {
final List<String> result = new ArrayList<>();
final String extension = getExtension() == null ? "" : getExtension();
try {
for (DataFile file : directory.list()) {
final String filename = file.getName();
if (!filename.startsWith(".")
&& filename.toLowerCase().endsWith(extension.toLowerCase())) {
result.add(file.getName());
}
}
} catch (IOException e) {
// The protocol is not browsable, do nothing
}
return result;
}
//
// Resource path management
//
/**
* Add a resource paths.
* @param resourcePaths the resource path to add
*/
public void addResourcePaths(final String resourcePaths) {
checkNotNull(resourcePaths, "resourcePaths argument cannot be null");
for (String directory : resourcePaths.split(" ")) {
directory = directory.trim();
if (!directory.isEmpty()) {
addResourcePath(new DataFile(directory));
}
}
}
/**
* Add a resource path.
* @param resourcePath the resource path to add
*/
public void addResourcePath(final DataFile resourcePath) {
checkNotNull(resourcePath, "baseDir argument cannot be null");
this.directories.add(resourcePath);
}
/**
* Add a resource path.
* @param resourcePath the resource path to remove
* @return true if the resource has been successfully removed
*/
public boolean removeResourcePath(final DataFile resourcePath) {
checkNotNull(resourcePath, "baseDir argument cannot be null");
return this.directories.remove(resourcePath);
}
//
// Public constructor
//
/**
* Public constructor.
* @param clazz the Class type of the resource to load @param resourcePath the
* path to the resource to load
*/
public FileResourceLoader(final Class<S> clazz, final DataFile resourcePath) {
checkNotNull(clazz, "clazz argument cannot be null");
this.clazz = clazz;
addResourcePath(resourcePath);
}
}