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
(Generate patch)

Comparing projects/cms/source/server/uk/org/iscream/cms/server/client/WebFeeder.java (file contents):
Revision 1.2 by tdb, Thu Mar 8 20:57:35 2001 UTC vs.
Revision 1.26 by tdb, Sun Sep 25 09:57:40 2005 UTC

# Line 1 | Line 1
1 + /*
2 + * i-scream central monitoring system
3 + * http://www.i-scream.org
4 + * 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   //---PACKAGE DECLARATION---
22 < package uk.ac.ukc.iscream.client;
22 > package uk.org.iscream.cms.server.client;
23  
24   //---IMPORTS---
25 < import uk.ac.ukc.iscream.componentmanager.*;
26 < import uk.ac.ukc.iscream.core.*;
27 < import uk.ac.ukc.iscream.util.*;
25 > import uk.org.iscream.cms.server.componentmanager.*;
26 > import uk.org.iscream.cms.server.core.*;
27 > import uk.org.iscream.cms.util.*;
28   import java.io.*;
29  
30   /**
# Line 13 | Line 33 | import java.io.*;
33   * @author  $Author$
34   * @version $Id$
35   */
36 < public class WebFeeder {
36 > public class WebFeeder extends Thread {
37  
38   //---FINAL ATTRIBUTES---
39  
# Line 22 | Line 42 | public class WebFeeder {
42       */
43      public static final String REVISION = "$Revision$";
44      
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 +    
55 +    /**
56 +     * The default path seperator, here for convienience
57 +     */
58 +    private final String sep = File.separator;
59 +    
60   //---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 <    public static WebFeeder getInstance() {
66 >    public synchronized static WebFeeder getInstance() {
67          if (_instance == null){
68              _instance = new WebFeeder();
69          }
# Line 36 | Line 71 | public class WebFeeder {
71      }
72  
73   //---CONSTRUCTORS---
74 <
74 >    
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      private WebFeeder() {
81          // do something, or nothing.. but must be private
82 +        // don't need to cleanup latest data
83 +        
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 +            File alertsDir = new File(rootPath, alertSubDir);
94 +            if(deleteContents(alertsDir)) {
95 +                _logger.write(this.toString(), Logger.DEBUG, "Deleted all files and directories from: "+rootPath+sep+alertSubDir);
96 +            } else {
97 +                _logger.write(this.toString(), Logger.WARNING, "Failed to delete all files and directories from: "+rootPath+sep+alertSubDir);
98 +            }
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 +        
105 +        // set our name and startup
106 +        setName("client.WebFeeder");
107 +        start();
108      }
109  
110   //---PUBLIC METHODS---
111      
112 <    // TO BE COMPLETED
113 <    // The following two methods should process and save
114 <    // XMLPackets and Alerts, in a directory structure that
115 <    // has been defined by the web page designer.
112 >    /**
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 >            // list the files and delete as appropriate
166 >            File alertsDir = new File(rootPath, alertSubDir);
167 >            // 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 >                                    }
207 >                                }
208 >                            }
209 >                        }
210 >                        // 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 >                                }
225 >                            }
226 >                        }
227 >                        // ---- 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 >                        }
244 >                    }
245 >                }
246 >            }
247 >            else {
248 >                _logger.write(toString(), Logger.WARNING, "IO error reading alerts directory, maybe it doesn't exist? : " +rootPath+sep+alertSubDir);
249 >            }
250 >        }
251 >    }
252      
253 <    // There may also be need to have a Thread to grab any
254 <    // required config (groups, "nice names, etc) and dump
255 <    // that to a file.
256 <    
253 >    /**
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      public void receiveXMLPacket(XMLPacket packet) {
260 +        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          // get config proxy
267          ConfigurationProxy cp = ConfigurationProxy.getInstance();
268          // get file locations
# Line 68 | Line 278 | public class WebFeeder {
278          }
279          // get raw data
280          String data = packet.printAll();
281 <        String hostname = packet.getParam("packet.attributes.host_name");
281 >        String hostname = packet.getParam("packet.attributes.machine_name");
282          // set paths
283 <        String destDir = rootPath+"/"+latestSubDir+"/"+hostname;
284 <        String destFile = destDir+"/"+latestFileName;
285 <        // write data
286 <        File outDir = new File(destDir);
287 <        if(outDir.mkdirs()) {
288 <            File outFile = new File(destFile);
289 <            if(outFile.canWrite()) {
290 <                PrintWriter out;
291 <                try {
292 <                    out = new PrintWriter(new FileWriter(outFile));
293 <                    out.println(data);
294 <                    out.close();
295 <                } catch (IOException e) {
296 <                    _logger.write(this.toString(), Logger.ERROR, "Failed to write file: "+e);
297 <                }
283 >        File outDir = new File(rootPath, latestSubDir+sep+hostname);
284 >        File outFile = new File(rootPath, latestSubDir+sep+hostname+sep+latestFileName);
285 >        // write the data out
286 >        writeData(outDir, outFile, data);
287 >    }
288 >    
289 >    /**
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 >    public void receiveAlert(Alert alert) {
296 >        // 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 >        File outDir = new File(rootPath, alertSubDir+sep+hostname);
314 >        String destFile = alertSubDir+sep+hostname+sep+alertFileName+"."+String.valueOf(alert.getInitialAlertTime());
315 >        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 >            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 <            else {
326 <                _logger.write(this.toString(), Logger.ERROR, "File not readable: "+outFile.getPath());
325 >            File oldFile = new File(rootPath, destFile);
326 >            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 +            outFile = new File(rootPath, destFile);
331          }
332 <        else {
333 <            _logger.write(this.toString(), Logger.ERROR, "Failed to create directory: "+outDir.getPath());
95 <        }
332 >        // write the data out
333 >        writeData(outDir, outFile, data);
334      }
335      
98    public void receiveAlert(Alert alert) {
99        // process and save
100    }
101    
336      /**
337       * Overrides the {@link java.lang.Object#toString() Object.toString()}
338       * method to provide clean logging (every class should have this).
339       *
340 <     * This uses the uk.ac.ukc.iscream.util.FormatName class
340 >     * This uses the uk.org.iscream.cms.util.FormatName class
341       * to format the toString()
342       *
343       * @return the name of this class and its CVS revision
# Line 116 | Line 350 | public class WebFeeder {
350      }
351  
352   //---PRIVATE METHODS---
353 <
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 >        // 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 >                out = new PrintWriter(new FileWriter(outFile));
389 >                out.print(data + "\n");
390 >                out.flush();
391 >                out.close();
392 >            } catch (IOException e) {
393 >                _logger.write(this.toString(), Logger.ERROR, "Failed to write file: "+e);
394 >            }
395 >        }
396 >        else {
397 >            _logger.write(this.toString(), Logger.ERROR, "File not writeable: "+outFile.getPath());
398 >        }
399 >    }
400 >    
401 >    /**
402 >     * Iterates through dir (a directory) and deletes
403 >     * all files and subdirectories.
404 >     *
405 >     * @param dir the directory to clear
406 >     * @return true if it succeeded
407 >     */
408 >    private boolean deleteContents(File dir) {
409 >        boolean success = true;
410 >        if(dir.isDirectory()) {
411 >            // is a directory
412 >            File[] contents = dir.listFiles();
413 >            for(int i=0; i < contents.length; i++) {
414 >                File sub = contents[i];
415 >                if(sub.isDirectory()) {
416 >                    // lets get recursive
417 >                    success = success & deleteContents(sub);
418 >                }
419 >                // it's a file or empty dir
420 >                success = success & sub.delete();
421 >            }
422 >        }
423 >        else {
424 >            // not a directory?
425 >            success=false;
426 >        }
427 >        return success;
428 >    }
429 >        
430   //---ACCESSOR/MUTATOR METHODS---
431  
432   //---ATTRIBUTES---

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines