Wednesday, April 24, 2013

Java7 NIO WatchService

Java 7: NIO WatchService

In my previous post I have written many of the Java 7 features for developing Java Telnet Server.
Here I want to go deep into one such feature WatchService.

The WatchService is a very interesting feature of the new java.nio.file package in Java 7.
One of the more interesting is the WatchService, adding the capability to watch a directory for changes.
   
The WatchService maps directly to the native file event notification mechanism, if available. If a native event notification mechanism is not available, then the default implementation will use polling. As a result, the responsiveness, ordering of events and details available are implementation specific.
 
Source Code:

Watching Directory:
We have to create a File Path for the specific directory we want to watch.
Path:
    Path faxFolder = Paths.get("C:\\foo");

The Path interface implements the register method that takes a WatchService object and varargs of type WatchEvent.Kind as arguments. There are 4 events to watch for:
ENTRY_CREATE
ENTRY_DELETE
ENTRY_MODIFY
OVERFLOW
While the first 3 types are easy to understand, OVERFLOW indicates that events may been lost or discarded. A WatchService is created by calling FileSystem.newWatchService().
Watching a directory is accomplished by registering a Path object with the WatchService:

WatchService watchService = FileSystems.getDefault().newWatchService();
 
faxFolder.register(watchService,   StandardWatchEventKinds.ENTRY_CREATE,  StandardWatchEventKinds.ENTRY_DELETE, 
StandardWatchEventKinds.ENTRY_MODIFY);

WatchKey watchKey = watchService.take();

As you can see above code register method returns a watchKey.  The WatchKey is a token that represents the registration of the Path with the WatchService.

The WatchKey
As a result of the registration process, the WatchKey is in a ‘ready’ state and is considered valid. A WatchKey remains valid until one of the following occurs:
  1. WatchKey.cancel() is called.
  2. The directory being watched is no longer available.
  3. The WatchService object is closed.
Checking For Changes
When a change is detected, the WatchKey state is set to ‘signaled’ and it is placed in a queue for processing.  Getting WatchKeys off the queue involves calling WatchService.poll() or
WatchService.take().
Here is a basic example:
WatchKey watchKey = watchService.poll(60,TimeUnit.SECONDS);
 //this will retrieve all the events for this watch key
List<WatchEvent.Kind<?>> events = watchKey.pollEvents(); 


boolean value = watchKey.reset()

The "reset" method sets the WatchKey state back to 'ready'(meaning listen for events) and returns a boolean indicating if the WatchKey is still valid. If there are any pending events, then the WatchKey will be re-queued, otherwise it will remain in the ready state until new events are detected.

How to process events
Now that we have detected an event, how do we determine:
  1. On which directory did the event happen? (assuming more than one directory registered)
  2. What was the actual event? (assuming listening for more than one event)
  3. What was the target of the event, i.e what Path object was created,deleted or updated?
//WatchKey watchable returns the calling Path object of Path.register
 Path watchedPath = (Path) watchKey.watchable();

for (WatchEvent<?> event : watchKey.pollEvents()) {
   
   //returns the event type
     StandardWatchEventKinds eventKind = event.kind();
  
   //returns the context of the event
     Path target = (Path)event.context();
}


There are two things that about the WatchService.
The WatchService does not pick up events for sub-directories of a watched directory.
We still need to poll the WatchService for events, rather than receive asynchronous notification.


 Here is the sample output:




No comments:

Post a Comment