diff -r 115e09b7a004 -r 3acf8e5e2ca0 jdk/src/share/sample/nio/file/WatchDir.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/file/WatchDir.java Sun Feb 15 12:25:54 2009 +0000 @@ -0,0 +1,196 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.nio.file.*; +import static java.nio.file.StandardWatchEventKind.*; +import static java.nio.file.LinkOption.*; +import java.nio.file.attribute.*; +import java.io.*; +import java.util.*; + +/** + * Example to watch a directory (or tree) for changes to files. + */ + +public class WatchDir { + + private final WatchService watcher; + private final Map keys; + private final boolean recursive; + private boolean trace = false; + + @SuppressWarnings("unchecked") + static WatchEvent cast(WatchEvent event) { + return (WatchEvent)event; + } + + /** + * Register the given directory with the WatchService + */ + private void register(Path dir) throws IOException { + WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + if (trace) { + FileRef prev = keys.get(key); + if (prev == null) { + System.out.format("register: %s\n", dir); + } else { + if (!dir.equals(prev)) { + System.out.format("update: %s -> %s\n", prev, dir); + } + } + } + keys.put(key, dir); + } + + /** + * Register the given directory, and all its sub-directories, with the + * WatchService. + */ + private void registerAll(final Path start) throws IOException { + // register directory and sub-directories + Files.walkFileTree(start, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir) { + try { + register(dir); + } catch (IOException x) { + throw new IOError(x); + } + return FileVisitResult.CONTINUE; + } + }); + } + + /** + * Creates a WatchService and registers the given directory + */ + WatchDir(Path dir, boolean recursive) throws IOException { + this.watcher = FileSystems.getDefault().newWatchService(); + this.keys = new HashMap(); + this.recursive = recursive; + + if (recursive) { + System.out.format("Scanning %s ...\n", dir); + registerAll(dir); + System.out.println("Done."); + } else { + register(dir); + } + + // enable trace after initial registration + this.trace = true; + } + + /** + * Process all events for keys queued to the watcher + */ + void processEvents() { + for (;;) { + + // wait for key to be signalled + WatchKey key; + try { + key = watcher.take(); + } catch (InterruptedException x) { + return; + } + + Path dir = keys.get(key); + if (dir == null) { + System.err.println("WatchKey not recognized!!"); + continue; + } + + for (WatchEvent event: key.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + + // TBD - provide example of how OVERFLOW event is handled + if (kind == OVERFLOW) { + continue; + } + + // Context for directory entry event is the file name of entry + WatchEvent ev = cast(event); + Path name = ev.context(); + Path child = dir.resolve(name); + + // print out event + System.out.format("%s: %s\n", event.kind().name(), child); + + // if directory is created, and watching recursively, then + // register it and its sub-directories + if (recursive && (kind == ENTRY_CREATE)) { + try { + if (Attributes.readBasicFileAttributes(child, NOFOLLOW_LINKS).isDirectory()) { + registerAll(child); + } + } catch (IOException x) { + // ignore to keep sample readbale + } + } + } + + // reset key and remove from set if directory no longer accessible + boolean valid = key.reset(); + if (!valid) { + keys.remove(key); + + // all directories are inaccessible + if (keys.isEmpty()) { + break; + } + } + } + } + + static void usage() { + System.err.println("usage: java WatchDir [-r] dir"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + // parse arguments + if (args.length == 0 || args.length > 2) + usage(); + boolean recursive = false; + int dirArg = 0; + if (args[0].equals("-r")) { + if (args.length < 2) + usage(); + recursive = true; + dirArg++; + } + + // register directory and process its events + Path dir = Paths.get(args[dirArg]); + new WatchDir(dir, recursive).processEvents(); + } +}