ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/server/uk/org/iscream/cms/server/client/WebFeeder.java
Revision: 1.16
Committed: Mon Mar 19 21:30:30 2001 UTC (23 years, 2 months ago) by tdb
Branch: MAIN
Changes since 1.15: +14 -3 lines
Log Message:
Now cleans up empty host directories on the alert pages.

File Contents

# Content
1 //---PACKAGE DECLARATION---
2 package uk.org.iscream.client;
3
4 //---IMPORTS---
5 import uk.org.iscream.componentmanager.*;
6 import uk.org.iscream.core.*;
7 import uk.org.iscream.util.*;
8 import java.io.*;
9
10 /**
11 * Provides a feed to the webpage system.
12 *
13 * !! There may also be need to have a Thread to grab any
14 * !! required config (groups, "nice names, etc) and dump
15 * !! that to a file.
16 *
17 * @author $Author: tdb1 $
18 * @version $Id: WebFeeder.java,v 1.15 2001/03/16 16:47:33 tdb1 Exp $
19 */
20 public class WebFeeder extends Thread {
21
22 //---FINAL ATTRIBUTES---
23
24 /**
25 * The current CVS revision of this class
26 */
27 public static final String REVISION = "$Revision: 1.15 $";
28
29 /**
30 * Default check period in seconds (30 minutes)
31 */
32 public final int DEFAULT_CHECK_PERIOD = 1800;
33
34 /**
35 * Delete alerts older than this in seconds, default.
36 */
37 public final int DEFAULT_AGE = 3600;
38
39 /**
40 * The default path seperator, here for convienience
41 */
42 private final String sep = File.separator;
43
44 //---STATIC METHODS---
45
46 /**
47 * Return a reference to the single class.
48 * Construct it if it does not already exist, otherwise just return the reference.
49 */
50 public static WebFeeder getInstance() {
51 if (_instance == null){
52 _instance = new WebFeeder();
53 }
54 return _instance;
55 }
56
57 //---CONSTRUCTORS---
58
59 /**
60 * Construct a new WebFeeder. This will also wipe out any
61 * old Alerts, as these can't be carried from one session
62 * until the next.
63 */
64 private WebFeeder() {
65 // do something, or nothing.. but must be private
66 // don't need to cleanup latest data
67
68 // -- cleanup old alerts
69 // get config proxy
70 ConfigurationProxy cp = ConfigurationProxy.getInstance();
71 // get file locations
72 String rootPath, alertSubDir, alertFileName;
73 try {
74 // work out where things are
75 rootPath = cp.getProperty("WebFeeder", "WebFeeder.rootPath");
76 alertSubDir = cp.getProperty("WebFeeder", "WebFeeder.alertSubDir");
77 File alertsDir = new File(rootPath, alertSubDir);
78 if(deleteContents(alertsDir)) {
79 _logger.write(this.toString(), Logger.DEBUG, "Deleted all files and directories from: "+rootPath+sep+alertSubDir);
80 } else {
81 _logger.write(this.toString(), Logger.WARNING, "Failed to delete all files and directories from: "+rootPath+sep+alertSubDir);
82 }
83 // cleanup complete
84 } catch (PropertyNotFoundException e) {
85 _logger.write(this.toString(), Logger.ERROR, "Failed to cleanup on construction, due to failing to get config for Alert Data: "+e);
86 // just leave it at that
87 }
88
89 // set our name and startup
90 setName("client.WebFeeder");
91 start();
92 }
93
94 //---PUBLIC METHODS---
95
96 /**
97 * Thread loop, will check at intervals for any files
98 * that need to be "cleaned up". This will normally
99 * be OK and FINAL alerts that have been around for longer
100 * than a specified period of time.
101 */
102 public void run() {
103 boolean running = true;
104 // get config proxy
105 ConfigurationProxy cp = ConfigurationProxy.getInstance();
106 // loop round
107 while(running) {
108 // get our check period
109 int checkPeriod = 0;
110 try {
111 checkPeriod = Integer.parseInt(cp.getProperty("WebFeeder", "WebFeeder.checkPeriod"));
112 } catch (NumberFormatException e) {
113 checkPeriod = DEFAULT_CHECK_PERIOD;
114 _logger.write(toString(), Logger.WARNING, "Erronous WebFeeder.checkPeriod value in configuration using default of " + checkPeriod + " seconds");
115 } catch (PropertyNotFoundException e) {
116 checkPeriod = DEFAULT_CHECK_PERIOD;
117 _logger.write(toString(), Logger.WARNING, "WebFeeder.checkPeriod value unavailable using default of " + checkPeriod + " seconds");
118 }
119 // wait for the check period
120 try {
121 Thread.sleep(checkPeriod * 1000);
122 } catch (InterruptedException e) {
123 }
124
125 // get alerts directory
126 String rootPath, alertSubDir, alertFileName;
127 try {
128 rootPath = cp.getProperty("WebFeeder", "WebFeeder.rootPath");
129 alertSubDir = cp.getProperty("WebFeeder", "WebFeeder.alertSubDir");
130 alertFileName = cp.getProperty("WebFeeder", "WebFeeder.alertFileName");
131 } catch (PropertyNotFoundException e) {
132 _logger.write(this.toString(), Logger.ERROR, "Failed to get config for Alert Data: "+e);
133 // bail out
134 continue;
135 }
136
137 // get the "age" barrier
138 int deleteOlderThan = 0;
139 try {
140 deleteOlderThan = Integer.parseInt(cp.getProperty("WebFeeder", "WebFeeder.alertDeleteOlderThan"));
141 } catch (NumberFormatException e) {
142 deleteOlderThan = DEFAULT_AGE;
143 _logger.write(toString(), Logger.WARNING, "Erronous WebFeeder.alertDeleteOlderThan value in configuration using default of " + deleteOlderThan + " seconds");
144 } catch (PropertyNotFoundException e) {
145 deleteOlderThan = DEFAULT_AGE;
146 _logger.write(toString(), Logger.WARNING, "WebFeeder.alertDeleteOlderThan value unavailable using default of " + deleteOlderThan + " seconds");
147 }
148
149 // list the files and delete as appropriate
150 File alertsDir = new File(rootPath, alertSubDir);
151 // get all the hostnames directories
152 File[] contents = alertsDir.listFiles();
153 for(int i=0; i < contents.length; i++) {
154 // get a single directory from the array..
155 File hostdir = contents[i];
156 // ..and check it's a directory
157 if(hostdir.isDirectory()) {
158 // get all the contents of that directory
159 File[] hostdirContents = hostdir.listFiles();
160 for(int j=0; j < hostdirContents.length; j++) {
161 File alertFile = hostdirContents[j];
162 // get the filename..
163 String filename = alertFile.getName();
164 // ..and see if it ends with OK or FINAL
165 if(filename.endsWith(Alert.alertLevels[0]) ||
166 filename.endsWith(Alert.alertLevels[Alert.alertLevels.length-1])) {
167 // it does end with either OK or FINAL
168 // ... so we can check it for deletion
169 long lastModified = alertFile.lastModified();
170 long age = System.currentTimeMillis() - lastModified;
171 if(age > ((long) deleteOlderThan*1000)) {
172 // it's also older than our age to delete older than
173 if(alertFile.delete()) {
174 // do a quick check to see if the directory is now empty
175 File[] newHostdirContents = hostdir.listFiles();
176 if(newHostdirContents.length == 0) {
177 // it does seem to be, try and delete it
178 // this will fail anyway if files still remain
179 if(!hostdir.delete()) {
180 _logger.write(this.toString(), Logger.WARNING, "Failed to delete the following empty host directory: "+hostdir.getPath());
181 }
182 }
183 }
184 else {
185 _logger.write(this.toString(), Logger.WARNING, "Failed to delete the following 'old' alert file: "+alertFile.getPath());
186 }
187 }
188 }
189 }
190 }
191 }
192 }
193 }
194
195 /**
196 * Handles an XMLPacket. This will write it out to disk
197 * in an appropriate manner.
198 *
199 * @param packet the XMLPacket to write
200 */
201 public void receiveXMLPacket(XMLPacket packet) {
202 String packetType = packet.getParam("packet.attributes.type");
203 if(packetType == null || !packetType.equals("data")) {
204 // bail out, without warning
205 // this is probably a heartbeat or similar
206 return;
207 }
208 // get config proxy
209 ConfigurationProxy cp = ConfigurationProxy.getInstance();
210 // get file locations
211 String rootPath, latestSubDir, latestFileName;
212 try {
213 rootPath = cp.getProperty("WebFeeder", "WebFeeder.rootPath");
214 latestSubDir = cp.getProperty("WebFeeder", "WebFeeder.latestSubDir");
215 latestFileName = cp.getProperty("WebFeeder", "WebFeeder.latestFileName");
216 } catch (PropertyNotFoundException e) {
217 _logger.write(this.toString(), Logger.ERROR, "Failed to get config for Latest Data: "+e);
218 // bail out
219 return;
220 }
221 // get raw data
222 String data = packet.printAll();
223 String hostname = packet.getParam("packet.attributes.machine_name");
224 // set paths
225 File outDir = new File(rootPath, latestSubDir+sep+hostname);
226 File outFile = new File(rootPath, latestSubDir+sep+hostname+sep+latestFileName);
227 // write the data out
228 writeData(outDir, outFile, data);
229 }
230
231 /**
232 * Handles an Alert. This will write it out to disk
233 * in an appropriate manner.
234 *
235 * @param alert the Alert object to write
236 */
237 public void receiveAlert(Alert alert) {
238 // get config proxy
239 ConfigurationProxy cp = ConfigurationProxy.getInstance();
240 // get file locations
241 String rootPath, alertSubDir, alertFileName;
242 try {
243 rootPath = cp.getProperty("WebFeeder", "WebFeeder.rootPath");
244 alertSubDir = cp.getProperty("WebFeeder", "WebFeeder.alertSubDir");
245 alertFileName = cp.getProperty("WebFeeder", "WebFeeder.alertFileName");
246 } catch (PropertyNotFoundException e) {
247 _logger.write(this.toString(), Logger.ERROR, "Failed to get config for Alert Data: "+e);
248 // bail out
249 return;
250 }
251 // get raw data
252 String data = alert.printAll();
253 String hostname = alert.getSource();
254 // set paths
255 File outDir = new File(rootPath, alertSubDir+sep+hostname);
256 String destFile = alertSubDir+sep+hostname+sep+alertFileName+"."+String.valueOf(alert.getInitialAlertTime());
257 File outFile;
258 // check if we're at a special "end case" (OK or FINAL)
259 if(alert.getLevel()==0 || alert.getLevel()==Alert.alertLevels.length-1) {
260 File oldFile = new File(rootPath, destFile);
261 outFile = new File(rootPath, destFile+"."+Alert.alertLevels[alert.getLevel()]);
262 if(!oldFile.renameTo(outFile)) {
263 _logger.write(this.toString(), Logger.WARNING, "Failed to rename old file, "+oldFile.getPath()+" to new file, "+outFile.getPath());
264 }
265 } else {
266 outFile = new File(rootPath, destFile);
267 }
268 // write the data out
269 writeData(outDir, outFile, data);
270 }
271
272 /**
273 * Overrides the {@link java.lang.Object#toString() Object.toString()}
274 * method to provide clean logging (every class should have this).
275 *
276 * This uses the uk.org.iscream.util.FormatName class
277 * to format the toString()
278 *
279 * @return the name of this class and its CVS revision
280 */
281 public String toString() {
282 return FormatName.getName(
283 _name,
284 getClass().getName(),
285 REVISION);
286 }
287
288 //---PRIVATE METHODS---
289
290 /**
291 * Attempts to write "data" to "outFile" in "outDir".
292 *
293 * Performs checks to create the directories, and the file.
294 * Does not "return" anything to indicate failure or success.
295 *
296 * @param outDir the directory to put the file in
297 * @param outFile the filename to put the data in
298 * @param data the String of data to write
299 */
300 private void writeData(File outDir, File outFile, String data) {
301 // try to create directory
302 if(!outDir.exists()) {
303 if(!outDir.mkdirs()) {
304 // didn't exist, and we couldn't make it
305 _logger.write(this.toString(), Logger.ERROR, "Failed to create directory: "+outDir.getPath());
306 // bail out
307 return;
308 }
309 }
310 // directory has been made, check file exists
311 if(!outFile.exists()) {
312 try {
313 outFile.createNewFile();
314 } catch (IOException e) {
315 _logger.write(this.toString(), Logger.ERROR, "Failed to create file: "+e);
316 // bail out
317 return;
318 }
319 }
320 // file should now exist
321 if(outFile.canWrite()) {
322 PrintWriter out;
323 try {
324 out = new PrintWriter(new FileWriter(outFile));
325 out.println(data);
326 out.close();
327 } catch (IOException e) {
328 _logger.write(this.toString(), Logger.ERROR, "Failed to write file: "+e);
329 }
330 }
331 else {
332 _logger.write(this.toString(), Logger.ERROR, "File not writeable: "+outFile.getPath());
333 }
334 }
335
336 /**
337 * Iterates through dir (a directory) and deletes
338 * all files and subdirectories.
339 *
340 * @param dir the directory to clear
341 * @return true if it succeeded
342 */
343 private boolean deleteContents(File dir) {
344 boolean success = true;
345 if(dir.isDirectory()) {
346 // is a directory
347 File[] contents = dir.listFiles();
348 for(int i=0; i < contents.length; i++) {
349 File sub = contents[i];
350 if(sub.isDirectory()) {
351 // lets get recursive
352 success = success & deleteContents(sub);
353 }
354 // it's a file or empty dir
355 success = success & sub.delete();
356 }
357 }
358 else {
359 // not a directory?
360 success=false;
361 }
362 return success;
363 }
364
365 //---ACCESSOR/MUTATOR METHODS---
366
367 //---ATTRIBUTES---
368
369 /**
370 * This is the friendly identifier of the
371 * component this class is running in.
372 * eg, a Filter may be called "filter1",
373 * If this class does not have an owning
374 * component, a name from the configuration
375 * can be placed here. This name could also
376 * be changed to null for utility classes.
377 */
378 private String _name = ClientMain.NAME;
379
380 /**
381 * This holds a reference to the
382 * system logger that is being used.
383 */
384 private Logger _logger = ReferenceManager.getInstance().getLogger();
385
386 //---STATIC ATTRIBUTES---
387
388 /**
389 * A reference to the single instance of this class
390 */
391 private static WebFeeder _instance;
392
393 }