package net.demilich.metastone.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ResourceLoader {
// the number of dirs levels to traverse on the given path
private static final int DIR_LEVELS = 5;
private static Logger logger = LoggerFactory.getLogger(ResourceLoader.class);
/**
* Loads all the json files from the given rootDir into a collection of
* ResourceInputStreams
*
* @param rootDir
* the root dir from where to start traversing to load the json
* files
* @param fromFileSystem
* True if the rootDir is on the filesystem, False if the rootDir
* is in the Resources dir
* @return Collections of ResourceInputStreams pointing to the json files
* @throws URISyntaxException
* @throws IOException
*/
public static Collection<ResourceInputStream> loadJsonInputStreams(String rootDir, boolean fromFileSystem)
throws URISyntaxException, IOException {
if (rootDir == null) {
throw new RuntimeException("rootDir cannot be null");
}
PathReference pathReference;
if (fromFileSystem) {
pathReference = new PathReference(Paths.get(rootDir), false);
} else { // from resources
pathReference = getPathFromResources(rootDir);
}
Collection<ResourceInputStream> inputStreams = new ArrayList<>();
Path filePath;
Stream<Path> walk = Files.walk(pathReference.path, DIR_LEVELS);
for (Iterator<Path> it = walk.iterator(); it.hasNext();) {
filePath = it.next();
// skip over non-json files and directories
if (!filePath.toString().endsWith("json"))
continue;
InputStream inputStream;
if (pathReference.fromJar) {
inputStream = Object.class.getResourceAsStream(filePath.toString());
} else {
inputStream = new FileInputStream(new File(filePath.toString()));
}
inputStreams.add(new ResourceInputStream(filePath.getFileName().toString(), inputStream, fromFileSystem));
}
walk.close();
return inputStreams;
}
/**
* Utility method to get a PathReference from a given sourceDir that's in
* the Resources dir or a Jar file.
*
* @param sourceDir
* the dir of interest in the Resources dir or Jar file
* @return a PathReference which contains a Path and boolean indicating the
* path is in a Jar fle.
* @throws URISyntaxException
* @throws IOException
*/
private static PathReference getPathFromResources(String sourceDir) throws URISyntaxException, IOException {
URI uri;
try {
uri = Object.class.getResource("/" + sourceDir).toURI();
} catch (NullPointerException ex) {
logger.error(sourceDir + " directory not found in resources");
throw new RuntimeException(sourceDir + " directory not found in resources");
}
// handle case where resources are on the filesystem instead of jar. ie:
// running form within IntelliJ
boolean fromJar = uri.getScheme().equals("jar");
Path path;
FileSystem fileSystem;
if (fromJar) { // from jar file on the classpath
try {
fileSystem = FileSystems.getFileSystem(uri);
} catch (FileSystemNotFoundException ex) {
fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object> emptyMap());
}
path = fileSystem.getPath(sourceDir);
} else { // from resources folder on the filesystem
path = Paths.get(uri);
}
return new PathReference(path, fromJar);
}
/**
* Copy all files from the Resources sourceDir subfolder to the targetDir on
* the filesystem.
*
* @param sourceDir
* path to dir who's contents to copy
* @param targetdir
* path to dir where we want to copy the files to
* @throws URISyntaxException
* @throws IOException
*/
public static void copyFromResources(final String sourceDir, final String targetdir) throws URISyntaxException, IOException {
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
URL cardsUrl = null;
String jarFileName = null;
for (URL url : urls) {
jarFileName = new File(url.toURI()).getName();
if (jarFileName.startsWith("cards")) {
cardsUrl = url;
break;
}
}
final String cardsJarFile = jarFileName;
final PathReference sourcePathReference = getPathFromResources(sourceDir);
final Path targetDirPath = Paths.get(targetdir);
logger.info("Copying resources from " + cardsUrl + " to " + targetDirPath);
Files.walkFileTree(sourcePathReference.path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
//Path currentTargetDir = Paths.get(targetDirPath.toString() + File.separator + dir.getFileName());
String relativePath = dir.toString().replace(sourcePathReference.path.toString(), "");
Path currentTargetDir = Paths.get(targetDirPath + relativePath);
Files.createDirectories(currentTargetDir);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
String relativePath = file.toString().replace(sourcePathReference.path.toString(), "");
Path currentTargetFile = Paths.get(targetDirPath + relativePath);
logger.info(cardsJarFile + "!" + file + " --> " + currentTargetFile);
Files.copy(file, currentTargetFile, StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
});
}
/**
* Data tuple which holds a path and boolean flag indicating that the path
* is from a jar resource file.
*/
private static class PathReference {
final Path path;
final boolean fromJar;
public PathReference(Path path, boolean fromJar) {
this.path = path;
this.fromJar = fromJar;
}
}
}