package org.nigajuan.springloaded;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by nigajuan on 10/02/14.
*/
public class FilesystemWatcher {
private static final Logger log = LoggerFactory.getLogger(FilesystemWatcher.class);
public static final String CLASS_EXTENSION = ".class";
private Path basePath;
private Map<String, Long> loadedFiles = new ConcurrentHashMap<>();
public FilesystemWatcher() throws URISyntaxException {
basePath = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).toPath();
}
public FilesystemWatcher(Path basePath) {
this.basePath = basePath;
}
public void init() throws IOException {
Files.walkFileTree(basePath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String fullPath = file.toString();
if (isClassFile(fullPath)) {
loadedFiles.put(keyFromPath(file), attrs.lastModifiedTime().toMillis());
}
return FileVisitResult.CONTINUE;
}
});
}
public void scan() throws IOException {
final List<ToReloadFile> modifiedFiles = new ArrayList<>();
Files.walkFileTree(basePath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
loadClass(file, attrs, modifiedFiles);
return FileVisitResult.CONTINUE;
}
});
for (ToReloadFile toReloadFile : modifiedFiles) {
try {
if (toReloadFile.isLoad()) {
getClass().getClassLoader().loadClass(toReloadFile.getDotted());
}
if (toReloadFile.isReload()) {
//Force reload to trigger the event
long modifiedDate = new Date().getTime();
Files.setLastModifiedTime(toReloadFile.getFile(), FileTime.fromMillis(modifiedDate));
loadedFiles.put(keyFromPath(toReloadFile.getFile()), modifiedDate);
}
} catch (ClassNotFoundException e) {
log.error(e.getMessage(), e);
}
}
}
private void loadClass(Path file, BasicFileAttributes attrs, List<ToReloadFile> modifiedFiles) throws IOException {
String fullPath = file.toString();
if (isClassFile(fullPath)) {
if (!loadedFiles.containsKey(fullPath)) {
String dotted = basePath.relativize(file).toString().replaceAll("[\\\\/]", ".").replace(CLASS_EXTENSION, "");
modifiedFiles.add(new ToReloadFile(file, dotted, true, true));
} else if (loadedFiles.get(fullPath) != attrs.lastModifiedTime().toMillis()) {
modifiedFiles.add(new ToReloadFile(file, null, false, true));
}
}
}
private boolean isClassFile(String path) {
return path.endsWith(CLASS_EXTENSION);
}
private String keyFromPath(Path path) {
return path.toString();
}
}