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.4 by tdb, Thu Mar 8 21:37:39 2001 UTC vs.
Revision 1.22 by tdb, Sat May 18 18:16:00 2002 UTC

# Line 1 | Line 1
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.ac.ukc.iscream.client;
21 > package uk.org.iscream.cms.server.client;
22  
23   //---IMPORTS---
24 < import uk.ac.ukc.iscream.componentmanager.*;
25 < import uk.ac.ukc.iscream.core.*;
26 < import uk.ac.ukc.iscream.util.*;
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   /**
# Line 13 | Line 32 | import java.io.*;
32   * @author  $Author$
33   * @version $Id$
34   */
35 < public class WebFeeder {
35 > public class WebFeeder extends Thread {
36  
37   //---FINAL ATTRIBUTES---
38  
# Line 22 | Line 41 | public class WebFeeder {
41       */
42      public static final String REVISION = "$Revision$";
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 static WebFeeder getInstance() {
65 >    public synchronized static WebFeeder getInstance() {
66          if (_instance == null){
67              _instance = new WebFeeder();
68          }
# Line 36 | Line 70 | public class WebFeeder {
70      }
71  
72   //---CONSTRUCTORS---
73 <
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 <    // TO BE COMPLETED
112 <    // The following two methods should process and save
113 <    // XMLPackets and Alerts, in a directory structure that
114 <    // has been defined by the web page designer.
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 <    // There may also be need to have a Thread to grab any
253 <    // required config (groups, "nice names, etc) and dump
254 <    // that to a file.
255 <    
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")) {
# Line 76 | Line 279 | public class WebFeeder {
279          String data = packet.printAll();
280          String hostname = packet.getParam("packet.attributes.machine_name");
281          // set paths
282 <        String destDir = rootPath+"/"+latestSubDir+"/"+hostname;
283 <        String destFile = destDir+"/"+latestFileName;
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
82        File outDir = new File(destDir);
365          if(!outDir.exists()) {
366              if(!outDir.mkdirs()) {
367                  // didn't exist, and we couldn't make it
# Line 89 | Line 371 | public class WebFeeder {
371              }
372          }
373          // directory has been made, check file exists
92        File outFile = new File(destFile);
374          if(!outFile.exists()) {
375              try {
376                  outFile.createNewFile();
# Line 115 | Line 396 | public class WebFeeder {
396          }
397      }
398      
118    public void receiveAlert(Alert alert) {
119        // process and save
120    }
121    
399      /**
400 <     * Overrides the {@link java.lang.Object#toString() Object.toString()}
401 <     * method to provide clean logging (every class should have this).
400 >     * Iterates through dir (a directory) and deletes
401 >     * all files and subdirectories.
402       *
403 <     * This uses the uk.ac.ukc.iscream.util.FormatName class
404 <     * to format the toString()
128 <     *
129 <     * @return the name of this class and its CVS revision
403 >     * @param dir the directory to clear
404 >     * @return true if it succeeded
405       */
406 <    public String toString() {
407 <        return FormatName.getName(
408 <            _name,
409 <            getClass().getName(),
410 <            REVISION);
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 <
138 < //---PRIVATE METHODS---
139 <
427 >        
428   //---ACCESSOR/MUTATOR METHODS---
429  
430   //---ATTRIBUTES---

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines