View Javadoc

1   /*
2    * This file is part of AceLogger.
3    * 
4    * AceLogger is free software: you can redistribute it and/or modify it under the terms of the GNU
5    * Lesser General Public License as published by the Free Software Foundation, either version 3 of
6    * the License, or (at your option) any later version.
7    * 
8    * AceLogger is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
9    * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10   * Lesser General Public License for more details.
11   * 
12   * You should have received a copy of the GNU Lesser General Public License along with AceLogger.
13   * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
14   */
15  package net.sourceforge.acelogger.appender;
16  
17  import java.io.File;
18  import java.io.FileOutputStream;
19  import java.io.RandomAccessFile;
20  import java.io.Writer;
21  import java.nio.channels.Channels;
22  import java.nio.channels.WritableByteChannel;
23  import java.text.MessageFormat;
24  import java.util.Date;
25  
26  import net.sourceforge.acelogger.LogEvent;
27  import net.sourceforge.acelogger.execution.LogController;
28  import net.sourceforge.acelogger.execution.manager.ExecutorManager;
29  import net.sourceforge.acelogger.formatter.Formatter;
30  
31  // FIXME: this is only a POC... don't take it seriously
32  public class TextFileAppender extends BaseAppender {
33  
34  	private static final String DEFAULT_CHARSET = "UTF-8";
35  
36  	private static final String HEADER = "# {1}: created on {0,date,yyyy-MM-dd HH:mm:ss,SSS} by {2}\n";
37  
38  	private static final String FOOTER = "# last updated on {0,date,yyyy-MM-dd HH:mm:ss,SSS}\n";
39  
40  	private String fileName;
41  
42  	private WritableByteChannel fileChannel;
43  
44  	private Writer fileWriter;
45  
46  	private boolean newFile;
47  
48  	public TextFileAppender(String identifier, String fileName, Formatter formatter,
49  			ExecutorManager executor) {
50  		super(identifier, formatter, executor);
51  		this.fileName = fileName;
52  		newFile = false;
53  		super.initialize();
54  	}
55  
56  	/* 0: date, 1: fileName, 2: this class Class */
57  	private String getHeader() {
58  		return MessageFormat.format(HEADER, new Date(), fileName, TextFileAppender.class);
59  	}
60  
61  	private String getFooter() {
62  		return MessageFormat.format(FOOTER, new Date(), fileName, TextFileAppender.class);
63  	}
64  
65  	/** {@inheritDoc} */
66  	@Override
67  	protected Runnable openProcess() {
68  		final Runnable openFileProcess = new Runnable() {
69  			public void run() {
70  				try {
71  					File file = new File(fileName);
72  					if (!file.exists()) {
73  						if (file.getParentFile() != null && !file.getParentFile().exists()) {
74  							file.getParentFile().mkdirs();
75  						}
76  						// Maybe someone else created the file
77  						newFile = file.createNewFile();
78  					}
79  					fileChannel = Channels.newChannel(new FileOutputStream(file, true));
80  					fileWriter = Channels.newWriter(fileChannel, DEFAULT_CHARSET);
81  					if (!newFile) {
82  						RandomAccessFile f = new RandomAccessFile(file, "rw");
83  						f.setLength(f.length() - getFooter().getBytes(DEFAULT_CHARSET).length);
84  						f.close();
85  					}
86  				} catch (Exception e) {
87  					LogController.getInternalLogger().error("Could not open file \"{0}\"",
88  							e, fileName);
89  				}
90  			}
91  		};
92  		return openFileProcess;
93  	}
94  
95  	/** {@inheritDoc} */
96  	@Override
97  	public Runnable closeProcess() {
98  		final Runnable closeFileProcess = new Runnable() {
99  			public void run() {
100 				try {
101 					fileWriter.flush();
102 					fileChannel.close();
103 				} catch (Exception e) {
104 					LogController.getInternalLogger().error("Could not close file \"{0}\"",
105 							e, fileName);
106 				}
107 			}
108 		};
109 		return closeFileProcess;
110 	}
111 
112 	/** {@inheritDoc} */
113 	@Override
114 	public Runnable appendHeaderProcess() {
115 		return new Runnable() {
116 			public void run() {
117 				try {
118 					if (newFile) {
119 						fileWriter.write(getHeader());
120 					}
121 				} catch (Exception e) {
122 					LogController.getInternalLogger().error(
123 							"Could not append header to file \"{0}\"", e, fileName);
124 				}
125 			}
126 		};
127 	}
128 
129 	/** {@inheritDoc} */
130 	@Override
131 	public Runnable appendFooterProcess() {
132 		return new Runnable() {
133 			public void run() {
134 				try {
135 					fileWriter.write(getFooter());
136 				} catch (Exception e) {
137 					LogController.getInternalLogger().error(
138 							"Could not append footer to file \"{0}\"", e, fileName);
139 				}
140 			}
141 		};
142 	}
143 
144 	/** {@inheritDoc} */
145 	public Runnable appendLogProcess(final LogEvent call) {
146 		final Runnable appendProcess = new Runnable() {
147 			public void run() {
148 				String logMessage = "";
149 				try {
150 					logMessage = getFormatter().formatLogCall(call);
151 					fileWriter.write(logMessage);
152 					// TODO: Is the flush necessary?
153 					fileWriter.flush();
154 				} catch (final Exception e) {
155 					LogController.getInternalLogger().error(
156 							"Could not append message \"{1}\" to file \"{0}\"", e, fileName,
157 							logMessage);
158 				}
159 			}
160 
161 		};
162 		return appendProcess;
163 	}
164 
165 }