1
+ /*
2
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions
6
+ * are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ *
11
+ * - Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ *
15
+ * - Neither the name of Oracle nor the names of its
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
+ package processing .app .tools ;
33
+
34
+ import java .nio .file .*;
35
+ import static java .nio .file .StandardWatchEventKinds .*;
36
+ import static java .nio .file .LinkOption .*;
37
+ import java .nio .file .attribute .*;
38
+ import java .io .*;
39
+ import java .util .*;
40
+ import processing .app .EditorTab ;
41
+
42
+ /**
43
+ * Example to watch a directory (or tree) for changes to files.
44
+ */
45
+
46
+ public class WatchDir {
47
+
48
+ private final WatchService watcher ;
49
+ private final Map <WatchKey ,Path > keys ;
50
+ private final boolean recursive ;
51
+ private boolean trace = false ;
52
+
53
+ @ SuppressWarnings ("unchecked" )
54
+ static <T > WatchEvent <T > cast (WatchEvent <?> event ) {
55
+ return (WatchEvent <T >)event ;
56
+ }
57
+
58
+ /**
59
+ * Register the given directory with the WatchService
60
+ */
61
+ private void register (Path dir ) throws IOException {
62
+ WatchKey key = dir .register (watcher , ENTRY_CREATE , ENTRY_DELETE , ENTRY_MODIFY );
63
+ if (trace ) {
64
+ Path prev = keys .get (key );
65
+ if (prev == null ) {
66
+ } else {
67
+ if (!dir .equals (prev )) {
68
+ }
69
+ }
70
+ }
71
+ keys .put (key , dir );
72
+ }
73
+
74
+ /**
75
+ * Register the given directory, and all its sub-directories, with the
76
+ * WatchService.
77
+ */
78
+ private void registerAll (final Path start ) throws IOException {
79
+ // register directory and sub-directories
80
+ Files .walkFileTree (start , new SimpleFileVisitor <Path >() {
81
+ @ Override
82
+ public FileVisitResult preVisitDirectory (Path dir , BasicFileAttributes attrs )
83
+ throws IOException
84
+ {
85
+ register (dir );
86
+ return FileVisitResult .CONTINUE ;
87
+ }
88
+ });
89
+ }
90
+
91
+ /**
92
+ * Creates a WatchService and registers the given directory
93
+ */
94
+ public WatchDir (Path dir , boolean recursive ) throws IOException {
95
+ this .watcher = FileSystems .getDefault ().newWatchService ();
96
+ this .keys = new HashMap <WatchKey ,Path >();
97
+ this .recursive = recursive ;
98
+
99
+ if (recursive ) {
100
+ registerAll (dir );
101
+ } else {
102
+ register (dir );
103
+ }
104
+
105
+ // enable trace after initial registration
106
+ this .trace = true ;
107
+ }
108
+
109
+ /**
110
+ * Process all events for keys queued to the watcher
111
+ */
112
+ public void processEvents (EditorTab tab ) {
113
+ for (;;) {
114
+
115
+ // wait for key to be signalled
116
+ WatchKey key ;
117
+ try {
118
+ key = watcher .take ();
119
+ } catch (InterruptedException x ) {
120
+ return ;
121
+ }
122
+
123
+ Path dir = keys .get (key );
124
+ if (dir == null ) {
125
+ continue ;
126
+ }
127
+
128
+ for (WatchEvent <?> event : key .pollEvents ()) {
129
+ WatchEvent .Kind kind = event .kind ();
130
+
131
+ // TBD - provide example of how OVERFLOW event is handled
132
+ if (kind == OVERFLOW ) {
133
+ continue ;
134
+ }
135
+
136
+ // Context for directory entry event is the file name of entry
137
+ WatchEvent <Path > ev = cast (event );
138
+ Path name = ev .context ();
139
+ Path child = dir .resolve (name );
140
+
141
+ // reload the tab content
142
+ tab .reload ();
143
+
144
+ // if directory is created, and watching recursively, then
145
+ // register it and its sub-directories
146
+ if (recursive && (kind == ENTRY_CREATE )) {
147
+ try {
148
+ if (Files .isDirectory (child , NOFOLLOW_LINKS )) {
149
+ registerAll (child );
150
+ }
151
+ } catch (IOException x ) {
152
+ // ignore to keep sample readbale
153
+ }
154
+ }
155
+ }
156
+
157
+ // reset key and remove from set if directory no longer accessible
158
+ boolean valid = key .reset ();
159
+ if (!valid ) {
160
+ keys .remove (key );
161
+
162
+ // all directories are inaccessible
163
+ if (keys .isEmpty ()) {
164
+ break ;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
0 commit comments