View Javadoc

1   /*
2    * Copyright 2000-2001,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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  // Jetspeed classes
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                             // if fragment has some uncommitted changes
263                             if (fragment.isDirty())
264                             {
265                                 //save it to disk
266                                 subscriber.saveFragment(filename);
267 
268                                 if (logger.isDebugEnabled())
269                                 {
270                                     logger.debug( "RegistryWatcher: Saved " + filename);
271                                 }
272 
273                                 //and update the stored timestamp
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                     // make sure to reset the state of all fragments
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 }