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.20
Committed: Mon Dec 10 22:20:22 2001 UTC (22 years, 5 months ago) by tdb
Branch: MAIN
Changes since 1.19: +2 -6 lines
Log Message:
Some minor javadoc tweaks. The first sentence is now more obvious to the
javadoc parser.

File Contents

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