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.9 by tdb, Thu Mar 15 04:03:24 2001 UTC vs.
Revision 1.18 by tdb, Fri Mar 23 00:44:11 2001 UTC

# Line 10 | Line 10 | import java.io.*;
10   /**
11   * Provides a feed to the webpage system.
12   *
13 < * !! still needs a routine to "maintain" alerts !!
13 > * !! There may also be need to have a Thread to grab any
14 > * !! required config (groups, "nice names, etc) and dump
15 > * !! that to a file.
16   *
17   * @author  $Author$
18   * @version $Id$
19   */
20 < public class WebFeeder {
20 > public class WebFeeder extends Thread {
21  
22   //---FINAL ATTRIBUTES---
23  
# Line 24 | Line 26 | public class WebFeeder {
26       */
27      public static final String REVISION = "$Revision$";
28      
29 +    /**
30 +     * Default check period in seconds (30 minutes)
31 +     */
32 +    public final int DEFAULT_CHECK_PERIOD = 1800;
33 +    
34 +    /**
35 +     * Delete alerts older than this in seconds, default.
36 +     */
37 +    public final int DEFAULT_AGE = 3600;
38 +    
39 +    /**
40 +     * The default path seperator, here for convienience
41 +     */
42 +    private final String sep = File.separator;
43 +    
44   //---STATIC METHODS---
45  
46      /**
47       * Return a reference to the single class.
48       * Construct it if it does not already exist, otherwise just return the reference.
49       */
50 <    public static WebFeeder getInstance() {
50 >    public synchronized static WebFeeder getInstance() {
51          if (_instance == null){
52              _instance = new WebFeeder();
53          }
# Line 38 | Line 55 | public class WebFeeder {
55      }
56  
57   //---CONSTRUCTORS---
58 <
58 >    
59 >    /**
60 >     * Construct a new WebFeeder. This will also wipe out any
61 >     * old Alerts, as these can't be carried from one session
62 >     * until the next.
63 >     */
64      private WebFeeder() {
65          // do something, or nothing.. but must be private
66          // don't need to cleanup latest data
# Line 52 | Line 74 | public class WebFeeder {
74              // work out where things are
75              rootPath = cp.getProperty("WebFeeder", "WebFeeder.rootPath");
76              alertSubDir = cp.getProperty("WebFeeder", "WebFeeder.alertSubDir");
77 <            File alerts = new File(rootPath+"/"+alertSubDir);
78 <            File[] contents = alerts.listFiles();
79 <            for(int i=0; i < contents.length; i++) {
80 <                contents[i].delete();
77 >            File alertsDir = new File(rootPath, alertSubDir);
78 >            if(deleteContents(alertsDir)) {
79 >                _logger.write(this.toString(), Logger.DEBUG, "Deleted all files and directories from: "+rootPath+sep+alertSubDir);
80 >            } else {
81 >                _logger.write(this.toString(), Logger.WARNING, "Failed to delete all files and directories from: "+rootPath+sep+alertSubDir);
82              }
83              // cleanup complete
61            _logger.write(this.toString(), Logger.DEBUG, "Deleted "+contents.length+" files or directories from: "+rootPath+"/"+alertSubDir);
84          } catch (PropertyNotFoundException e) {
85              _logger.write(this.toString(), Logger.ERROR, "Failed to cleanup on construction, due to failing to get config for Alert Data: "+e);
86              // just leave it at that
87          }
88 +        
89 +        // set our name and startup
90 +        setName("client.WebFeeder");
91 +        start();
92      }
93  
94   //---PUBLIC METHODS---
95      
96 <    // TO BE COMPLETED
97 <    // The following two methods should process and save
98 <    // XMLPackets and Alerts, in a directory structure that
99 <    // has been defined by the web page designer.
96 >    /**
97 >     * Thread loop, will check at intervals for any files
98 >     * that need to be "cleaned up". This will normally
99 >     * be OK and FINAL alerts that have been around for longer
100 >     * than a specified period of time.
101 >     */
102 >    public void run() {
103 >        boolean running = true;
104 >        // get config proxy
105 >        ConfigurationProxy cp = ConfigurationProxy.getInstance();
106 >        // loop round
107 >        while(running) {
108 >            // get our check period
109 >            int checkPeriod = 0;
110 >            try {
111 >                checkPeriod = Integer.parseInt(cp.getProperty("WebFeeder", "WebFeeder.checkPeriod"));
112 >            } catch (NumberFormatException e) {
113 >                checkPeriod = DEFAULT_CHECK_PERIOD;
114 >                _logger.write(toString(), Logger.WARNING, "Erronous WebFeeder.checkPeriod value in configuration using default of " + checkPeriod + " seconds");
115 >            } catch (PropertyNotFoundException e) {
116 >                checkPeriod = DEFAULT_CHECK_PERIOD;
117 >                _logger.write(toString(), Logger.WARNING, "WebFeeder.checkPeriod value unavailable using default of " + checkPeriod + " seconds");
118 >            }
119 >            // wait for the check period
120 >            try {
121 >                Thread.sleep(checkPeriod * 1000);
122 >            } catch (InterruptedException e) {
123 >            }
124 >            
125 >            // get alerts directory
126 >            String rootPath, alertSubDir, alertFileName;
127 >            try {
128 >                rootPath = cp.getProperty("WebFeeder", "WebFeeder.rootPath");
129 >                alertSubDir = cp.getProperty("WebFeeder", "WebFeeder.alertSubDir");
130 >                alertFileName = cp.getProperty("WebFeeder", "WebFeeder.alertFileName");
131 >            } catch (PropertyNotFoundException e) {
132 >                _logger.write(this.toString(), Logger.ERROR, "Failed to get config for Alert Data: "+e);
133 >                // bail out
134 >                continue;
135 >            }
136 >            
137 >            // get the "age" barrier
138 >            int deleteOlderThan = 0;
139 >            try {
140 >                deleteOlderThan = Integer.parseInt(cp.getProperty("WebFeeder", "WebFeeder.alertDeleteOlderThan"));
141 >            } catch (NumberFormatException e) {
142 >                deleteOlderThan = DEFAULT_AGE;
143 >                _logger.write(toString(), Logger.WARNING, "Erronous WebFeeder.alertDeleteOlderThan value in configuration using default of " + deleteOlderThan + " seconds");
144 >            } catch (PropertyNotFoundException e) {
145 >                deleteOlderThan = DEFAULT_AGE;
146 >                _logger.write(toString(), Logger.WARNING, "WebFeeder.alertDeleteOlderThan value unavailable using default of " + deleteOlderThan + " seconds");
147 >            }
148 >            
149 >            // list the files and delete as appropriate
150 >            File alertsDir = new File(rootPath, alertSubDir);
151 >            // get all the hostnames directories
152 >            File[] contents = alertsDir.listFiles();
153 >            for(int i=0; i < contents.length; i++) {
154 >                // get a single directory from the array..
155 >                File hostdir = contents[i];
156 >                // ..and check it's a directory
157 >                if(hostdir.isDirectory()) {
158 >                    // if this is set, we clean files older than it
159 >                    long deleteFiles = -1;
160 >                    // get all the contents of that directory
161 >                    File[] hostdirContents = hostdir.listFiles();
162 >                    for(int j=0; j < hostdirContents.length; j++) {
163 >                        File alertFile = hostdirContents[j];
164 >                        // get the filename..
165 >                        String filename = alertFile.getName();
166 >                        // ..and see if it ends with OK or FINAL
167 >                        if(filename.endsWith(Alert.alertLevels[0]) ||
168 >                           filename.endsWith(Alert.alertLevels[Alert.alertLevels.length-1])) {
169 >                            // it does end with either OK or FINAL
170 >                            // ... so we can check it for deletion
171 >                            long lastModified = alertFile.lastModified();
172 >                            long age = System.currentTimeMillis() - lastModified;
173 >                            if(age > ((long) deleteOlderThan*1000)) {
174 >                                // if we're on a final heartbeat, we probably want to
175 >                                // clean up any stale alerts left behind
176 >                                // by setting this flag, we'll clean them up on leaving this loop
177 >                                if(filename.endsWith(".HB."+Alert.alertLevels[Alert.alertLevels.length-1])) {
178 >                                    // we do this so that delete files is set to the
179 >                                    // latest date of a HB.FINAL. There should only be
180 >                                    // one of them though :)
181 >                                    if(lastModified > deleteFiles) {
182 >                                        deleteFiles = lastModified;
183 >                                    }
184 >                                }
185 >                                // it's also older than our age to delete older than
186 >                                if(!alertFile.delete()) {
187 >                                    _logger.write(this.toString(), Logger.WARNING, "Failed to delete the following 'old' alert file: "+alertFile.getPath());
188 >                                }
189 >                            }
190 >                        }
191 >                    }
192 >                    // cleanup stale alerts
193 >                    if(deleteFiles >= 0) {
194 >                        File[] remainingHostdirContents = hostdir.listFiles();
195 >                        for(int j=0; j < remainingHostdirContents.length; j++) {
196 >                            File alertFile = remainingHostdirContents[j];
197 >                            if(alertFile.lastModified() < deleteFiles) {
198 >                                // alert file is older than the most recent
199 >                                // FINAL Heartbeat alert.
200 >                                if(alertFile.delete()) {
201 >                                    _logger.write(this.toString(), Logger.DEBUG, "Deleted stale alert file: "+alertFile.getPath());
202 >                                }
203 >                                else {
204 >                                    _logger.write(this.toString(), Logger.WARNING, "Failed to delete the following 'stale' alert file: "+alertFile.getPath());
205 >                                }
206 >                            }
207 >                        }
208 >                    }
209 >                    // ---- RECAP ----
210 >                    // at this point, we have cleaned up any OK or FINAL alerts
211 >                    // that have passed our age limit. We have then cleaned up
212 >                    // any alerts older the most recent Heartbeat FINAL alert,
213 >                    // as these are probably stale. Any files left are valid and
214 >                    // active alerts. We are now in a position to remove the host
215 >                    // directory if it's empty.
216 >                    // ---------------
217 >                    // do a quick check to see if the directory is now empty
218 >                    File[] newHostdirContents = hostdir.listFiles();
219 >                    if(newHostdirContents.length == 0) {
220 >                        // it does seem to be, try and delete it
221 >                        // this will fail anyway if files still remain
222 >                        if(!hostdir.delete()) {
223 >                            _logger.write(this.toString(), Logger.WARNING, "Failed to delete the following empty host directory: "+hostdir.getPath());
224 >                        }
225 >                    }
226 >                }
227 >            }
228 >        }
229 >    }
230      
231 <    // There may also be need to have a Thread to grab any
232 <    // required config (groups, "nice names, etc) and dump
233 <    // that to a file.
234 <    
231 >    /**
232 >     * Handles an XMLPacket. This will write it out to disk
233 >     * in an appropriate manner.
234 >     *
235 >     * @param packet the XMLPacket to write
236 >     */
237      public void receiveXMLPacket(XMLPacket packet) {
238          String packetType = packet.getParam("packet.attributes.type");
239          if(packetType == null || !packetType.equals("data")) {
# Line 100 | Line 258 | public class WebFeeder {
258          String data = packet.printAll();
259          String hostname = packet.getParam("packet.attributes.machine_name");
260          // set paths
261 <        String destDir = rootPath+"/"+latestSubDir+"/"+hostname;
262 <        String destFile = destDir+"/"+latestFileName;
263 <        // try to create directory
264 <        File outDir = new File(destDir);
107 <        if(!outDir.exists()) {
108 <            if(!outDir.mkdirs()) {
109 <                // didn't exist, and we couldn't make it
110 <                _logger.write(this.toString(), Logger.ERROR, "Failed to create directory: "+outDir.getPath());
111 <                // bail out
112 <                return;
113 <            }
114 <        }
115 <        // directory has been made, check file exists
116 <        File outFile = new File(destFile);
117 <        if(!outFile.exists()) {
118 <            try {
119 <                outFile.createNewFile();
120 <            } catch (IOException e) {
121 <                _logger.write(this.toString(), Logger.ERROR, "Failed to create file: "+e);
122 <                // bail out
123 <                return;
124 <            }
125 <        }
126 <        // file should now exist
127 <        if(outFile.canWrite()) {
128 <            PrintWriter out;
129 <            try {
130 <                out = new PrintWriter(new FileWriter(outFile));
131 <                out.println(data);
132 <                out.close();
133 <            } catch (IOException e) {
134 <                _logger.write(this.toString(), Logger.ERROR, "Failed to write file: "+e);
135 <            }
136 <        }
137 <        else {
138 <            _logger.write(this.toString(), Logger.ERROR, "File not writeable: "+outFile.getPath());
139 <        }
261 >        File outDir = new File(rootPath, latestSubDir+sep+hostname);
262 >        File outFile = new File(rootPath, latestSubDir+sep+hostname+sep+latestFileName);
263 >        // write the data out
264 >        writeData(outDir, outFile, data);
265      }
266      
267 +    /**
268 +     * Handles an Alert. This will write it out to disk
269 +     * in an appropriate manner.
270 +     *
271 +     * @param alert the Alert object to write
272 +     */
273      public void receiveAlert(Alert alert) {
274          // get config proxy
275          ConfigurationProxy cp = ConfigurationProxy.getInstance();
# Line 157 | Line 288 | public class WebFeeder {
288          String data = alert.printAll();
289          String hostname = alert.getSource();
290          // set paths
291 <        String destDir = rootPath+"/"+alertSubDir+"/"+hostname;
292 <        File outDir = new File(destDir);
162 <        String destFile = destDir+"/"+alertFileName+"."+String.valueOf(alert.getInitialAlertTime());
291 >        File outDir = new File(rootPath, alertSubDir+sep+hostname);
292 >        String destFile = alertSubDir+sep+hostname+sep+alertFileName+"."+String.valueOf(alert.getInitialAlertTime());
293          File outFile;
294          // check if we're at a special "end case" (OK or FINAL)
295          if(alert.getLevel()==0 || alert.getLevel()==Alert.alertLevels.length-1) {
296 <            File oldFile = new File(destFile);
297 <            outFile = new File(destFile+Alert.alertLevels[alert.getLevel()]);
296 >            if(alert.getAttributeName().equals("Heartbeat") && alert.getLevel()==Alert.alertLevels.length-1) {
297 >                // new file is something like alert.nnnnnnnn.HB.FINAL
298 >                outFile = new File(rootPath, destFile+".HB."+Alert.alertLevels[alert.getLevel()]);
299 >            } else {
300 >                // new file is something like alert.nnnnnnnn.OK
301 >                outFile = new File(rootPath, destFile+"."+Alert.alertLevels[alert.getLevel()]);
302 >            }
303 >            File oldFile = new File(rootPath, destFile);
304              if(!oldFile.renameTo(outFile)) {
305                  _logger.write(this.toString(), Logger.WARNING, "Failed to rename old file, "+oldFile.getPath()+" to new file, "+outFile.getPath());
306              }
307          } else {
308 <            outFile = new File(destFile);
308 >            outFile = new File(rootPath, destFile);
309          }
310 +        // write the data out
311 +        writeData(outDir, outFile, data);
312 +    }
313 +    
314 +    /**
315 +     * Overrides the {@link java.lang.Object#toString() Object.toString()}
316 +     * method to provide clean logging (every class should have this).
317 +     *
318 +     * This uses the uk.org.iscream.util.FormatName class
319 +     * to format the toString()
320 +     *
321 +     * @return the name of this class and its CVS revision
322 +     */
323 +    public String toString() {
324 +        return FormatName.getName(
325 +            _name,
326 +            getClass().getName(),
327 +            REVISION);
328 +    }
329 +
330 + //---PRIVATE METHODS---
331 +    
332 +    /**
333 +     * Attempts to write "data" to "outFile" in "outDir".
334 +     *
335 +     * Performs checks to create the directories, and the file.
336 +     * Does not "return" anything to indicate failure or success.
337 +     *
338 +     * @param outDir the directory to put the file in
339 +     * @param outFile the filename to put the data in
340 +     * @param data the String of data to write
341 +     */
342 +    private void writeData(File outDir, File outFile, String data) {
343          // try to create directory
344          if(!outDir.exists()) {
345              if(!outDir.mkdirs()) {
# Line 207 | Line 376 | public class WebFeeder {
376      }
377      
378      /**
379 <     * Overrides the {@link java.lang.Object#toString() Object.toString()}
380 <     * method to provide clean logging (every class should have this).
379 >     * Iterates through dir (a directory) and deletes
380 >     * all files and subdirectories.
381       *
382 <     * This uses the uk.org.iscream.util.FormatName class
383 <     * to format the toString()
215 <     *
216 <     * @return the name of this class and its CVS revision
382 >     * @param dir the directory to clear
383 >     * @return true if it succeeded
384       */
385 <    public String toString() {
386 <        return FormatName.getName(
387 <            _name,
388 <            getClass().getName(),
389 <            REVISION);
385 >    private boolean deleteContents(File dir) {
386 >        boolean success = true;
387 >        if(dir.isDirectory()) {
388 >            // is a directory
389 >            File[] contents = dir.listFiles();
390 >            for(int i=0; i < contents.length; i++) {
391 >                File sub = contents[i];
392 >                if(sub.isDirectory()) {
393 >                    // lets get recursive
394 >                    success = success & deleteContents(sub);
395 >                }
396 >                // it's a file or empty dir
397 >                success = success & sub.delete();
398 >            }
399 >        }
400 >        else {
401 >            // not a directory?
402 >            success=false;
403 >        }
404 >        return success;
405      }
406 <
225 < //---PRIVATE METHODS---
226 <
406 >        
407   //---ACCESSOR/MUTATOR METHODS---
408  
409   //---ATTRIBUTES---

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines