1
2
3
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
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
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
300
301
302
303