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.22
Committed: Sat May 18 18:16:00 2002 UTC (22 years ago) by tdb
Branch: MAIN
Changes since 1.21: +21 -2 lines
Log Message:
i-scream is now licensed under the GPL. I've added the GPL headers to every
source file, and put a full copy of the license in the appropriate places.
I think I've covered everything. This is going to be a mad commit ;)

File Contents

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