Skip to content

Instantly share code, notes, and snippets.

@dangnhdev
Last active February 17, 2018 17:46
Show Gist options
  • Save dangnhdev/09117687ab95e266c7bf to your computer and use it in GitHub Desktop.
Save dangnhdev/09117687ab95e266c7bf to your computer and use it in GitHub Desktop.
package com.activestudy.Utility.file.watchservice;
import java.io.IOException;
import java.nio.file.*;
import java.util.*;
import static java.nio.file.StandardWatchEventKinds.*;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.attribute.BasicFileAttributes;
/**
* A class based on NIO's WatchService to watch entire folder.
*
* @author NguyenHaiDang@ActiveStudy
*/
public class WatchDirService implements Runnable {
private final WatchService watchService;
private final Map<WatchKey, Path> keyPathMap = new HashMap<>();
private final WatchEvent.Kind[] eventKinds;
private Path currentFilePath;
private WatchEventAction onCreatedAction;
private WatchEventAction onModifiedAction;
private WatchEventAction onDeletedAction;
private final boolean all;
public WatchDirService(boolean all, WatchEvent.Kind... eventKinds) {
try {
this.watchService = FileSystems.getDefault().newWatchService();
} catch (IOException ex) {
throw new RuntimeException("Cannot create watch service. Reason: ", ex);
}
this.eventKinds = eventKinds;
this.all = all;
}
/**
* This blocking method continously watch given directories until an
* exception throw or it have no job to do anymore (ex: folder deleted,
* permission changed...)
*
* @throws IOException
* @throws InterruptedException
*/
private void watch() throws IOException, InterruptedException {
MAIN_LOOP:
while (true) {
final WatchKey key = watchService.take();
INNER_LOOP:
for (WatchEvent<?> watchEvent : key.pollEvents()) {
final Kind<?> kind = watchEvent.kind();
WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
Path fileName = watchEventPath.context();
Path parentDir = keyPathMap.get(key);
Path child = parentDir.resolve(fileName);
setCurrentFilePath(child);
if (kind == ENTRY_CREATE) {
if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS) && all) {
registerDir(child);
}
performAction(onCreatedAction);
continue;
}
if (kind == ENTRY_MODIFY) {
performAction(onModifiedAction);
continue;
}
if (kind == ENTRY_DELETE) {
performAction(onDeletedAction);
}
}
boolean validKey = key.reset();
if (!validKey) {
keyPathMap.remove(key);
if (keyPathMap.isEmpty()) {
watchService.close();
break MAIN_LOOP;
}
}
}
}
private void registerPath(Path path) throws IOException {
WatchKey key = path.register(watchService, eventKinds);
keyPathMap.put(key, path);
}
/**
* Register a directory to watch
*
* @param dir Path, the Path object represent the directory
* @throws IOException
*/
public void registerDir(Path dir) throws IOException {
if (Files.isDirectory(dir, LinkOption.NOFOLLOW_LINKS)) {
if (all) {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
registerPath(dir);
return FileVisitResult.CONTINUE;
}
public FileVisitResult visitFileFailed(Path file, IOException exc)
throws IOException {
return FileVisitResult.CONTINUE;
}
});
} else registerPath(dir);
}
}
private void setCurrentFilePath(Path file) {
currentFilePath = file;
}
/**
*
* @return the Path object of the file which is making current event
*/
public Path getCurrentFilePath() {
return currentFilePath;
}
public void setOnCreatedAction(WatchEventAction onCreatedAction) {
this.onCreatedAction = onCreatedAction;
}
public void setOnModifiedAction(WatchEventAction onModifiedAction) {
this.onModifiedAction = onModifiedAction;
}
public void setOnDeletedAction(WatchEventAction onDeletedAction) {
this.onDeletedAction = onDeletedAction;
}
private void performAction(WatchEventAction ea) {
ea.doAction();
}
@Override
public void run() {
try {
watch();
} catch (IOException | InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment