1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.eclipse.jetty.util;
16
17 import java.io.File;
18 import java.io.FilenameFilter;
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.Timer;
29 import java.util.TimerTask;
30
31 import org.eclipse.jetty.util.log.Log;
32
33
34
35
36
37
38
39
40
41
42 public class Scanner
43 {
44 private static int __scannerId=0;
45 private int _scanInterval;
46 private List _listeners = Collections.synchronizedList(new ArrayList());
47 private Map _prevScan = new HashMap();
48 private Map _currentScan = new HashMap();
49 private FilenameFilter _filter;
50 private List _scanDirs;
51 private volatile boolean _running = false;
52 private boolean _reportExisting = true;
53 private Timer _timer;
54 private TimerTask _task;
55 private boolean _recursive=true;
56
57
58
59
60
61
62
63 public interface Listener
64 {
65 }
66
67
68 public interface DiscreteListener extends Listener
69 {
70 public void fileChanged (String filename) throws Exception;
71 public void fileAdded (String filename) throws Exception;
72 public void fileRemoved (String filename) throws Exception;
73 }
74
75
76 public interface BulkListener extends Listener
77 {
78 public void filesChanged (List filenames) throws Exception;
79 }
80
81
82
83
84
85 public Scanner ()
86 {
87 }
88
89
90
91
92
93 public int getScanInterval()
94 {
95 return _scanInterval;
96 }
97
98
99
100
101
102 public synchronized void setScanInterval(int scanInterval)
103 {
104 this._scanInterval = scanInterval;
105 schedule();
106 }
107
108
109
110
111
112
113 public void setScanDir (File dir)
114 {
115 _scanDirs = new ArrayList();
116 _scanDirs.add(dir);
117 }
118
119
120
121
122
123
124 public File getScanDir ()
125 {
126 return (_scanDirs==null?null:(File)_scanDirs.get(0));
127 }
128
129 public void setScanDirs (List dirs)
130 {
131 _scanDirs = dirs;
132 }
133
134 public List getScanDirs ()
135 {
136 return _scanDirs;
137 }
138
139 public void setRecursive (boolean recursive)
140 {
141 _recursive=recursive;
142 }
143
144 public boolean getRecursive ()
145 {
146 return _recursive;
147 }
148
149
150
151
152
153 public void setFilenameFilter (FilenameFilter filter)
154 {
155 this._filter = filter;
156 }
157
158
159
160
161
162 public FilenameFilter getFilenameFilter ()
163 {
164 return _filter;
165 }
166
167
168
169
170
171
172
173 public void setReportExistingFilesOnStartup (boolean reportExisting)
174 {
175 this._reportExisting = reportExisting;
176 }
177
178
179
180
181
182 public synchronized void addListener (Listener listener)
183 {
184 if (listener == null)
185 return;
186 _listeners.add(listener);
187 }
188
189
190
191
192
193
194
195 public synchronized void removeListener (Listener listener)
196 {
197 if (listener == null)
198 return;
199 _listeners.remove(listener);
200 }
201
202
203
204
205
206 public synchronized void start ()
207 {
208 if (_running)
209 return;
210
211 _running = true;
212
213 if (_reportExisting)
214 {
215
216 scan();
217 }
218 else
219 {
220
221 scanFiles();
222 _prevScan.putAll(_currentScan);
223 }
224 schedule();
225 }
226
227 public TimerTask newTimerTask ()
228 {
229 return new TimerTask()
230 {
231 public void run() { scan(); }
232 };
233 }
234
235 public Timer newTimer ()
236 {
237 return new Timer("Scanner-"+__scannerId++, true);
238 }
239
240 public void schedule ()
241 {
242 if (_running)
243 {
244 if (_timer!=null)
245 _timer.cancel();
246 if (_task!=null)
247 _task.cancel();
248 if (getScanInterval() > 0)
249 {
250 _timer = newTimer();
251 _task = newTimerTask();
252 _timer.schedule(_task, 1000L*getScanInterval(),1000L*getScanInterval());
253 }
254 }
255 }
256
257
258
259 public synchronized void stop ()
260 {
261 if (_running)
262 {
263 _running = false;
264 if (_timer!=null)
265 _timer.cancel();
266 if (_task!=null)
267 _task.cancel();
268 _task=null;
269 _timer=null;
270 }
271 }
272
273
274
275
276 public void scan ()
277 {
278 scanFiles();
279 reportDifferences(_currentScan, _prevScan);
280 _prevScan.clear();
281 _prevScan.putAll(_currentScan);
282 }
283
284
285
286
287
288 public void scanFiles ()
289 {
290 if (_scanDirs==null)
291 return;
292
293 _currentScan.clear();
294 Iterator itor = _scanDirs.iterator();
295 while (itor.hasNext())
296 {
297 File dir = (File)itor.next();
298
299 if ((dir != null) && (dir.exists()))
300 scanFile(dir, _currentScan);
301 }
302 }
303
304
305
306
307
308
309
310
311 public void reportDifferences (Map currentScan, Map oldScan)
312 {
313 List bulkChanges = new ArrayList();
314
315 Set oldScanKeys = new HashSet(oldScan.keySet());
316 Iterator itor = currentScan.entrySet().iterator();
317 while (itor.hasNext())
318 {
319 Map.Entry entry = (Map.Entry)itor.next();
320 if (!oldScanKeys.contains(entry.getKey()))
321 {
322 Log.debug("File added: "+entry.getKey());
323 reportAddition ((String)entry.getKey());
324 bulkChanges.add(entry.getKey());
325 }
326 else if (!oldScan.get(entry.getKey()).equals(entry.getValue()))
327 {
328 Log.debug("File changed: "+entry.getKey());
329 reportChange((String)entry.getKey());
330 oldScanKeys.remove(entry.getKey());
331 bulkChanges.add(entry.getKey());
332 }
333 else
334 oldScanKeys.remove(entry.getKey());
335 }
336
337 if (!oldScanKeys.isEmpty())
338 {
339
340 Iterator keyItor = oldScanKeys.iterator();
341 while (keyItor.hasNext())
342 {
343 String filename = (String)keyItor.next();
344 Log.debug("File removed: "+filename);
345 reportRemoval(filename);
346 bulkChanges.add(filename);
347 }
348 }
349
350 if (!bulkChanges.isEmpty())
351 reportBulkChanges(bulkChanges);
352 }
353
354
355
356
357
358
359
360
361 private void scanFile (File f, Map scanInfoMap)
362 {
363 try
364 {
365 if (!f.exists())
366 return;
367
368 if (f.isFile())
369 {
370 if ((_filter == null) || ((_filter != null) && _filter.accept(f.getParentFile(), f.getName())))
371 {
372 String name = f.getCanonicalPath();
373 long lastModified = f.lastModified();
374 scanInfoMap.put(name, new Long(lastModified));
375 }
376 }
377 else if (f.isDirectory() && (_recursive || _scanDirs.contains(f)))
378 {
379 File[] files = f.listFiles();
380 for (int i=0;i<files.length;i++)
381 scanFile(files[i], scanInfoMap);
382 }
383 }
384 catch (IOException e)
385 {
386 Log.warn("Error scanning watched files", e);
387 }
388 }
389
390 private void warn(Object listener,String filename,Throwable th)
391 {
392 Log.warn(th);
393 Log.warn(listener+" failed on '"+filename);
394 }
395
396
397
398
399
400 private void reportAddition (String filename)
401 {
402 Iterator itor = _listeners.iterator();
403 while (itor.hasNext())
404 {
405 Object l = itor.next();
406 try
407 {
408 if (l instanceof DiscreteListener)
409 ((DiscreteListener)l).fileAdded(filename);
410 }
411 catch (Exception e)
412 {
413 warn(l,filename,e);
414 }
415 catch (Error e)
416 {
417 warn(l,filename,e);
418 }
419 }
420 }
421
422
423
424
425
426
427 private void reportRemoval (String filename)
428 {
429 Iterator itor = _listeners.iterator();
430 while (itor.hasNext())
431 {
432 Object l = itor.next();
433 try
434 {
435 if (l instanceof DiscreteListener)
436 ((DiscreteListener)l).fileRemoved(filename);
437 }
438 catch (Exception e)
439 {
440 warn(l,filename,e);
441 }
442 catch (Error e)
443 {
444 warn(l,filename,e);
445 }
446 }
447 }
448
449
450
451
452
453
454 private void reportChange (String filename)
455 {
456 Iterator itor = _listeners.iterator();
457 while (itor.hasNext())
458 {
459 Object l = itor.next();
460 try
461 {
462 if (l instanceof DiscreteListener)
463 ((DiscreteListener)l).fileChanged(filename);
464 }
465 catch (Exception e)
466 {
467 warn(l,filename,e);
468 }
469 catch (Error e)
470 {
471 warn(l,filename,e);
472 }
473 }
474 }
475
476 private void reportBulkChanges (List filenames)
477 {
478 Iterator itor = _listeners.iterator();
479 while (itor.hasNext())
480 {
481 Object l = itor.next();
482 try
483 {
484 if (l instanceof BulkListener)
485 ((BulkListener)l).filesChanged(filenames);
486 }
487 catch (Exception e)
488 {
489 warn(l,filenames.toString(),e);
490 }
491 catch (Error e)
492 {
493 warn(l,filenames.toString(),e);
494 }
495 }
496 }
497
498 }