Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Watch Service Java 7 polling loop

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?

like image 586
Alex Kreutznaer Avatar asked Jun 05 '13 22:06

Alex Kreutznaer


3 Answers

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.

like image 163
David says Reinstate Monica Avatar answered Nov 01 '22 04:11

David says Reinstate Monica


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.

like image 21
Silly Freak Avatar answered Nov 01 '22 03:11

Silly Freak


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.

like image 3
Alexei Kaigorodov Avatar answered Nov 01 '22 04:11

Alexei Kaigorodov