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

# User Rev Content
1 tdb 1.22 /*
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 tdb 1.1 //---PACKAGE DECLARATION---
21 tdb 1.19 package uk.org.iscream.cms.server.client;
22 tdb 1.1
23     //---IMPORTS---
24 tdb 1.19 import uk.org.iscream.cms.server.componentmanager.*;
25     import uk.org.iscream.cms.server.core.*;
26     import uk.org.iscream.cms.server.util.*;
27 tdb 1.2 import java.io.*;
28 tdb 1.1
29     /**
30     * Provides a feed to the webpage system.
31     *
32 tdb 1.21 * @author $Author: tdb $
33 tdb 1.22 * @version $Id: WebFeeder.java,v 1.21 2002/01/10 21:49:38 tdb Exp $
34 tdb 1.1 */
35 tdb 1.11 public class WebFeeder extends Thread {
36 tdb 1.1
37     //---FINAL ATTRIBUTES---
38    
39     /**
40     * The current CVS revision of this class
41     */
42 tdb 1.22 public static final String REVISION = "$Revision: 1.21 $";
43 tdb 1.11
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 tdb 1.1
54 tdb 1.14 /**
55     * The default path seperator, here for convienience
56     */
57     private final String sep = File.separator;
58    
59 tdb 1.1 //---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 tdb 1.17 public synchronized static WebFeeder getInstance() {
66 tdb 1.1 if (_instance == null){
67     _instance = new WebFeeder();
68     }
69     return _instance;
70     }
71    
72     //---CONSTRUCTORS---
73 tdb 1.11
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 tdb 1.1 private WebFeeder() {
80     // do something, or nothing.. but must be private
81 tdb 1.8 // don't need to cleanup latest data
82 tdb 1.9
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 tdb 1.12 File alertsDir = new File(rootPath, alertSubDir);
93 tdb 1.10 if(deleteContents(alertsDir)) {
94 tdb 1.14 _logger.write(this.toString(), Logger.DEBUG, "Deleted all files and directories from: "+rootPath+sep+alertSubDir);
95 tdb 1.10 } else {
96 tdb 1.14 _logger.write(this.toString(), Logger.WARNING, "Failed to delete all files and directories from: "+rootPath+sep+alertSubDir);
97 tdb 1.9 }
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 tdb 1.11
104     // set our name and startup
105     setName("client.WebFeeder");
106     start();
107 tdb 1.1 }
108    
109     //---PUBLIC METHODS---
110    
111 tdb 1.11 /**
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 tdb 1.12 // list the files and delete as appropriate
165     File alertsDir = new File(rootPath, alertSubDir);
166 tdb 1.21 // 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 tdb 1.18 }
206     }
207     }
208     }
209 tdb 1.21 // 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 tdb 1.12 }
224 tdb 1.11 }
225     }
226 tdb 1.21 // ---- 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 tdb 1.18 }
243     }
244 tdb 1.11 }
245 tdb 1.21 }
246     else {
247     _logger.write(toString(), Logger.WARNING, "IO error reading alerts directory, maybe it doesn't exist? : " +rootPath+sep+alertSubDir);
248 tdb 1.11 }
249     }
250     }
251 tdb 1.1
252 tdb 1.11 /**
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 tdb 1.1 public void receiveXMLPacket(XMLPacket packet) {
259 tdb 1.4 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 tdb 1.2 // 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 tdb 1.3 String hostname = packet.getParam("packet.attributes.machine_name");
281 tdb 1.2 // set paths
282 tdb 1.14 File outDir = new File(rootPath, latestSubDir+sep+hostname);
283     File outFile = new File(rootPath, latestSubDir+sep+hostname+sep+latestFileName);
284 tdb 1.11 // write the data out
285     writeData(outDir, outFile, data);
286 tdb 1.1 }
287    
288 tdb 1.11 /**
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 tdb 1.1 public void receiveAlert(Alert alert) {
295 tdb 1.5 // 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 tdb 1.14 File outDir = new File(rootPath, alertSubDir+sep+hostname);
313     String destFile = alertSubDir+sep+hostname+sep+alertFileName+"."+String.valueOf(alert.getInitialAlertTime());
314 tdb 1.9 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 tdb 1.18 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 tdb 1.12 File oldFile = new File(rootPath, destFile);
325 tdb 1.9 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 tdb 1.13 outFile = new File(rootPath, destFile);
330 tdb 1.9 }
331 tdb 1.11 // 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 tdb 1.19 * This uses the uk.org.iscream.cms.server.util.FormatName class
340 tdb 1.11 * 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 tdb 1.5 // 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 tdb 1.8 out = new PrintWriter(new FileWriter(outFile));
388 tdb 1.5 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 tdb 1.1 }
398 tdb 1.10
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 tdb 1.1 //---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     }