16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 import java.nio.file.*; 33 import static java.nio.file.StandardWatchEventKind.*; 34 import static java.nio.file.LinkOption.*; 35 import java.nio.file.attribute.*; 36 import java.io.*; 37 import java.util.*; 38 39 /** 40 * Example to watch a directory (or tree) for changes to files. 41 */ 42 43 public class WatchDir { 44 45 private final WatchService watcher; 46 private final Map<WatchKey,Path> keys; 47 private final boolean recursive; 48 private boolean trace = false; 49 50 @SuppressWarnings("unchecked") 51 static <T> WatchEvent<T> cast(WatchEvent<?> event) { 52 return (WatchEvent<T>)event; 53 } 54 55 /** 56 * Register the given directory with the WatchService 57 */ 58 private void register(Path dir) throws IOException { 59 WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); 60 if (trace) { 61 Path prev = keys.get(key); 62 if (prev == null) { 63 System.out.format("register: %s\n", dir); 64 } else { 65 if (!dir.equals(prev)) { 66 System.out.format("update: %s -> %s\n", prev, dir); 67 } 68 } 69 } 70 keys.put(key, dir); 71 } 72 73 /** 74 * Register the given directory, and all its sub-directories, with the 75 * WatchService. 76 */ 77 private void registerAll(final Path start) throws IOException { 78 // register directory and sub-directories 79 Files.walkFileTree(start, new SimpleFileVisitor<Path>() { 80 @Override 81 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) 82 throws IOException 83 { 84 register(dir); 85 return FileVisitResult.CONTINUE; 86 } 87 }); 88 } 89 90 /** 91 * Creates a WatchService and registers the given directory 92 */ 93 WatchDir(Path dir, boolean recursive) throws IOException { 94 this.watcher = FileSystems.getDefault().newWatchService(); 95 this.keys = new HashMap<WatchKey,Path>(); 96 this.recursive = recursive; 97 98 if (recursive) { 99 System.out.format("Scanning %s ...\n", dir); 100 registerAll(dir); 101 System.out.println("Done."); 102 } else { 103 register(dir); 104 } 105 106 // enable trace after initial registration 107 this.trace = true; 108 } 109 110 /** 111 * Process all events for keys queued to the watcher 112 */ 113 void processEvents() { 114 for (;;) { 115 116 // wait for key to be signalled 117 WatchKey key; 118 try { 119 key = watcher.take(); 120 } catch (InterruptedException x) { 121 return; 122 } 123 124 Path dir = keys.get(key); 125 if (dir == null) { 126 System.err.println("WatchKey not recognized!!"); 127 continue; 128 } 129 130 for (WatchEvent<?> event: key.pollEvents()) { 131 WatchEvent.Kind kind = event.kind(); 132 133 // TBD - provide example of how OVERFLOW event is handled 134 if (kind == OVERFLOW) { 135 continue; 136 } 137 138 // Context for directory entry event is the file name of entry 139 WatchEvent<Path> ev = cast(event); 140 Path name = ev.context(); 141 Path child = dir.resolve(name); 142 143 // print out event 144 System.out.format("%s: %s\n", event.kind().name(), child); 145 146 // if directory is created, and watching recursively, then 147 // register it and its sub-directories 148 if (recursive && (kind == ENTRY_CREATE)) { 149 try { 150 if (Files.isDirectory(child, NOFOLLOW_LINKS)) { 151 registerAll(child); 152 } 153 } catch (IOException x) { 154 // ignore to keep sample readbale 155 } 156 } 157 } 158 159 // reset key and remove from set if directory no longer accessible 160 boolean valid = key.reset(); 161 if (!valid) { 162 keys.remove(key); 163 164 // all directories are inaccessible 165 if (keys.isEmpty()) { 166 break; 167 } 168 } 169 } 170 } 171 172 static void usage() { 173 System.err.println("usage: java WatchDir [-r] dir"); 174 System.exit(-1); 175 } 176 177 public static void main(String[] args) throws IOException { 178 // parse arguments 179 if (args.length == 0 || args.length > 2) 180 usage(); 181 boolean recursive = false; 182 int dirArg = 0; 183 if (args[0].equals("-r")) { 184 if (args.length < 2) 185 usage(); 186 recursive = true; 187 dirArg++; 188 } 189 | 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 import java.nio.file.*; 33 import static java.nio.file.StandardWatchEventKind.*; 34 import static java.nio.file.LinkOption.*; 35 import java.nio.file.attribute.*; 36 import java.io.IOException; 37 38 /** 39 * Example to watch a directory (or tree) for changes to files. 40 */ 41 42 public class WatchDir { 43 44 private final WatchService watcher; 45 private final boolean recursive; 46 private boolean trace = false; 47 private int count; 48 49 @SuppressWarnings("unchecked") 50 static <T> WatchEvent<T> cast(WatchEvent<?> event) { 51 return (WatchEvent<T>)event; 52 } 53 54 /** 55 * Register the given directory with the WatchService 56 */ 57 private void register(Path dir) throws IOException { 58 WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); 59 count++; 60 if (trace) 61 System.out.format("register: %s\n", dir); 62 } 63 64 /** 65 * Register the given directory, and all its sub-directories, with the 66 * WatchService. 67 */ 68 private void registerAll(final Path start) throws IOException { 69 // register directory and sub-directories 70 Files.walkFileTree(start, new SimpleFileVisitor<Path>() { 71 @Override 72 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) 73 throws IOException 74 { 75 register(dir); 76 return FileVisitResult.CONTINUE; 77 } 78 }); 79 } 80 81 /** 82 * Creates a WatchService and registers the given directory 83 */ 84 WatchDir(Path dir, boolean recursive) throws IOException { 85 this.watcher = FileSystems.getDefault().newWatchService(); 86 this.recursive = recursive; 87 88 if (recursive) { 89 System.out.format("Scanning %s ...\n", dir); 90 registerAll(dir); 91 System.out.println("Done."); 92 } else { 93 register(dir); 94 } 95 96 // enable trace after initial registration 97 this.trace = true; 98 } 99 100 /** 101 * Process all events for keys queued to the watcher 102 */ 103 void processEvents() { 104 for (;;) { 105 106 // wait for key to be signalled 107 WatchKey key; 108 try { 109 key = watcher.take(); 110 } catch (InterruptedException x) { 111 return; 112 } 113 114 for (WatchEvent<?> event: key.pollEvents()) { 115 WatchEvent.Kind kind = event.kind(); 116 117 // TBD - provide example of how OVERFLOW event is handled 118 if (kind == OVERFLOW) { 119 continue; 120 } 121 122 // Context for directory entry event is the file name of entry 123 WatchEvent<Path> ev = cast(event); 124 Path name = ev.context(); 125 Path child = ((Path)key.watchable()).resolve(name); 126 127 // print out event 128 System.out.format("%s: %s\n", event.kind().name(), child); 129 130 // if directory is created, and watching recursively, then 131 // register it and its sub-directories 132 if (recursive && (kind == ENTRY_CREATE)) { 133 try { 134 if (Files.isDirectory(child, NOFOLLOW_LINKS)) { 135 registerAll(child); 136 } 137 } catch (IOException x) { 138 // ignore to keep sample readbale 139 } 140 } 141 } 142 143 // reset key 144 boolean valid = key.reset(); 145 if (!valid) { 146 // directory no longer accessible 147 count--; 148 if (count == 0) 149 break; 150 } 151 } 152 } 153 154 static void usage() { 155 System.err.println("usage: java WatchDir [-r] dir"); 156 System.exit(-1); 157 } 158 159 public static void main(String[] args) throws IOException { 160 // parse arguments 161 if (args.length == 0 || args.length > 2) 162 usage(); 163 boolean recursive = false; 164 int dirArg = 0; 165 if (args[0].equals("-r")) { 166 if (args.length < 2) 167 usage(); 168 recursive = true; 169 dirArg++; 170 } 171 |