ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/experimental/server/Logger/FileLog.java
Revision: 1.1
Committed: Mon Nov 6 21:28:53 2000 UTC (24 years ago) by tdb
Branch: MAIN
CVS Tags: PROJECT_COMPLETION, HEAD
Log Message:
File Logging implementation of the logging mechanism interface.

File Contents

# Content
1 import java.util.Date;
2 import java.text.DateFormat;
3 import java.util.Locale;
4 import java.io.BufferedWriter;
5 import java.io.File;
6 import java.io.FileWriter;
7 import java.io.IOException;
8
9 /**
10 * FileLog <br> <br>
11 *
12 * The FileLog class is an implementation of the Log interface, and as the
13 * name suggest writes all output to a file. The filename is specified
14 * during construction, and there is no default for a no-arg constructor.
15 * Various checks are carried out to check that writing will be possible and
16 * an IOException is thrown if for some reason it fails. If the file exists
17 * then the write() method will append to it. <br> <br>
18 *
19 * Revision History: <br>
20 * 1.8 - Added a fix to the write() method to ensure log is synchronised correctly [28/04/00] <br>
21 * 1.7 - Added suspend() and resume() methods [26/04/00] <br>
22 * 1.6 - Added open() method so that a new log file can be opened after a close() [26/04/00] <br>
23 * 1.5 - Made sure writing cannot be attempted when logfile not open [26/04/00] <br>
24 * 1.4 - Method of clearing the logfile improved [26/04/00] <br>
25 * 1.3 - Improved javadoc comments and tidied up [26/04/00] <br>
26 * 1.2 - Used the .newLine() method to write a new line, rather than \n [14/04/00] <br>
27 * 1.1 - Used an interface to create seperate File & Screen logs [15/03/00] <br>
28 * 1.0 - Original File-only version <br>
29 *
30 * @author T.D.Bishop [tdb1@ukc.ac.uk]
31 * @version 1.8, 28/04/2000
32 */
33 public class FileLog implements Log {
34
35 /**
36 * This attribute is used by the Server class to print out versions
37 * of all class files that form the server on startup.
38 */
39 public static String version = "1.8, 28/04/2000";
40
41 /**
42 * The constructor checks that writing will be ok, then sets up the
43 * writer. It makes use of the fileCheck() method found later on to
44 * ensure writing will be ok, and throws an IOException if there is
45 * a problem. Errors at this stage cannot be logged because the
46 * logging mechanism has not be setup completely, so any problems
47 * are printed to the screen in the same format used for logging.
48 *
49 * @param filename The filename to which logging should be written.
50 * @throws IOException if there is a problem with the file check.
51 */
52 public FileLog(String filename) throws IOException{
53 this.filename = filename;
54 // Perform file check to make sure writing is ok
55 if(!fileCheck()){
56 // Have to system.out.println errors because logging mechanism failed !
57 System.out.println(formatLogLine(this, "File check failed, construction terminated"));
58 throw new IOException("File check failed, unable to create FileLog");
59 }
60 try{
61 // Setup the writer
62 writer = new BufferedWriter(new FileWriter(filename, true));
63 // File is now open
64 open = true;
65 }
66 catch(IOException e){
67 System.out.println(formatLogLine(this, "Attemp to setup writer failed: "+e.getMessage()));
68 }
69 // Put an initial line into the log
70 write(this, "Logging initialised");
71 }
72
73 /**
74 * The write() method writes a line of log to the file, prepending
75 * it with some information about where to line came from and the
76 * date. This formatting is handled by the formatLogLine() method.
77 * There is some synchronisation here due to problems with the logfiles
78 * having multiple lines written on the same line, followed by dotted
79 * newlines in the wrong places. This is due to this method being
80 * called by multiple threads.
81 *
82 * @param source A reference to the source of the message.
83 * @param input The message to be logged.
84 */
85 public void write(Object source, String input){
86 // Check to make sure file is open
87 if(open){
88 // Produce a nicely formatted line for the logfile
89 String line = formatLogLine(source, input);
90 try{
91 // We have to synchronize here due to problems with two write()'s being called before a newLine()
92 synchronized(writer){
93 // Attempt to write the line
94 writer.write(line);
95 // Best to use newLine() as it will use the correct platform encoding
96 writer.newLine();
97 }
98 // Make sure the line is written immeidiately
99 writer.flush();
100 }
101 catch(IOException e){
102 // We'd best log the error
103 System.out.println(formatLogLine(this, "Writing to logfile failed: "+e.getMessage()));
104 // As it's an IOException we should suspend logging
105 open = false;
106 }
107 }
108 else{
109 // If file is not open we should print this to the screen
110 System.out.println(formatLogLine(this, "Write failed: file not open"));
111 }
112 }
113
114 /**
115 * This method generates a nicely formatted line for the logfile,
116 * including the date/time and the source of the message. The date
117 * and time are formatted using the DateFormat class, and the source
118 * class is formatted using the toString() method found in every
119 * source file for the server. This is then prepended to the message
120 * and returned.
121 *
122 * @param source A reference to the source of the message.
123 * @param input The message to be logged.
124 * @return The string to be written to the log.
125 */
126 private String formatLogLine(Object source, String input){
127 // Construct the date string using the DateFormat class
128 String date = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(new Date());
129 // Return the date, the toString() of the source and the input
130 return "[" + date + "] " + source.toString() + ": " + input;
131 }
132
133 /**
134 * The toString() method returns the name of the Class for formatting
135 * when it writes to the logfile. <br>
136 *
137 * @return The formatted string identifying this Class.
138 */
139 public String toString(){
140 return this.getClass().getName();
141 }
142
143 /**
144 * The clear() method erases the contents of the logfile. It does
145 * this in a very clumsy way - by closing the writer and opening a
146 * new one which is set not to append. This results in the logfile
147 * being overwritten, which effectively erases it.
148 */
149 public void clear(){
150 // Check file is open
151 if(open){
152 write(this, "Attempting to clear logfile");
153 try{
154 // Close appending writer
155 open = false;
156 writer.close();
157 // Open a non-appending writer
158 writer = new BufferedWriter(new FileWriter(filename));
159 open = true;
160 }
161 catch(IOException e){
162 // We'd best log the error
163 write(this, "Attempt to clear logfile failed: "+e.getMessage());
164 // As it's an IOException we should suspend logging
165 open = false;
166 }
167 }
168 else{
169 // If file is not open we should print this to the screen
170 System.out.println(formatLogLine(this, "Clearing failed: file not open"));
171 }
172 }
173
174 /**
175 * The close() method closes the logfile and no more data can be written.
176 * If writing is attempted after close() has been called an error will be
177 * generated. The open() method can be used to reopen or open a new file.
178 */
179 public void close(){
180 // Check to see if a file is open
181 if(open){
182 write(this, "Attempting to terminate logging");
183 try{
184 open = false;
185 writer.close();
186 }
187 catch(IOException e){
188 write(this, "Attempt to close logfile failed: "+e.getMessage());
189 // As it's an IOException we should suspend logging
190 open = false;
191 }
192 }
193 else{
194 // If file is not open we should print this to the screen
195 System.out.println(formatLogLine(this, "Close failed: file not open"));
196 }
197 }
198
199 /**
200 * The open() method opens a new file after the close() method has
201 * been called on the FileLog. This enables the user to easily change
202 * the file to which the log is being written. An error is generated
203 * if a file is already open.
204 *
205 * @param filename The new file to write to.
206 * @throws IOException if the file cannot be written to.
207 */
208 public void open(String filename) throws IOException{
209 // Check to see if a file is open
210 if(open){
211 // If file is already open then we should log that this went wrong
212 write(this, "Open failed: a file is already open");
213 }
214 else{
215 this.filename = filename;
216 if(!fileCheck()) {
217 // Have to system.out.println errors because logging mechanism failed !
218 System.out.println(formatLogLine(this, "File check failed, construction terminated"));
219 throw new IOException("File check failed, unable to create FileLog");
220 }
221 try{
222 // Setup the writer
223 writer = new BufferedWriter(new FileWriter(filename, true));
224 // File is now open
225 open = true;
226 }
227 catch(IOException e){
228 System.out.println(formatLogLine(this, "Attempt to open writer failed: "+e.getMessage()));
229 }
230 }
231 }
232
233 /**
234 * The suspend() method halts writing to the file by setting the open
235 * boolean to false, and thus blocking the write() method. A line is
236 * written to the logfile beforehand to note that writing has been
237 * suspended.
238 */
239 public void suspend(){
240 // Check to see if a file is open
241 if(open){
242 // Make a note of the fact that writing has been suspended
243 write(this, "Writing suspended");
244 // Make sure writing not permitted
245 open=false;
246 }
247 else{
248 // If file is not open we should print this to the screen
249 System.out.println(formatLogLine(this, "Suspend failed: file not open"));
250 }
251 }
252
253 /**
254 * The resume() method resumes writing to the file by setting the open
255 * boolean to true. A line is written to the logfile to signify this
256 * event occuring.
257 */
258 public void resume(){
259 // Check to see if a file is open
260 if(open){
261 // If file is open we should print this to the screen
262 System.out.println(formatLogLine(this, "Resume failed: file open"));
263 }
264 else{
265 // Permit writing again
266 open=true;
267 // Make a note of the fact that writing has been resumed
268 write(this, "Writing resumed");
269 }
270 }
271
272 /**
273 * The fileCheck() method is used to ensure that writing is ok. It
274 * performs so basic checks to make sure that if the file exists
275 * it can be written to, and if not a new file is created. A boolean
276 * result is returned to signify success or failure.
277 *
278 * @return A boolean value signify whether the test was sucessful.
279 */
280 private boolean fileCheck(){
281 boolean fileOK = false;
282 try{
283 File file = new File(filename);
284
285 // File already exists
286 if(file.exists()) {
287 /* Only want success if it is a file (not a directory)
288 * and can be written to.
289 */
290 if(file.isFile() && file.canWrite()) {
291 fileOK = true;
292 }
293 }
294 // Create a new file and suceed
295 else{
296 file.createNewFile();
297 fileOK = true;
298 }
299 }
300 catch(IOException e){
301 System.out.println(formatLogLine(this, "File check failed: "+e.getMessage()));
302 }
303
304 return fileOK;
305 }
306
307 /**
308 * The filename of the currently open, or last open, file.
309 */
310 private String filename;
311
312 /**
313 * A reference to the writer being used.
314 */
315 private BufferedWriter writer;
316
317 /**
318 * A boolean signifying whether a file is open or not.
319 */
320 private boolean open = false;
321
322 }