1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.services.registry;
18
19 import java.io.File;
20 import java.io.FileFilter;
21 import java.util.Enumeration;
22 import java.util.Hashtable;
23 import java.util.Iterator;
24 import java.util.Map;
25
26
27 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
28 import org.apache.jetspeed.services.logging.JetspeedLogger;
29
30 /***
31 * Monitors a Registry directory and notifies the associated Registry
32 * of file updates.
33 *
34 * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
35 * @version $Id: RegistryWatcher.java,v 1.10 2004/02/23 03:31:50 jford Exp $
36 */
37 public class RegistryWatcher extends Thread
38 {
39 /***
40 * Static initialization of the logger for this class
41 */
42 private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(RegistryWatcher.class.getName());
43
44 /*** Minimum scan rate for evaluating file refresh */
45 public static final int SCAN_RATE = 10;
46
47 /***
48 The files monitored by this watcher
49 */
50 private Hashtable files = new Hashtable();
51
52 /***
53 the refresh rate, in milliseconds, to use for monitoring this file
54 */
55 private long refreshRate = 0;
56
57 /***
58 The object that relies on this RegsitryWatcher
59 */
60 private FileRegistry subscriber = null;
61
62 /***
63 The filter to use for filtering registry files
64 */
65 private FileFilter filter = null;
66
67 /***
68 * This object marks that we are done
69 */
70 private boolean done = false;
71
72 /***
73 * Creates a default RegistryWatcher
74 */
75 public RegistryWatcher()
76 {
77 setDaemon(true);
78 setPriority(Thread.MIN_PRIORITY);
79 }
80
81 /*** Modifies the subscriber to this Watcher
82 *
83 * @param registry the new registry subscriber
84 */
85 public void setSubscriber(FileRegistry registry)
86 {
87 synchronized (this)
88 {
89 if (subscriber!=null)
90 {
91 Enumeration en = files.keys();
92 while(en.hasMoreElements())
93 {
94 try
95 {
96 subscriber.removeFragment(((File)en.nextElement()).getCanonicalPath());
97 }
98 catch (Exception e)
99 {
100 logger.error("RegistryWatcher: Can't remove fragment", e);
101 }
102 }
103 }
104
105 this.subscriber = registry;
106
107 if (subscriber!=null)
108 {
109 Enumeration en = files.keys();
110 while(en.hasMoreElements())
111 {
112 try
113 {
114 subscriber.loadFragment(((File)en.nextElement()).getCanonicalPath());
115 }
116 catch (Exception e)
117 {
118 logger.error("RegistryWatcher: Can't load fragment", e);
119 }
120 }
121 }
122 }
123 }
124
125 /*** @return the subscriber to this watcher */
126 public FileRegistry getSubscriber()
127 {
128 return this.subscriber;
129 }
130
131 /*** Sets the refresh rate for this watcher
132 * @param refresh the refresh rate in seconds
133 */
134 public void setRefreshRate(long refresh)
135 {
136 this.refreshRate = (( refresh > SCAN_RATE ) ? refresh : SCAN_RATE) * 1000;
137 }
138
139 /*** @return the refresh rate, in seconds, of this watcher */
140 public long getRefreshRate()
141 {
142 return refreshRate / 1000;
143 }
144
145 /*** Sets the file filter for selecting the registry files
146 * @param filter the file filter to use
147 */
148 public void setFilter(FileFilter filter)
149 {
150 this.filter = filter;
151 }
152
153 /*** @return the file filter used by this watcher instance */
154 public FileFilter getFilter()
155 {
156 return filter;
157 }
158
159 /*** Change the base file or directory to be monitored by this watcher
160 *
161 * @param f the file or directory to monitor
162 */
163 public void changeBase(File f)
164 {
165 synchronized (this)
166 {
167 if (this.subscriber!=null)
168 {
169 Enumeration en = files.keys();
170 while (en.hasMoreElements())
171 {
172 try
173 {
174 subscriber.removeFragment(((File)en.nextElement()).getCanonicalPath());
175 }
176 catch (Exception e)
177 {
178 logger.error("RegistryWatcher: Can't remove fragment", e);
179 }
180 }
181 }
182 files.clear();
183 findFiles(f);
184 }
185 }
186
187 /***
188 * Refresh the monitored file list
189 *
190 * @param f the file or directory to monitor
191 */
192 private void findFiles(File f)
193 {
194 File[] contents = null;
195
196 if (f.exists() && f.canRead())
197 {
198 this.files.put(f,new Long(f.lastModified()));
199
200 if (f.isDirectory())
201 {
202
203 if (filter != null)
204 contents = f.listFiles(filter);
205 else
206 contents = f.listFiles();
207
208 if (contents!=null)
209 {
210 for (int i=0; i< contents.length; i++)
211 {
212 files.put(contents[i],new Long(contents[i].lastModified()));
213
214 if (subscriber!=null)
215 {
216 try
217 {
218 subscriber.loadFragment(contents[i].getCanonicalPath());
219 }
220 catch (Exception e)
221 {
222 logger.error("RegistryWatcher: Can't load fragment", e);
223 }
224 }
225 }
226 }
227 }
228 }
229 }
230
231 /***
232 * <p>Main routine for the monitor which periodically checks whether
233 * the filex have been modified.</p>
234 * The algorithm used does not guarantee a constant refresh rate
235 * between invocations.
236 */
237 public void run()
238 {
239 try
240 {
241 while(!done)
242 {
243 boolean needRefresh = false;
244
245 synchronized (this)
246 {
247 Map fragments = subscriber.getFragmentMap();
248
249 if (logger.isDebugEnabled())
250 {
251 logger.debug( "RegistryWatcher: Saving dirty fragments.");
252 }
253
254 Iterator i = fragments.keySet().iterator();
255 while(i.hasNext())
256 {
257 try
258 {
259 String filename = (String)i.next();
260 RegistryFragment fragment = (RegistryFragment)subscriber.getFragmentMap().get(filename);
261
262
263 if (fragment.isDirty())
264 {
265
266 subscriber.saveFragment(filename);
267
268 if (logger.isDebugEnabled())
269 {
270 logger.debug( "RegistryWatcher: Saved " + filename);
271 }
272
273
274 Enumeration en = files.keys();
275 while(en.hasMoreElements())
276 {
277 File f = (File)en.nextElement();
278 if (filename.equals(f.getCanonicalPath()))
279 {
280 files.put(f,new Long(f.lastModified()));
281 }
282 }
283 }
284 }
285 catch (Exception e)
286 {
287 logger.error("RegistryWatcher: exception during update",e);
288 }
289 }
290
291 if (logger.isDebugEnabled())
292 {
293 logger.debug( "RegistryWatcher: Checking for updated files.");
294 }
295
296 Enumeration en = files.keys();
297 while(en.hasMoreElements())
298 {
299 try
300 {
301 File f = (File)en.nextElement();
302 long modified = ((Long)files.get(f)).longValue();
303
304 if (!f.exists())
305 {
306 files.remove(f);
307 }
308 else
309 {
310 if (f.lastModified() > modified)
311 {
312 files.put(f,new Long(f.lastModified()));
313
314 if (f.isDirectory())
315 {
316 File[] contents = null;
317
318 if (filter != null)
319 {
320 contents = f.listFiles(filter);
321 }
322 else
323 {
324 contents = f.listFiles();
325 }
326
327 if (contents!=null)
328 {
329 for (int idx=0; idx< contents.length; idx++)
330 {
331 if (files.get(contents[idx])==null)
332 {
333 files.put(contents[idx],new Long(contents[idx].lastModified()));
334
335 if (subscriber!=null)
336 {
337 subscriber.loadFragment(contents[idx].getCanonicalPath());
338 }
339 }
340 }
341 }
342 }
343 else
344 {
345 subscriber.loadFragment(f.getCanonicalPath());
346 }
347
348 if (logger.isDebugEnabled())
349 {
350 logger.debug("RegistryWatcher: Refreshing because "
351 + f.getCanonicalPath()
352 + " was modified.("
353 + f.lastModified()
354 + " "
355 + modified
356 + ")");
357 }
358
359 RegistryFragment frag = (RegistryFragment)fragments.get(f.getCanonicalPath());
360
361 if (frag!=null)
362 {
363 frag.setChanged(true);
364 }
365
366 needRefresh = true;
367 }
368 }
369 }
370 catch (Exception e)
371 {
372 logger.error("RegistryWatcher: exception during update",e);
373 }
374 }
375
376 if (needRefresh)
377 {
378 subscriber.refresh();
379 needRefresh = false;
380 }
381
382
383 i = fragments.keySet().iterator();
384 while(i.hasNext())
385 {
386 RegistryFragment frag = (RegistryFragment)fragments.get((String)i.next());
387 frag.setDirty(false);
388 frag.setChanged(false);
389 }
390 }
391
392 sleep( refreshRate );
393 }
394 }
395 catch (InterruptedException e)
396 {
397 logger.error("RegistryWatcher: Stopping monitor: ", e);
398 return;
399 }
400 }
401
402 /***
403 * Mark that the watching thread should be stopped
404 */
405 public void setDone()
406 {
407 done = true;
408 logger.info("RegistryWatcher: Watching thread stop requested");
409 }
410
411 }