View Javadoc

1   // 
2   // Copyright (c) 2003,2004 , Caltha - Gajda, Krzewski, Mach, Potempski Sp.J. 
3   // All rights reserved. 
4   // 
5   // Redistribution and use in source and binary forms, with or without modification,  
6   // are permitted provided that the following conditions are met: 
7   //  
8   // * Redistributions of source code must retain the above copyright notice,  
9   //	 this list of conditions and the following disclaimer. 
10  // * Redistributions in binary form must reproduce the above copyright notice,  
11  //	 this list of conditions and the following disclaimer in the documentation  
12  //	 and/or other materials provided with the distribution. 
13  // * Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.  
14  //	 nor the names of its contributors may be used to endorse or promote products  
15  //	 derived from this software without specific prior written permission. 
16  // 
17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
18  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
19  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
20  // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  
21  // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  
22  // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
23  // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
24  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
25  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
26  // POSSIBILITY OF SUCH DAMAGE. 
27  // 
28  package org.objectledge.logging;
29  
30  import java.io.BufferedWriter;
31  import java.io.IOException;
32  import java.io.Writer;
33  
34  import org.apache.log4j.RollingFileAppender;
35  import org.apache.log4j.helpers.CountingQuietWriter;
36  import org.apache.log4j.helpers.LogLog;
37  import org.objectledge.filesystem.FileSystem;
38  
39  /***
40   * A derivate of log4j.RollingFileAppender that accepts paths within Ledge file system.
41   *
42   * @author <a href="mailto:rafal@caltha.pl">Rafal Krzewski</a>
43   * @version $Id: LedgeRollingFileAppender.java,v 1.5 2004/12/22 08:34:55 rafal Exp $
44   */
45  public class LedgeRollingFileAppender
46  	extends RollingFileAppender
47  {
48      private FileSystem fileSystem;
49      
50      /***
51       * Creates new LedgeRollingFileAppender instance.
52       * 
53       * @param fileSystem the Ledge FileSystem.
54       */
55      public LedgeRollingFileAppender(FileSystem fileSystem)
56      {
57          this.fileSystem = fileSystem;
58      }
59  
60      /***
61       * <p>
62       * Sets and <i>opens </i> the file where the log output will go. The specified file must be
63       * writable.
64       * 
65       * <p>
66       * If there was already an opened file, then the previous file is closed first.
67       * 
68       * <p>
69       * <b>Do not use this method directly. To configure a FileAppender or one of its subclasses, set
70       * its properties one by one and then call activateOptions. </b>
71       * 
72       * @param fileName The path to the log file.
73       * @param append If true will append to fileName. Otherwise will truncate fileName.
74       * @param bufferedIO If true buffered IO will be used.
75       * @param bufferSize the size of buffer in bytes.
76       * @throws IOException if setting up the file IO fails.
77       */
78      public synchronized void setFile(String fileName, boolean append, boolean bufferedIO,
79          int bufferSize) throws IOException
80      {
81          LogLog.debug("setFile called: " + fileName + ", " + append);
82  
83          // It does not make sense to have immediate flush and bufferedIO.
84          if(bufferedIO)
85          {
86              setImmediateFlush(false);
87          }
88  
89          reset();
90          Writer fw = createWriter(fileSystem.getOutputStream(fileName, append));
91          if(bufferedIO)
92          {
93              fw = new BufferedWriter(fw, bufferSize);
94          }
95          this.setQWForFiles(fw);
96          this.fileName = fileName;
97          this.fileAppend = append;
98          this.bufferedIO = bufferedIO;
99          this.bufferSize = bufferSize;
100         writeHeader();
101         LogLog.debug("setFile ended");
102     }    
103 
104     /***
105      * Implements the usual roll over behaviour.
106      * 
107      * <p>
108      * If <code>MaxBackupIndex</code> is positive, then files {<code>File.1</code>, ...,
109      * <code>File.MaxBackupIndex -1</code>} are renamed to {<code>File.2</code>, ...,
110      * <code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is renamed
111      * <code>File.1</code> and closed. A new <code>File</code> is created to receive further log
112      * output.
113      * 
114      * <p>
115      * If <code>MaxBackupIndex</code> is equal to zero, then the <code>File</code> is truncated
116      * with no backup files created.
117      *  
118      */
119     public// synchronization not necessary since doAppend is alreasy synched
120     void rollOver()
121     {
122         String file;
123         String target;
124         
125         LogLog.debug("rolling over count=" + ((CountingQuietWriter)qw).getCount());
126         LogLog.debug("maxBackupIndex=" + maxBackupIndex);
127 
128         try
129         {
130             // If maxBackups <= 0, then there is no file renaming to be done.
131             if(maxBackupIndex > 0)
132             {
133                 // Delete the oldest file, to keep Windows happy.
134                 file = fileName + '.' + maxBackupIndex;
135                 if(fileSystem.exists(file)) 
136                 {
137                     fileSystem.delete(file);
138                 }
139 
140                 // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
141                 for (int i = maxBackupIndex - 1; i >= 1; i--)
142                 {
143                     file = fileName + "." + i;
144                     if(fileSystem.exists(file))
145                     {
146                         target = fileName + '.' + (i + 1);
147                         LogLog.debug("Renaming file " + file + " to " + target);
148                         fileSystem.rename(file, target);
149                     }
150                 }
151 
152                 // Rename fileName to fileName.1
153                 target = fileName + "." + 1;
154 
155                 this.closeFile(); // keep windows happy.
156 
157                 file = fileName;
158                 LogLog.debug("Renaming file " + file + " to " + target);
159                 fileSystem.rename(file, target);
160             }
161         }
162         catch(Exception e)
163         {
164             LogLog.error("rollover operations failed", e);
165         }
166 
167         try
168         {
169             // This will also close the file. This is OK since multiple
170             // close operations are safe.
171             this.setFile(fileName, false, bufferedIO, bufferSize);
172         }
173         catch(IOException e)
174         {
175             LogLog.error("setFile(" + fileName + ", false) call failed.", e);
176         }
177     }    
178 }