I'm trying to synchronize two folders and their sub directories between a client and a server. I have a modified version of this class which I've posted below. In my Client class, I create a WatchDir object and call its processEvents()
method in an infinite loop.
The method returns a myTuple
object (a struct containing the event type and a path object) if an event is registered and null if not. The problem is that this only seems to work for the first event to happen in the directory (i.e. if I add a file to the watched folder, my WatchDir object.processEvents()
returns one Tuple with an ENTRY_CREATE
event and never returns another Tuple for other file additions/deletions/modifications that happen after). I'd like for processEvents
to be continuously called (hence the infinite while) returning a Tuple each time some event occurs.
My modified WatchDir:
import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.LinkOption.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class WatchDir {
private final WatchService watcher;
private final Map<WatchKey,Path> keys;
private final boolean recursive;
private boolean trace = false;
public WatchDir(Path dir, boolean recursive) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.keys = new HashMap<WatchKey,Path>(); //holds the key for each subdirectory
this.recursive = true;
registerAll(dir);
}
public void registerAll(Path start) throws IOException {
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
register(dir);
return FileVisitResult.CONTINUE;
}
});
}
public void register(Path dir) throws IOException {
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
keys.put(key, dir);
}
public myTuple processEvents() {
WatchKey key;
//while (true) {
try {
key = watcher.take();
} catch (InterruptedException e) {
return new myTuple("INTERRUPTED", null);
}
Path dir = keys.get(key); //get next subdirectory path
if (dir == null)
return new myTuple("NULL DIRECTORY", null);
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind kind = event.kind();
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
return new myTuple(event.kind().name(), child);
}
return null;
//}
}
@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>)event;
}
}
My Client:
import java.nio.file.attribute.*;
import java.nio.file.*;
import java.util.concurrent.TimeUnit;
public class newClient {
public static void main(String[] args) throws IOException {
Path folder = Paths.get(System.getProperty("user.dir"));
WatchDir watcher = new WatchDir(folder, true);
myTuple thisTuple;
while (true) {
thisTuple = watcher.processEvents();
String event = thisTuple.getEvent();
Path path = thisTuple.getPath();
System.out.println(event+": "+path.toString());
}
}
}
You don't reset the key. Read the docs again:
Once the events have been processed the consumer invokes the key's reset method to reset the key which allows the key to be signalled and re-queued with further events.
Probably here
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind kind = event.kind();
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
return new myTuple(event.kind().name(), child);
}
key.reset();
return null;