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.6 by tdb, Thu Mar 8 23:26:03 2001 UTC vs.
Revision 1.21 by tdb, Thu Jan 10 21:49:38 2002 UTC

# Line 1 | Line 1
1   //---PACKAGE DECLARATION---
2 < package uk.ac.ukc.iscream.client;
2 > package uk.org.iscream.cms.server.client;
3  
4   //---IMPORTS---
5 < import uk.ac.ukc.iscream.componentmanager.*;
6 < import uk.ac.ukc.iscream.core.*;
7 < import uk.ac.ukc.iscream.util.*;
5 > import uk.org.iscream.cms.server.componentmanager.*;
6 > import uk.org.iscream.cms.server.core.*;
7 > import uk.org.iscream.cms.server.util.*;
8   import java.io.*;
9  
10   /**
# Line 13 | Line 13 | import java.io.*;
13   * @author  $Author$
14   * @version $Id$
15   */
16 < public class WebFeeder {
16 > public class WebFeeder extends Thread {
17  
18   //---FINAL ATTRIBUTES---
19  
# Line 22 | Line 22 | public class WebFeeder {
22       */
23      public static final String REVISION = "$Revision$";
24      
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 +    
35 +    /**
36 +     * The default path seperator, here for convienience
37 +     */
38 +    private final String sep = File.separator;
39 +    
40   //---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 <    public static WebFeeder getInstance() {
46 >    public synchronized static WebFeeder getInstance() {
47          if (_instance == null){
48              _instance = new WebFeeder();
49          }
# Line 36 | Line 51 | public class WebFeeder {
51      }
52  
53   //---CONSTRUCTORS---
54 <
54 >    
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      private WebFeeder() {
61          // do something, or nothing.. but must be private
62 +        // don't need to cleanup latest data
63 +        
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 +            File alertsDir = new File(rootPath, alertSubDir);
74 +            if(deleteContents(alertsDir)) {
75 +                _logger.write(this.toString(), Logger.DEBUG, "Deleted all files and directories from: "+rootPath+sep+alertSubDir);
76 +            } else {
77 +                _logger.write(this.toString(), Logger.WARNING, "Failed to delete all files and directories from: "+rootPath+sep+alertSubDir);
78 +            }
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 +        
85 +        // set our name and startup
86 +        setName("client.WebFeeder");
87 +        start();
88      }
89  
90   //---PUBLIC METHODS---
91      
92 <    // TO BE COMPLETED
93 <    // The following two methods should process and save
94 <    // XMLPackets and Alerts, in a directory structure that
95 <    // has been defined by the web page designer.
92 >    /**
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 >            // list the files and delete as appropriate
146 >            File alertsDir = new File(rootPath, alertSubDir);
147 >            // check it's a directory
148 >            if(alertsDir.isDirectory()) {
149 >                // get all the hostnames directories
150 >                File[] contents = alertsDir.listFiles();
151 >                for(int i=0; i < contents.length; i++) {
152 >                    // get a single directory from the array..
153 >                    File hostdir = contents[i];
154 >                    // ..and check it's a directory
155 >                    if(hostdir.isDirectory()) {
156 >                        // if this is set, we clean files older than it
157 >                        long deleteFiles = -1;
158 >                        // get all the contents of that directory
159 >                        File[] hostdirContents = hostdir.listFiles();
160 >                        for(int j=0; j < hostdirContents.length; j++) {
161 >                            File alertFile = hostdirContents[j];
162 >                            // get the filename..
163 >                            String filename = alertFile.getName();
164 >                            // ..and see if it ends with OK or FINAL
165 >                            if(filename.endsWith(Alert.alertLevels[0]) ||
166 >                               filename.endsWith(Alert.alertLevels[Alert.alertLevels.length-1])) {
167 >                                // it does end with either OK or FINAL
168 >                                // ... so we can check it for deletion
169 >                                long lastModified = alertFile.lastModified();
170 >                                long age = System.currentTimeMillis() - lastModified;
171 >                                if(age > ((long) deleteOlderThan*1000)) {
172 >                                    // if we're on a final heartbeat, we probably want to
173 >                                    // clean up any stale alerts left behind
174 >                                    // by setting this flag, we'll clean them up on leaving this loop
175 >                                    if(filename.endsWith(".HB."+Alert.alertLevels[Alert.alertLevels.length-1])) {
176 >                                        // we do this so that delete files is set to the
177 >                                        // latest date of a HB.FINAL. There should only be
178 >                                        // one of them though :)
179 >                                        if(lastModified > deleteFiles) {
180 >                                            deleteFiles = lastModified;
181 >                                        }
182 >                                    }
183 >                                    // it's also older than our age to delete older than
184 >                                    if(!alertFile.delete()) {
185 >                                        _logger.write(this.toString(), Logger.WARNING, "Failed to delete the following 'old' alert file: "+alertFile.getPath());
186 >                                    }
187 >                                }
188 >                            }
189 >                        }
190 >                        // cleanup stale alerts
191 >                        if(deleteFiles >= 0) {
192 >                            File[] remainingHostdirContents = hostdir.listFiles();
193 >                            for(int j=0; j < remainingHostdirContents.length; j++) {
194 >                                File alertFile = remainingHostdirContents[j];
195 >                                if(alertFile.lastModified() < deleteFiles) {
196 >                                    // alert file is older than the most recent
197 >                                    // FINAL Heartbeat alert.
198 >                                    if(alertFile.delete()) {
199 >                                        _logger.write(this.toString(), Logger.DEBUG, "Deleted stale alert file: "+alertFile.getPath());
200 >                                    }
201 >                                    else {
202 >                                        _logger.write(this.toString(), Logger.WARNING, "Failed to delete the following 'stale' alert file: "+alertFile.getPath());
203 >                                    }
204 >                                }
205 >                            }
206 >                        }
207 >                        // ---- RECAP ----
208 >                        // at this point, we have cleaned up any OK or FINAL alerts
209 >                        // that have passed our age limit. We have then cleaned up
210 >                        // any alerts older the most recent Heartbeat FINAL alert,
211 >                        // as these are probably stale. Any files left are valid and
212 >                        // active alerts. We are now in a position to remove the host
213 >                        // directory if it's empty.
214 >                        // ---------------
215 >                        // do a quick check to see if the directory is now empty
216 >                        File[] newHostdirContents = hostdir.listFiles();
217 >                        if(newHostdirContents.length == 0) {
218 >                            // it does seem to be, try and delete it
219 >                            // this will fail anyway if files still remain
220 >                            if(!hostdir.delete()) {
221 >                                _logger.write(this.toString(), Logger.WARNING, "Failed to delete the following empty host directory: "+hostdir.getPath());
222 >                            }
223 >                        }
224 >                    }
225 >                }
226 >            }
227 >            else {
228 >                _logger.write(toString(), Logger.WARNING, "IO error reading alerts directory, maybe it doesn't exist? : " +rootPath+sep+alertSubDir);
229 >            }
230 >        }
231 >    }
232      
233 <    // There may also be need to have a Thread to grab any
234 <    // required config (groups, "nice names, etc) and dump
235 <    // that to a file.
236 <    
233 >    /**
234 >     * Handles an XMLPacket. This will write it out to disk
235 >     * in an appropriate manner.
236 >     *
237 >     * @param packet the XMLPacket to write
238 >     */
239      public void receiveXMLPacket(XMLPacket packet) {
240          String packetType = packet.getParam("packet.attributes.type");
241          if(packetType == null || !packetType.equals("data")) {
# Line 76 | Line 260 | public class WebFeeder {
260          String data = packet.printAll();
261          String hostname = packet.getParam("packet.attributes.machine_name");
262          // set paths
263 <        String destDir = rootPath+"/"+latestSubDir+"/"+hostname;
264 <        String destFile = destDir+"/"+latestFileName;
265 <        // try to create directory
266 <        File outDir = new File(destDir);
83 <        if(!outDir.exists()) {
84 <            if(!outDir.mkdirs()) {
85 <                // didn't exist, and we couldn't make it
86 <                _logger.write(this.toString(), Logger.ERROR, "Failed to create directory: "+outDir.getPath());
87 <                // bail out
88 <                return;
89 <            }
90 <        }
91 <        // directory has been made, check file exists
92 <        File outFile = new File(destFile);
93 <        if(!outFile.exists()) {
94 <            try {
95 <                outFile.createNewFile();
96 <            } catch (IOException e) {
97 <                _logger.write(this.toString(), Logger.ERROR, "Failed to create file: "+e);
98 <                // bail out
99 <                return;
100 <            }
101 <        }
102 <        // file should now exist
103 <        if(outFile.canWrite()) {
104 <            PrintWriter out;
105 <            try {
106 <                out = new PrintWriter(new FileWriter(outFile));
107 <                out.println(data);
108 <                out.close();
109 <            } catch (IOException e) {
110 <                _logger.write(this.toString(), Logger.ERROR, "Failed to write file: "+e);
111 <            }
112 <        }
113 <        else {
114 <            _logger.write(this.toString(), Logger.ERROR, "File not writeable: "+outFile.getPath());
115 <        }
263 >        File outDir = new File(rootPath, latestSubDir+sep+hostname);
264 >        File outFile = new File(rootPath, latestSubDir+sep+hostname+sep+latestFileName);
265 >        // write the data out
266 >        writeData(outDir, outFile, data);
267      }
268      
269 +    /**
270 +     * Handles an Alert. This will write it out to disk
271 +     * in an appropriate manner.
272 +     *
273 +     * @param alert the Alert object to write
274 +     */
275      public void receiveAlert(Alert alert) {
276          // get config proxy
277          ConfigurationProxy cp = ConfigurationProxy.getInstance();
# Line 133 | Line 290 | public class WebFeeder {
290          String data = alert.printAll();
291          String hostname = alert.getSource();
292          // set paths
293 <        String destDir = rootPath+"/"+alertSubDir+"/"+hostname;
294 <        String destFile = destDir+"/"+alertFileName;
293 >        File outDir = new File(rootPath, alertSubDir+sep+hostname);
294 >        String destFile = alertSubDir+sep+hostname+sep+alertFileName+"."+String.valueOf(alert.getInitialAlertTime());
295 >        File outFile;
296 >        // check if we're at a special "end case" (OK or FINAL)
297 >        if(alert.getLevel()==0 || alert.getLevel()==Alert.alertLevels.length-1) {
298 >            if(alert.getAttributeName().equals("Heartbeat") && alert.getLevel()==Alert.alertLevels.length-1) {
299 >                // new file is something like alert.nnnnnnnn.HB.FINAL
300 >                outFile = new File(rootPath, destFile+".HB."+Alert.alertLevels[alert.getLevel()]);
301 >            } else {
302 >                // new file is something like alert.nnnnnnnn.OK
303 >                outFile = new File(rootPath, destFile+"."+Alert.alertLevels[alert.getLevel()]);
304 >            }
305 >            File oldFile = new File(rootPath, destFile);
306 >            if(!oldFile.renameTo(outFile)) {
307 >                _logger.write(this.toString(), Logger.WARNING, "Failed to rename old file, "+oldFile.getPath()+" to new file, "+outFile.getPath());
308 >            }
309 >        } else {
310 >            outFile = new File(rootPath, destFile);
311 >        }
312 >        // write the data out
313 >        writeData(outDir, outFile, data);
314 >    }
315 >    
316 >    /**
317 >     * Overrides the {@link java.lang.Object#toString() Object.toString()}
318 >     * method to provide clean logging (every class should have this).
319 >     *
320 >     * This uses the uk.org.iscream.cms.server.util.FormatName class
321 >     * to format the toString()
322 >     *
323 >     * @return the name of this class and its CVS revision
324 >     */
325 >    public String toString() {
326 >        return FormatName.getName(
327 >            _name,
328 >            getClass().getName(),
329 >            REVISION);
330 >    }
331 >
332 > //---PRIVATE METHODS---
333 >    
334 >    /**
335 >     * Attempts to write "data" to "outFile" in "outDir".
336 >     *
337 >     * Performs checks to create the directories, and the file.
338 >     * Does not "return" anything to indicate failure or success.
339 >     *
340 >     * @param outDir the directory to put the file in
341 >     * @param outFile the filename to put the data in
342 >     * @param data the String of data to write
343 >     */
344 >    private void writeData(File outDir, File outFile, String data) {
345          // try to create directory
139        File outDir = new File(destDir);
346          if(!outDir.exists()) {
347              if(!outDir.mkdirs()) {
348                  // didn't exist, and we couldn't make it
# Line 146 | Line 352 | public class WebFeeder {
352              }
353          }
354          // directory has been made, check file exists
149        File outFile = new File(destFile);
355          if(!outFile.exists()) {
356              try {
357                  outFile.createNewFile();
# Line 160 | Line 365 | public class WebFeeder {
365          if(outFile.canWrite()) {
366              PrintWriter out;
367              try {
368 <                out = new PrintWriter(new FileWriter(outFile.getPath(), true));
368 >                out = new PrintWriter(new FileWriter(outFile));
369                  out.println(data);
370                  out.close();
371              } catch (IOException e) {
# Line 173 | Line 378 | public class WebFeeder {
378      }
379      
380      /**
381 <     * Overrides the {@link java.lang.Object#toString() Object.toString()}
382 <     * method to provide clean logging (every class should have this).
381 >     * Iterates through dir (a directory) and deletes
382 >     * all files and subdirectories.
383       *
384 <     * This uses the uk.ac.ukc.iscream.util.FormatName class
385 <     * to format the toString()
181 <     *
182 <     * @return the name of this class and its CVS revision
384 >     * @param dir the directory to clear
385 >     * @return true if it succeeded
386       */
387 <    public String toString() {
388 <        return FormatName.getName(
389 <            _name,
390 <            getClass().getName(),
391 <            REVISION);
387 >    private boolean deleteContents(File dir) {
388 >        boolean success = true;
389 >        if(dir.isDirectory()) {
390 >            // is a directory
391 >            File[] contents = dir.listFiles();
392 >            for(int i=0; i < contents.length; i++) {
393 >                File sub = contents[i];
394 >                if(sub.isDirectory()) {
395 >                    // lets get recursive
396 >                    success = success & deleteContents(sub);
397 >                }
398 >                // it's a file or empty dir
399 >                success = success & sub.delete();
400 >            }
401 >        }
402 >        else {
403 >            // not a directory?
404 >            success=false;
405 >        }
406 >        return success;
407      }
408 <
191 < //---PRIVATE METHODS---
192 <
408 >        
409   //---ACCESSOR/MUTATOR METHODS---
410  
411   //---ATTRIBUTES---

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines