KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > LoggingOutputStream


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17
18 import java.io.*;
19 import org.apache.log4j.*;
20
21
22 /**
23  * An OutputStream that flushes out to a Category.<p>
24  *
25  * Note that no data is written out to the Category until the stream is
26  * flushed or closed.<p>
27  *
28  * Example:<pre>
29  * // make sure everything sent to System.err is logged
30  * System.setErr(new PrintStream(new LoggingOutputStream(Category.getRoot(), Priority.WARN), true));
31  *
32  * // make sure everything sent to System.out is also logged
33  * System.setOut(new PrintStream(new LoggingOutputStream(Category.getRoot(), Priority.INFO), true));
34  * </pre>
35  *
36  * @author <a HREF="mailto://Jim.Moore@rocketmail.com">Jim Moore</a>
37  * @see Category
38  */

39 public class LoggingOutputStream extends OutputStream {
40   protected static final String JavaDoc LINE_SEPERATOR = System.getProperty("line.separator");
41
42
43   /**
44    * Used to maintain the contract of {@link #close()}.
45    */

46   protected boolean hasBeenClosed = false;
47
48   /**
49    * The internal buffer where data is stored.
50    */

51   protected byte[] buf;
52
53   /**
54    * The number of valid bytes in the buffer. This value is always
55    * in the range <tt>0</tt> through <tt>buf.length</tt>; elements
56    * <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid
57    * byte data.
58    */

59   protected int count;
60
61
62   /**
63    * Remembers the size of the buffer for speed.
64    */

65   private int bufLength;
66
67   /**
68    * The default number of bytes in the buffer. =2048
69    */

70   public static final int DEFAULT_BUFFER_LENGTH = 2048;
71
72
73   /**
74    * The category to write to.
75    */

76   protected Category category;
77
78   /**
79    * The priority to use when writing to the Category.
80    */

81   protected Priority priority;
82
83
84   private LoggingOutputStream() {
85     // illegal
86
}
87
88
89   /**
90    * Creates the LoggingOutputStream to flush to the given Category.
91    *
92    * @param cat the Category to write to
93    *
94    * @param priority the Priority to use when writing to the Category
95    *
96    * @exception IllegalArgumentException
97    * if cat == null or priority == null
98    */

99   public LoggingOutputStream(Category cat, Priority priority)
100   throws IllegalArgumentException JavaDoc {
101     if (cat == null) {
102       throw new IllegalArgumentException JavaDoc("cat == null");
103     }
104     if (priority == null) {
105       throw new IllegalArgumentException JavaDoc("priority == null");
106     }
107
108     this.priority = priority;
109     category = cat;
110     bufLength = DEFAULT_BUFFER_LENGTH;
111     buf = new byte[DEFAULT_BUFFER_LENGTH];
112     count = 0;
113   }
114
115
116   /**
117    * Closes this output stream and releases any system resources
118    * associated with this stream. The general contract of <code>close</code>
119    * is that it closes the output stream. A closed stream cannot perform
120    * output operations and cannot be reopened.
121    */

122   public void close() {
123     flush();
124     hasBeenClosed = true;
125   }
126
127
128   /**
129    * Writes the specified byte to this output stream. The general
130    * contract for <code>write</code> is that one byte is written
131    * to the output stream. The byte to be written is the eight
132    * low-order bits of the argument <code>b</code>. The 24
133    * high-order bits of <code>b</code> are ignored.
134    *
135    * @param b the <code>byte</code> to write
136    *
137    * @exception IOException
138    * if an I/O error occurs. In particular,
139    * an <code>IOException</code> may be thrown if the
140    * output stream has been closed.
141    */

142   public void write(final int b) throws IOException {
143     if (hasBeenClosed) {
144       throw new IOException("The stream has been closed.");
145     }
146
147     // don't log nulls
148
if (b == 0) {
149       return;
150     }
151
152     // would this be writing past the buffer?
153
if (count == bufLength) {
154       // grow the buffer
155
final int newBufLength = bufLength+DEFAULT_BUFFER_LENGTH;
156       final byte[] newBuf = new byte[newBufLength];
157
158       System.arraycopy(buf, 0, newBuf, 0, bufLength);
159
160       buf = newBuf;
161       bufLength = newBufLength;
162     }
163
164     buf[count] = (byte)b;
165     count++;
166   }
167
168
169   /**
170    * Flushes this output stream and forces any buffered output bytes
171    * to be written out. The general contract of <code>flush</code> is
172    * that calling it is an indication that, if any bytes previously
173    * written have been buffered by the implementation of the output
174    * stream, such bytes should immediately be written to their
175    * intended destination.
176    */

177   public void flush() {
178     if (count == 0) {
179       return;
180     }
181
182     // don't print out blank lines; flushing from PrintStream puts out these
183
if (count == LINE_SEPERATOR.length()) {
184       if ( ((char)buf[0]) == LINE_SEPERATOR.charAt(0) &&
185            ( ( count == 1 ) || // <- Unix & Mac, -> Windows
186
( (count == 2) && ((char)buf[1]) == LINE_SEPERATOR.charAt(1) ) ) ) {
187         reset();
188         return;
189       }
190     }
191
192     final byte[] theBytes = new byte[count];
193
194     System.arraycopy(buf, 0, theBytes, 0, count);
195
196     category.log(priority, new String JavaDoc(theBytes));
197
198     reset();
199   }
200
201
202   private void reset() {
203     // not resetting the buffer -- assuming that if it grew that it
204
// will likely grow similarly again
205
count = 0;
206   }
207
208 }
209
210
Popular Tags