1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jci.monitor;
19
20 import java.io.File;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30
31
32
33
34
35 public class FilesystemAlterationObserverImpl implements FilesystemAlterationObserver {
36
37 private final Log log = LogFactory.getLog(FilesystemAlterationObserverImpl.class);
38
39 private interface MonitorFile {
40
41 long lastModified();
42 MonitorFile[] listFiles();
43 boolean isDirectory();
44 boolean exists();
45 String getName();
46
47 }
48
49 private final static class MonitorFileImpl implements MonitorFile {
50
51 private final File file;
52
53 public MonitorFileImpl( final File pFile ) {
54 file = pFile;
55 }
56
57 public boolean exists() {
58 return file.exists();
59 }
60
61 public MonitorFile[] listFiles() {
62 final File[] childs = file.listFiles();
63
64 final MonitorFile[] providers = new MonitorFile[childs.length];
65 for (int i = 0; i < providers.length; i++) {
66 providers[i] = new MonitorFileImpl(childs[i]);
67 }
68 return providers;
69 }
70
71 public String getName() {
72 return file.getName();
73 }
74
75 public boolean isDirectory() {
76 return file.isDirectory();
77 }
78
79 public long lastModified() {
80 return file.lastModified();
81 }
82
83 public String toString() {
84 return file.toString();
85 }
86
87 }
88
89 private final class Entry {
90
91 private final static int TYPE_UNKNOWN = 0;
92 private final static int TYPE_FILE = 1;
93 private final static int TYPE_DIRECTORY = 2;
94
95 private final MonitorFile file;
96 private long lastModified = -1;
97 private int lastType = TYPE_UNKNOWN;
98 private Map childs = new HashMap();
99
100 public Entry(final MonitorFile pFile) {
101 file = pFile;
102 }
103
104 public String getName() {
105 return file.getName();
106 }
107
108
109 public String toString() {
110 return file.toString();
111 }
112
113
114 private void compareChilds() {
115 if (!file.isDirectory()) {
116 return;
117 }
118
119 final MonitorFile[] files = file.listFiles();
120 final Set deleted = new HashSet(childs.values());
121 for (int i = 0; i < files.length; i++) {
122 final MonitorFile f = files[i];
123 final String name = f.getName();
124 final Entry entry = (Entry)childs.get(name);
125 if (entry != null) {
126
127 deleted.remove(entry);
128
129 if(entry.needsToBeDeleted()) {
130
131 childs.remove(name);
132 }
133 } else {
134
135 final Entry newChild = new Entry(f);
136 childs.put(name, newChild);
137 newChild.needsToBeDeleted();
138 }
139 }
140
141
142
143 for (Iterator it = deleted.iterator(); it.hasNext();) {
144 final Entry entry = (Entry) it.next();
145 entry.deleteChildsAndNotify();
146 childs.remove(entry.getName());
147 }
148 }
149
150
151 private void deleteChildsAndNotify() {
152 for (Iterator it = childs.values().iterator(); it.hasNext();) {
153 final Entry entry = (Entry) it.next();
154
155 entry.deleteChildsAndNotify();
156 }
157 childs.clear();
158
159 if(lastType == TYPE_DIRECTORY) {
160 notifyOnDirectoryDelete(this);
161 } else if (lastType == TYPE_FILE) {
162 notifyOnFileDelete(this);
163 }
164 }
165
166 public boolean needsToBeDeleted() {
167
168 if (!file.exists()) {
169
170
171
172
173 deleteChildsAndNotify();
174
175
176 return true;
177 } else {
178
179 final long currentModified = file.lastModified();
180
181 if (currentModified != lastModified) {
182
183 lastModified = currentModified;
184
185
186
187
188 final int newType = (file.isDirectory()?TYPE_DIRECTORY:TYPE_FILE);
189
190 if (lastType != newType) {
191
192
193
194
195 deleteChildsAndNotify();
196
197 lastType = newType;
198
199
200
201 if (newType == TYPE_DIRECTORY) {
202 notifyOnDirectoryCreate(this);
203 compareChilds();
204 } else {
205 notifyOnFileCreate(this);
206 }
207
208 return false;
209 }
210
211 if (newType == TYPE_DIRECTORY) {
212 notifyOnDirectoryChange(this);
213 compareChilds();
214 } else {
215 notifyOnFileChange(this);
216 }
217
218 return false;
219
220 } else {
221
222
223
224
225
226 compareChilds();
227
228 return false;
229 }
230 }
231 }
232
233 public MonitorFile getFile() {
234 return file;
235 }
236
237 public void markNotChanged() {
238 lastModified = file.lastModified();
239 }
240
241 }
242
243 private final File rootDirectory;
244 private final Entry rootEntry;
245
246 private FilesystemAlterationListener[] listeners = new FilesystemAlterationListener[0];
247 private Set listenersSet = new HashSet();
248
249 public FilesystemAlterationObserverImpl( final File pRootDirectory ) {
250 rootDirectory = pRootDirectory;
251 rootEntry = new Entry(new MonitorFileImpl(pRootDirectory));
252 }
253
254
255
256 private void notifyOnStart() {
257 log.debug("onStart " + rootEntry);
258 for (int i = 0; i < listeners.length; i++) {
259 final FilesystemAlterationListener listener = listeners[i];
260 listener.onStart(this);
261 }
262 }
263 private void notifyOnStop() {
264 log.debug("onStop " + rootEntry);
265 for (int i = 0; i < listeners.length; i++) {
266 final FilesystemAlterationListener listener = listeners[i];
267 listener.onStop(this);
268 }
269 }
270
271 private void notifyOnFileCreate( final Entry pEntry ) {
272 log.debug("onFileCreate " + pEntry);
273 for (int i = 0; i < listeners.length; i++) {
274 final FilesystemAlterationListener listener = listeners[i];
275 listener.onFileCreate(((MonitorFileImpl)pEntry.getFile()).file );
276 }
277 }
278 private void notifyOnFileChange( final Entry pEntry ) {
279 log.debug("onFileChange " + pEntry);
280 for (int i = 0; i < listeners.length; i++) {
281 final FilesystemAlterationListener listener = listeners[i];
282 listener.onFileChange(((MonitorFileImpl)pEntry.getFile()).file );
283 }
284 }
285 private void notifyOnFileDelete( final Entry pEntry ) {
286 log.debug("onFileDelete " + pEntry);
287 for (int i = 0; i < listeners.length; i++) {
288 final FilesystemAlterationListener listener = listeners[i];
289 listener.onFileDelete(((MonitorFileImpl)pEntry.getFile()).file );
290 }
291 }
292
293 private void notifyOnDirectoryCreate( final Entry pEntry ) {
294 log.debug("onDirectoryCreate " + pEntry);
295 for (int i = 0; i < listeners.length; i++) {
296 final FilesystemAlterationListener listener = listeners[i];
297 listener.onDirectoryCreate(((MonitorFileImpl)pEntry.getFile()).file );
298 }
299 }
300 private void notifyOnDirectoryChange( final Entry pEntry ) {
301 log.debug("onDirectoryChange " + pEntry);
302 for (int i = 0; i < listeners.length; i++) {
303 final FilesystemAlterationListener listener = listeners[i];
304 listener.onDirectoryChange(((MonitorFileImpl)pEntry.getFile()).file );
305 }
306 }
307 private void notifyOnDirectoryDelete( final Entry pEntry ) {
308 log.debug("onDirectoryDelete " + pEntry);
309 for (int i = 0; i < listeners.length; i++) {
310 final FilesystemAlterationListener listener = listeners[i];
311 listener.onDirectoryDelete(((MonitorFileImpl)pEntry.getFile()).file );
312 }
313 }
314
315
316 private void checkEntries() {
317 if(rootEntry.needsToBeDeleted()) {
318
319 rootEntry.lastType = Entry.TYPE_UNKNOWN;
320 }
321 }
322
323
324 public synchronized void checkAndNotify() {
325 if (listeners.length == 0) {
326 return;
327 }
328
329 notifyOnStart();
330
331 checkEntries();
332
333 notifyOnStop();
334 }
335
336
337 public File getRootDirectory() {
338 return rootDirectory;
339 }
340
341 public synchronized void addListener( final FilesystemAlterationListener pListener ) {
342 if (listenersSet.add(pListener)) {
343 createArrayFromSet();
344 }
345 }
346
347 public synchronized void removeListener( final FilesystemAlterationListener pListener ) {
348 if (listenersSet.remove(pListener)) {
349 createArrayFromSet();
350 }
351 }
352
353 private void createArrayFromSet() {
354 final FilesystemAlterationListener[] newListeners = new FilesystemAlterationListener[listenersSet.size()];
355 listenersSet.toArray(newListeners);
356 listeners = newListeners;
357 }
358
359 public FilesystemAlterationListener[] getListeners() {
360 return listeners;
361 }
362
363
364 public static void main( String[] args ) {
365 final FilesystemAlterationObserverImpl observer = new FilesystemAlterationObserverImpl(new File(args[0]));
366 while(true) {
367 observer.checkEntries();
368 try {
369 Thread.sleep(1000);
370 } catch (InterruptedException e) {
371 }
372 }
373 }
374 }