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.23
Committed: Tue May 21 16:47:16 2002 UTC (22 years ago) by tdb
Branch: MAIN
Changes since 1.22: +3 -2 lines
Log Message:
Added URL to GPL headers.

File Contents

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