00001 /** 00002 * C-JDBC: Clustered JDBC. 00003 * Copyright (C) 2002-2004 French National Institute For Research In Computer 00004 * Science And Control (INRIA). 00005 * Contact: c-jdbc@objectweb.org 00006 * 00007 * This library is free software; you can redistribute it and/or modify it 00008 * under the terms of the GNU Lesser General Public License as published by the 00009 * Free Software Foundation; either version 2.1 of the License, or any later 00010 * version. 00011 * 00012 * This library is distributed in the hope that it will be useful, but WITHOUT 00013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 00015 * for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public License 00018 * along with this library; if not, write to the Free Software Foundation, 00019 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00020 * 00021 * Initial developer(s): Jim Moore 00022 * Contributor(s): Nicolas Modrzyk 00023 */ 00024 00025 package org.objectweb.cjdbc.common.util; 00026 00027 import java.io.IOException; 00028 import java.io.OutputStream; 00029 00030 import org.apache.log4j.Category; 00031 import org.apache.log4j.Priority; 00032 00033 /** 00034 * An OutputStream that flushes out to a Category. 00035 * <p> 00036 * Note that no data is written out to the Category until the stream is flushed 00037 * or closed. 00038 * <p> 00039 * 00040 * @author <a href="mailto://Jim.Moore@rocketmail.com">Jim Moore</a> 00041 * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk</a> 00042 * 00043 * @see Category 00044 */ 00045 public class LoggingOutputStream extends OutputStream 00046 { 00047 protected static final String LINE_SEPERATOR = System 00048 .getProperty("line.separator"); 00049 /** 00050 * Used to maintain the contract of {@link #close()}. 00051 */ 00052 protected boolean hasBeenClosed = false; 00053 /** 00054 * The internal buffer where data is stored. 00055 */ 00056 protected byte[] buf; 00057 /** 00058 * The number of valid bytes in the buffer. This value is always in the range 00059 * <tt>0</tt> through <tt>buf.length</tt>; elements <tt>buf[0]</tt> 00060 * through <tt>buf[count-1]</tt> contain valid byte data. 00061 */ 00062 protected int count; 00063 /** 00064 * Remembers the size of the buffer for speed. 00065 */ 00066 private int bufLength; 00067 /** 00068 * The default number of bytes in the buffer. =2048 00069 */ 00070 public static final int DEFAULT_BUFFER_LENGTH = 2048; 00071 /** 00072 * The category to write to. 00073 */ 00074 protected Category category; 00075 /** 00076 * The priority to use when writing to the Category. 00077 */ 00078 protected Priority priority; 00079 00080 private LoggingOutputStream() 00081 { 00082 // illegal 00083 } 00084 00085 /** 00086 * Creates the LoggingOutputStream to flush to the given Category. 00087 * 00088 * @param cat the Category to write to 00089 * @param priority the Priority to use when writing to the Category 00090 * @exception IllegalArgumentException if cat == null or priority == null 00091 */ 00092 public LoggingOutputStream(Category cat, Priority priority) 00093 throws IllegalArgumentException 00094 { 00095 if (cat == null) 00096 { 00097 throw new IllegalArgumentException("cat == null"); 00098 } 00099 if (priority == null) 00100 { 00101 throw new IllegalArgumentException("priority == null"); 00102 } 00103 this.priority = priority; 00104 category = cat; 00105 bufLength = DEFAULT_BUFFER_LENGTH; 00106 buf = new byte[DEFAULT_BUFFER_LENGTH]; 00107 count = 0; 00108 } 00109 00110 /** 00111 * Closes this output stream and releases any system resources associated 00112 * with this stream. The general contract of <code>close</code> is that it 00113 * closes the output stream. A closed stream cannot perform output operations 00114 * and cannot be reopened. 00115 */ 00116 public void close() 00117 { 00118 flush(); 00119 hasBeenClosed = true; 00120 } 00121 00122 /** 00123 * Writes the specified byte to this output stream. The general contract for 00124 * <code>write</code> is that one byte is written to the output stream. The 00125 * byte to be written is the eight low-order bits of the argument <code>b</code>. 00126 * The 24 high-order bits of <code>b</code> are ignored. 00127 * 00128 * @param b the <code>byte</code> to write 00129 * @exception IOException if an I/O error occurs. In particular, an <code>IOException</code> 00130 * may be thrown if the output stream has been closed. 00131 */ 00132 public void write(final int b) throws IOException 00133 { 00134 if (hasBeenClosed) 00135 { 00136 throw new IOException("The stream has been closed."); 00137 } 00138 // don't log nulls 00139 if (b == 0) 00140 { 00141 return; 00142 } 00143 // would this be writing past the buffer? 00144 if (count == bufLength) 00145 { 00146 // grow the buffer 00147 final int newBufLength = bufLength + DEFAULT_BUFFER_LENGTH; 00148 final byte[] newBuf = new byte[newBufLength]; 00149 System.arraycopy(buf, 0, newBuf, 0, bufLength); 00150 buf = newBuf; 00151 bufLength = newBufLength; 00152 } 00153 buf[count] = (byte) b; 00154 count++; 00155 } 00156 00157 /** 00158 * Flushes this output stream and forces any buffered output bytes to be 00159 * written out. The general contract of <code>flush</code> is that calling 00160 * it is an indication that, if any bytes previously written have been 00161 * buffered by the implementation of the output stream, such bytes should 00162 * immediately be written to their intended destination. 00163 */ 00164 public void flush() 00165 { 00166 if (count == 0) 00167 { 00168 return; 00169 } 00170 // don't print out blank lines; flushing from PrintStream puts out these 00171 if (count == LINE_SEPERATOR.length()) 00172 { 00173 if (((char) buf[0]) == LINE_SEPERATOR.charAt(0) && ((count == 1) || // <- 00174 // Unix 00175 // & 00176 // Mac, 00177 // -> 00178 // Windows 00179 ((count == 2) && ((char) buf[1]) == LINE_SEPERATOR.charAt(1)))) 00180 { 00181 reset(); 00182 return; 00183 } 00184 } 00185 final byte[] theBytes = new byte[count]; 00186 System.arraycopy(buf, 0, theBytes, 0, count); 00187 00188 // ADDED: We don't want blank lines at all 00189 String bytes = new String(theBytes).trim(); 00190 int line = -1; 00191 while((line = bytes.indexOf(LINE_SEPERATOR))!=-1) 00192 { 00193 bytes = bytes.substring(0, line) + bytes.substring(line+LINE_SEPERATOR.length()); 00194 } 00195 // END ADDED 00196 00197 category.log(priority, bytes); 00198 reset(); 00199 } 00200 00201 private void reset() 00202 { 00203 // not resetting the buffer -- assuming that if it grew that it 00204 // will likely grow similarly again 00205 count = 0; 00206 } 00207 }