| /* |
| * Copyright (c) 2008, 2011, Oracle and/or its affiliates. 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 Oracle 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. |
| */ |
| |
| /* |
| * This source code is provided to illustrate the usage of a given feature |
| * or technique and has been deliberately simplified. Additional steps |
| * required for a production-quality application, such as security checks, |
| * input validation and proper error handling, might not be present in |
| * this sample code. |
| */ |
| |
| |
| import java.nio.file.*; |
| import static java.nio.file.StandardWatchEventKinds.*; |
| import static java.nio.file.LinkOption.*; |
| import java.nio.file.attribute.*; |
| import java.io.IOException; |
| |
| /** |
| * Example to watch a directory (or tree) for changes to files. |
| */ |
| |
| public class WatchDir { |
| |
| private final WatchService watcher; |
| private final boolean recursive; |
| private boolean trace = false; |
| private int count; |
| |
| @SuppressWarnings("unchecked") |
| static <T> WatchEvent<T> cast(WatchEvent<?> event) { |
| return (WatchEvent<T>)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); |
| count++; |
| if (trace) |
| System.out.format("register: %s\n", 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<Path>() { |
| @Override |
| public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) |
| throws IOException |
| { |
| register(dir); |
| return FileVisitResult.CONTINUE; |
| } |
| }); |
| } |
| |
| /** |
| * Creates a WatchService and registers the given directory |
| */ |
| WatchDir(Path dir, boolean recursive) throws IOException { |
| this.watcher = FileSystems.getDefault().newWatchService(); |
| 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; |
| } |
| |
| 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<Path> ev = cast(event); |
| Path name = ev.context(); |
| Path child = ((Path)key.watchable()).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 (Files.isDirectory(child, NOFOLLOW_LINKS)) { |
| registerAll(child); |
| } |
| } catch (IOException x) { |
| // ignore to keep sample readbale |
| } |
| } |
| } |
| |
| // reset key |
| boolean valid = key.reset(); |
| if (!valid) { |
| // directory no longer accessible |
| count--; |
| if (count == 0) |
| 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(); |
| } |
| } |