JAL-3048 test updated for AlignExportSettings changes
[jalview.git] / srcjar / org / apache / log4j / FileAppender.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  * 
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package org.apache.log4j;
19
20 import java.io.BufferedWriter;
21 import java.io.File;
22 import java.io.FileNotFoundException;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.InterruptedIOException;
26 import java.io.Writer;
27
28 import org.apache.log4j.helpers.LogLog;
29 import org.apache.log4j.helpers.QuietWriter;
30 import org.apache.log4j.spi.ErrorCode;
31
32 // Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
33 //              Ben Sandee
34
35 /**
36  *  FileAppender appends log events to a file.
37  *
38  *  <p>Support for <code>java.io.Writer</code> and console appending
39  *  has been deprecated and then removed. See the replacement
40  *  solutions: {@link WriterAppender} and {@link ConsoleAppender}.
41  *
42  * @author Ceki G&uuml;lc&uuml; 
43  * */
44 public class FileAppender extends WriterAppender {
45
46   /** Controls file truncatation. The default value for this variable
47    * is <code>true</code>, meaning that by default a
48    * <code>FileAppender</code> will append to an existing file and not
49    * truncate it.
50    *
51    * <p>This option is meaningful only if the FileAppender opens the
52    * file.
53    */
54   protected boolean fileAppend = true;
55
56   /**
57      The name of the log file. */
58   protected String fileName = null;
59
60   /**
61      Do we do bufferedIO? */
62   protected boolean bufferedIO = false;
63
64   /**
65    * Determines the size of IO buffer be. Default is 8K. 
66    */
67   protected int bufferSize = 8*1024;
68
69
70   /**
71      The default constructor does not do anything.
72   */
73   public
74   FileAppender() {
75   }
76
77   /**
78     Instantiate a <code>FileAppender</code> and open the file
79     designated by <code>filename</code>. The opened filename will
80     become the output destination for this appender.
81
82     <p>If the <code>append</code> parameter is true, the file will be
83     appended to. Otherwise, the file designated by
84     <code>filename</code> will be truncated before being opened.
85
86     <p>If the <code>bufferedIO</code> parameter is <code>true</code>,
87     then buffered IO will be used to write to the output file.
88
89   */
90   public
91   FileAppender(Layout layout, String filename, boolean append, boolean bufferedIO,
92                int bufferSize) throws IOException {
93     this.layout = layout;
94     this.setFile(filename, append, bufferedIO, bufferSize);
95   }
96
97   /**
98     Instantiate a FileAppender and open the file designated by
99     <code>filename</code>. The opened filename will become the output
100     destination for this appender.
101
102     <p>If the <code>append</code> parameter is true, the file will be
103     appended to. Otherwise, the file designated by
104     <code>filename</code> will be truncated before being opened.
105   */
106   public
107   FileAppender(Layout layout, String filename, boolean append)
108                                                              throws IOException {
109     this.layout = layout;
110     this.setFile(filename, append, false, bufferSize);
111   }
112
113   /**
114      Instantiate a FileAppender and open the file designated by
115     <code>filename</code>. The opened filename will become the output
116     destination for this appender.
117
118     <p>The file will be appended to.  */
119   public
120   FileAppender(Layout layout, String filename) throws IOException {
121     this(layout, filename, true);
122   }
123
124   /**
125      The <b>File</b> property takes a string value which should be the
126      name of the file to append to.
127
128      <p><font color="#DD0044"><b>Note that the special values
129      "System.out" or "System.err" are no longer honored.</b></font>
130
131      <p>Note: Actual opening of the file is made when {@link
132      #activateOptions} is called, not when the options are set.  */
133   public void setFile(String file) {
134     // Trim spaces from both ends. The users probably does not want
135     // trailing spaces in file names.
136     String val = file.trim();
137     fileName = val;
138   }
139
140   /**
141       Returns the value of the <b>Append</b> option.
142    */
143   public
144   boolean getAppend() {
145     return fileAppend;
146   }
147
148
149   /** Returns the value of the <b>File</b> option. */
150   public
151   String getFile() {
152     return fileName;
153   }
154
155   /**
156      If the value of <b>File</b> is not <code>null</code>, then {@link
157      #setFile} is called with the values of <b>File</b>  and
158      <b>Append</b> properties.
159
160      @since 0.8.1 */
161   public
162   void activateOptions() {
163     if(fileName != null) {
164       try {
165         setFile(fileName, fileAppend, bufferedIO, bufferSize);
166       }
167       catch(java.io.IOException e) {
168         errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",
169                            e, ErrorCode.FILE_OPEN_FAILURE);
170       }
171     } else {
172       //LogLog.error("File option not set for appender ["+name+"].");
173       LogLog.warn("File option not set for appender ["+name+"].");
174       LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
175     }
176   }
177
178  /**
179      Closes the previously opened file.
180   */
181   protected
182   void closeFile() {
183     if(this.qw != null) {
184       try {
185         this.qw.close();
186       }
187       catch(java.io.IOException e) {
188           if (e instanceof InterruptedIOException) {
189               Thread.currentThread().interrupt();
190           }
191         // Exceptionally, it does not make sense to delegate to an
192         // ErrorHandler. Since a closed appender is basically dead.
193         LogLog.error("Could not close " + qw, e);
194       }
195     }
196   }
197
198   /**
199      Get the value of the <b>BufferedIO</b> option.
200
201      <p>BufferedIO will significatnly increase performance on heavily
202      loaded systems.
203
204   */
205   public
206   boolean getBufferedIO() {
207     return this.bufferedIO;
208   }
209
210
211   /**
212      Get the size of the IO buffer.
213   */
214   public
215   int getBufferSize() {
216     return this.bufferSize;
217   }
218
219
220
221   /**
222      The <b>Append</b> option takes a boolean value. It is set to
223      <code>true</code> by default. If true, then <code>File</code>
224      will be opened in append mode by {@link #setFile setFile} (see
225      above). Otherwise, {@link #setFile setFile} will open
226      <code>File</code> in truncate mode.
227
228      <p>Note: Actual opening of the file is made when {@link
229      #activateOptions} is called, not when the options are set.
230    */
231   public
232   void setAppend(boolean flag) {
233     fileAppend = flag;
234   }
235
236   /**
237      The <b>BufferedIO</b> option takes a boolean value. It is set to
238      <code>false</code> by default. If true, then <code>File</code>
239      will be opened and the resulting {@link java.io.Writer} wrapped
240      around a {@link BufferedWriter}.
241
242      BufferedIO will significatnly increase performance on heavily
243      loaded systems.
244
245   */
246   public
247   void setBufferedIO(boolean bufferedIO) {
248     this.bufferedIO = bufferedIO;
249     if(bufferedIO) {
250       immediateFlush = false;
251     }
252   }
253
254
255   /**
256      Set the size of the IO buffer.
257   */
258   public
259   void setBufferSize(int bufferSize) {
260     this.bufferSize = bufferSize;
261   }
262
263   /**
264     <p>Sets and <i>opens</i> the file where the log output will
265     go. The specified file must be writable.
266
267     <p>If there was already an opened file, then the previous file
268     is closed first.
269
270     <p><b>Do not use this method directly. To configure a FileAppender
271     or one of its subclasses, set its properties one by one and then
272     call activateOptions.</b>
273
274     @param fileName The path to the log file.
275     @param append   If true will append to fileName. Otherwise will
276         truncate fileName.  */
277   public
278   synchronized
279   void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
280                                                             throws IOException {
281     LogLog.debug("setFile called: "+fileName+", "+append);
282
283     // It does not make sense to have immediate flush and bufferedIO.
284     if(bufferedIO) {
285       setImmediateFlush(false);
286     }
287
288     reset();
289     FileOutputStream ostream = null;
290     try {
291           //
292           //   attempt to create file
293           //
294           ostream = new FileOutputStream(fileName, append);
295     } catch(FileNotFoundException ex) {
296           //
297           //   if parent directory does not exist then
298           //      attempt to create it and try to create file
299           //      see bug 9150
300           //
301           String parentName = new File(fileName).getParent();
302           if (parentName != null) {
303              File parentDir = new File(parentName);
304              if(!parentDir.exists() && parentDir.mkdirs()) {
305                 ostream = new FileOutputStream(fileName, append);
306              } else {
307                 throw ex;
308              }
309           } else {
310              throw ex;
311           }
312     }
313     Writer fw = createWriter(ostream);
314     if(bufferedIO) {
315       fw = new BufferedWriter(fw, bufferSize);
316     }
317     this.setQWForFiles(fw);
318     this.fileName = fileName;
319     this.fileAppend = append;
320     this.bufferedIO = bufferedIO;
321     this.bufferSize = bufferSize;
322     writeHeader();
323     LogLog.debug("setFile ended");
324   }
325
326
327   /**
328      Sets the quiet writer being used.
329
330      This method is overriden by {@link RollingFileAppender}.
331    */
332   protected
333   void setQWForFiles(Writer writer) {
334      this.qw = new QuietWriter(writer, errorHandler);
335   }
336
337
338   /**
339      Close any previously opened file and call the parent's
340      <code>reset</code>.  */
341   protected
342   void reset() {
343     closeFile();
344     this.fileName = null;
345     super.reset();
346   }
347 }
348