View Javadoc

1   /*
2    * $Id: FileMonitor.java 7976 2007-08-21 14:26:13Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.util.monitor;
12  
13  import java.beans.ExceptionListener;
14  import java.io.File;
15  import java.io.IOException;
16  import java.lang.ref.WeakReference;
17  import java.util.ArrayList;
18  import java.util.Collection;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Timer;
24  import java.util.TimerTask;
25  
26  /**
27   * Class for monitoring changes in disk files. Usage: 1. Implement the FileListener
28   * interface. 2. Create a FileMonitor instance. 3. Add the file(s)/directory(ies) to
29   * listen for. fileChanged() will be called when a monitored file is created, deleted
30   * or its modified time changes.
31   * 
32   * @author <a href="mailto:jacob.dreyer@geosoft.no">Jacob Dreyer</a>
33   */
34  public class FileMonitor
35  {
36      private Timer timer;
37      private Map files;
38      private List listeners;
39      private long pollingInterval;
40  
41      /**
42       * Create a file monitor instance with specified polling interval.
43       * 
44       * @param pollingInterval Polling interval in milli seconds.
45       */
46      public FileMonitor(long pollingInterval)
47      {
48          files = new HashMap();
49          listeners = new ArrayList();
50          timer = new Timer(true);
51          this.pollingInterval = pollingInterval;
52      }
53  
54      /**
55       * Stop the file monitor polling.
56       */
57      public void stop()
58      {
59          timer.cancel();
60      }
61  
62      public void start()
63      {
64          timer.schedule(new FileMonitorNotifier(), 0, pollingInterval);
65      }
66  
67      /**
68       * Add file to listen for. File may be any java.io.File (including a directory)
69       * and may well be a non-existing file in the case where the creating of the file
70       * is to be trepped. <p/> More than one file can be listened for. When the
71       * specified file is created, modified or deleted, listeners are notified.
72       * 
73       * @param file File to listen for.
74       */
75      public void addFile(File file)
76      {
77          if (!files.containsKey(file))
78          {
79              long modifiedTime = file.exists() ? file.lastModified() : -1;
80              files.put(file, new Long(modifiedTime));
81          }
82      }
83  
84      /**
85       * Remove specified file for listening.
86       * 
87       * @param file File to remove.
88       */
89      public void removeFile(File file)
90      {
91          files.remove(file);
92      }
93  
94      /**
95       * Add listener to this file monitor.
96       * 
97       * @param fileListener Listener to add.
98       */
99      public void addListener(FileListener fileListener)
100     {
101         // Don't add if its already there
102         for (Iterator i = listeners.iterator(); i.hasNext();)
103         {
104             WeakReference reference = (WeakReference) i.next();
105             FileListener listener = (FileListener) reference.get();
106             if (listener == fileListener)
107             {
108                 return;
109             }
110         }
111 
112         // Use WeakReference to avoid memory leak if this becomes the
113         // sole reference to the object.
114         listeners.add(new WeakReference(fileListener));
115     }
116 
117     /**
118      * Remove listener from this file monitor.
119      * 
120      * @param fileListener Listener to remove.
121      */
122     public void removeListener(FileMonitor fileListener)
123     {
124         for (Iterator i = listeners.iterator(); i.hasNext();)
125         {
126             WeakReference reference = (WeakReference) i.next();
127             FileMonitor listener = (FileMonitor) reference.get();
128             if (listener == fileListener)
129             {
130                 i.remove();
131                 break;
132             }
133         }
134     }
135 
136     /**
137      * This is the timer thread which is executed every n milliseconds according to
138      * the setting of the file monitor.
139      */
140     public class FileMonitorNotifier extends TimerTask
141     {
142         private ExceptionListener exceptionListener;
143 
144         public FileMonitorNotifier()
145         {
146             super();
147         }
148 
149         public FileMonitorNotifier(ExceptionListener exceptionListener)
150         {
151             this.exceptionListener = exceptionListener;
152         }
153 
154         public void run()
155         {
156             // Loop over the registered files and see which have changed.
157             // Use a copy of the list in case listener wants to alter the
158             // list within its fileChanged method.
159             Collection fileKeys = new ArrayList(files.keySet());
160 
161             for (Iterator i = fileKeys.iterator(); i.hasNext();)
162             {
163                 File file = (File) i.next();
164                 long lastModifiedTime = ((Long) files.get(file)).longValue();
165                 long newModifiedTime = file.exists() ? file.lastModified() : -1;
166 
167                 // Chek if file has changed
168                 if (newModifiedTime != lastModifiedTime)
169                 {
170                     // Register new modified time
171                     files.put(file, new Long(newModifiedTime));
172 
173                     // Notify listeners
174                     for (Iterator j = listeners.iterator(); j.hasNext();)
175                     {
176                         WeakReference reference = (WeakReference) j.next();
177                         FileListener listener = (FileListener) reference.get();
178 
179                         // Remove from list if the back-end object has been GC'd
180                         if (listener == null)
181                         {
182                             j.remove();
183                         }
184                         else
185                         {
186                             try
187                             {
188                                 listener.fileChanged(file);
189                             }
190                             catch (IOException e)
191                             {
192                                 // TODO MULE-863: What should we do if null?
193                                 if (exceptionListener != null)
194                                 {
195                                     exceptionListener.exceptionThrown(e);
196                                 }
197                             }
198                         }
199                     }
200                 }
201             }
202         }
203     }
204 }