View Javadoc

1   /*
2    * $Id: AbstractFileStateMonitor.java,v 1.1 2004/04/27 10:59:15 johndavidtaylor Exp $ Created on Apr 26, 2004 by jdt@roe.ac.uk The alipes project Copyright
3    * (c) Astrigrid 2004. All rights reserved.
4    *  
5    */
6   package org.abraracourcix.alipes.monitors.file;
7   import java.io.File;
8   import java.util.Date;
9   import java.util.HashMap;
10  import java.util.Iterator;
11  import java.util.Map;
12  import java.util.Set;
13  import org.abraracourcix.alipes.listeners.Listener;
14  import org.abraracourcix.alipes.listeners.ListenerException;
15  import org.abraracourcix.alipes.monitors.PollingMonitor;
16  /***
17   * Factors out everything we know about FileStateMonitors, leaving subclasses
18   * to decide how to manage the files we want to monitor
19   * 
20   * @author jdt
21   */
22  public abstract class AbstractFileStateMonitor extends PollingMonitor {
23      /***
24       * Commons logger
25       */
26      private static final org.apache.commons.logging.Log log =
27          org.apache.commons.logging.LogFactory.getLog(
28              AbstractFileStateMonitor.class);
29      /***
30       * Constructor - pass through to superclass
31       * 
32       * @param listener see superclass
33       * @param pollingFrequency see superclass
34       */
35      public AbstractFileStateMonitor(
36          final Listener listener,
37          final long pollingFrequency) {
38          super(listener, pollingFrequency);
39      }
40      /***
41       * Number of milliseconds in a second
42       */
43      private static final int MILLIS_PER_SEC = 1000;
44      /***
45       * Map of Files to Fileinfos
46       */
47      private Map fileInfos = new HashMap();
48      /***
49       * @author jdt Java Enum for the states a file could have
50       */
51      protected static final class FileState {
52          /***
53           * Constructor
54           * 
55           * @param message some useful description
56           */
57          private FileState(final String message) {
58              this.message = message;
59          }
60          /***
61           * human readable description
62           */
63          private String message;
64          /***
65           * Enum value
66           */
67          public static final FileState FILE_EXISTS =
68              new FileState("File exists");
69          /***
70           * Enum value
71           */
72          public static final FileState FILE_EXISTS_STALE =
73              new FileState("File exists, but is old.");
74          /***
75           * Enum value
76           */
77          public static final FileState FILE_NO_EXIST =
78              new FileState("File does not exist");
79          /***
80           * Enum value
81           */
82          public static final FileState UNKNOWN = new FileState("Je ne sais pas");
83          /***
84           * Usual toString
85           * 
86           * @return description of filestate
87           */
88          public String toString() {
89              return message;
90          }
91          /***
92           * utility method - does the file exist?
93           * 
94           * @return true if exists
95           */
96          public boolean doesExist() {
97              return (this == FILE_EXISTS || this == FILE_EXISTS_STALE);
98          }
99          /***
100          * utility method - is the file absent
101          * 
102          * @return true if file is absent
103          */
104         public boolean doesNotExist() {
105             return (this == FILE_NO_EXIST);
106         }
107         /***
108          * utility method - is the file state?
109          * 
110          * @return true if the file is old
111          */
112         public boolean isStale() {
113             return this == FILE_EXISTS_STALE;
114         }
115     }
116     /***
117      * Simply a dataholder we can stick in a map containing info about a file
118      * 
119      * @author jdt
120      */
121     protected static final class FileInfo {
122         /***
123          * file's timestamp
124          */
125         private Date dateStamp;
126         /***
127          * File's state
128          */
129         private FileState fileState;
130         /***
131          * Constructor
132          * 
133          * @param fileState The State of the file
134          * @param dateStamp The time when it was measured
135          */
136         public FileInfo(final FileState fileState, final Date dateStamp) {
137             this.dateStamp = dateStamp;
138             this.fileState = fileState;
139         }
140         /***
141          * Getter
142          * 
143          * @return Returns the dateStamp.
144          */
145         public Date getDateStamp() {
146             return dateStamp;
147         }
148         /***
149          * Getter
150          * 
151          * @return Returns the fileState.
152          */
153         public FileState getFileState() {
154             return fileState;
155         }
156     }
157     /***
158      * After this # of millis the file is considered stale
159      */
160     private int staleIntervalMillis = NEVER;
161     /***
162      * Hardcoded value to say that files should never be considered stale
163      */
164     public static final int NEVER = -1;
165     /***
166      * Check the status of this file and fire off any events as appropriate
167      * 
168      * @param file file to check
169      * @param info the file's previous info
170      * @return the file's new info
171      * @throws ListenerException - need to deal with this 
172      * @TODO deal with exception properly
173      */
174     private FileInfo checkFile(final File file, final FileInfo info)
175         throws ListenerException {
176         assert file != null;
177         assert info != null;
178         final FileState oldFileState = info.getFileState();
179         final Date oldStamp = info.getDateStamp();
180         assert oldFileState != null;
181         assert oldStamp != null;
182         final FileState newFileState =
183             file.exists() ? FileState.FILE_EXISTS : FileState.FILE_NO_EXIST;
184         final Date newStamp = new Date(file.lastModified());
185         //@TODO what is this if file no exist?
186         FileInfo newInfo = new FileInfo(newFileState, newStamp);
187         log.debug("checkFile: file=" + file);
188         log.debug("Old state=" + oldFileState + ", old datestamp=" + oldStamp);
189         log.debug("New state=" + newFileState + ", new datestamp=" + newStamp);
190         if (newFileState.doesExist()) {
191             signalListener(FileEvent.EXISTS, file);
192         } else if (newFileState.doesNotExist()) {
193             signalListener(FileEvent.DOES_NOT_EXIST, file);
194         }
195         if (newFileState.doesExist() && oldFileState.doesNotExist()) {
196             signalListener(FileEvent.CREATED, file);
197         }
198         if (newFileState.doesNotExist() && oldFileState.doesExist()) {
199             signalListener(FileEvent.DELETED, file);
200         }
201         if (newFileState.doesExist() && oldFileState.doesExist()) {
202             if (newStamp.after(oldStamp)) {
203                 signalListener(FileEvent.UPDATED, file);
204             }
205         }
206         if (staleIntervalMillis != NEVER && newFileState.doesExist()) {
207             final Date limit =
208                 new Date(new Date().getTime() - staleIntervalMillis);
209             log.debug("Time limit for stale: " + limit);
210             if (newStamp.before(limit)) {
211                 signalListener(FileEvent.IS_STALE, file);
212                 newInfo = new FileInfo(FileState.FILE_EXISTS_STALE, newStamp);
213             }
214         }
215         if (newInfo.getFileState().isStale() && !oldFileState.isStale() && oldFileState!=FileState.UNKNOWN) {
216             signalListener(FileEvent.GONE_STALE, file);
217         }
218         return newInfo;
219     }
220     /***
221      * Stale interval in seconds
222      * 
223      * @return Returns the staleIntervalMillis.
224      */
225     public final int getStaleInterval() {
226         return staleIntervalMillis / MILLIS_PER_SEC;
227     }
228     /***
229      * Stale interval in seconds - the time after which the file goes stale use
230      * setStaleInterval(FileStateMonitor.NEVER) if the files are never
231      * considered stale.
232      * 
233      * @param staleInterval The staleIntervalMillis to set.
234      */
235     public final void setStaleInterval(final int staleInterval) {
236         this.staleIntervalMillis = staleInterval * MILLIS_PER_SEC;
237     }
238     /***
239      * Add a file the list we monitor and set its state to unknown
240      * 
241      * @param file another file
242      * @param state the initial state of the file added
243      */
244     public final void addFile(final File file, final FileState state) {
245         fileInfos.put(file, new FileInfo(state, new Date()));
246     }
247     /***
248      * Check the file list and respond acccordingly (non-Javadoc) @TODO deal
249      * with exception properly
250      * 
251      */
252     protected final void checkTheFiles() {
253         assert fileInfos != null;
254         final Set files = fileInfos.keySet();
255         final Iterator it = files.iterator();
256         while (it.hasNext()) {
257             final File file = (File) it.next();
258             FileInfo info = (FileInfo) fileInfos.get(file);
259             try {
260                 info = checkFile(file, info);
261             } catch (ListenerException e) {
262                 // TODO Auto-generated catch block
263                 e.printStackTrace();
264             }
265             fileInfos.put(file, info);
266         }
267     }
268     /***
269      * Add files to the list we monitor and set their state to unknown
270      * 
271      * @param files the files to add
272      */
273     public final void addFiles(final File[] files) {
274         for (int i = 0; i < files.length; ++i) {
275             fileInfos.put(
276                 files[i],
277                 new FileInfo(FileState.UNKNOWN, new Date()));
278         }
279     }
280     /***
281      * Adds a file with unknown state to the list of files to be monitored
282      * 
283      * @param file the file
284      */
285     public final void addFile(final File file) {
286         addFile(file, FileState.UNKNOWN);
287     }
288     /***
289      * Get a collection of the files we're monitoring
290      * 
291      * @return sais files
292      */
293     protected final Set getMonitoredFiles() {
294         assert fileInfos != null;
295         return fileInfos.keySet();
296     }
297 }
298 /*
299  * $Log: AbstractFileStateMonitor.java,v $
300  * Revision 1.1  2004/04/27 10:59:15  johndavidtaylor
301  * Refactored and added a directory monitor
302  *
303  */