I was a bit surprised that Watch Service should be implemented as a process/thread with a polling loop. I don't remember any other API in Java that is supposed to do it.
Wouldn't it be much better to implement it as a set of callbacks (listeners, observers, etc..)?
BTW - is there any third-party library that does pretty much the same, but using callbacks model?
Apache Commons has some file watching services which I think are much better than the ones in Java 7. Im not sure if they use callbacks, but they are much more intuitive in my opinion.
And yes, I think that an observer model would be much better. I read somewhere that its a bit tougher to do this with Java because it runs through a virtual machine, and to get listeners on files you need to talk directly to the OS. Im not sure of the details or validity of this though.
I build on Alexeis answer, but I don't think he was clear enough... look at this example code:
WatchService service = dir.getFileSystem().newWatchService();
WatchKey key = dir.register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
System.out.println(key);
for(;;) {
WatchKey k = service.take();
System.out.println(k);
for(WatchEvent<?> ev:k.pollEvents()) {
System.out.println(ev.kind());
if(ev.kind() == OVERFLOW) continue;
//TODO
System.out.println(ev.context());
}
if(!k.reset()) break;
}
key.cancel();
If you check the println(key) / println(k) outputs, you'll see that the same object is returned over and over; take() returns every time that key is signalled, so to use multiple keys with the same WatchService, just check what key was returned every time. That also means that your loop blocks as long as the key was not signalled - exactly what you want.
the if(!k.reset()) break; is crucial too; this is what I forgot when writing my comment on Alexeis answer. My assumption was that take() is called by register(), and thus no key should be returned in my user code, because register() already consumed it. With that mis-assumption, I didn't recognize what was actually going on.
You don't have to use polling, you can use WatchService.take(), which returns immediately when a change occur. Yes it requires a thread, but single thread can be used for multiple objects being watched. So it is easy to implement a singleton which owns a watching thread and allows to register callbacks for each object.
As for third party libraries, look at Guava EventBus. I did not try it and am not sure if it fits your needs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With