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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package java.util.logging;
20 import java.io.OutputStream;
21 import java.io.OutputStreamWriter;
22 import java.io.UnsupportedEncodingException;
23 import java.io.Writer;
26 * A {@code StreamHandler} object writes log messages to an output stream, that
27 * is, objects of the class {@link java.io.OutputStream}.
29 * A {@code StreamHandler} object reads the following properties from the log
30 * manager to initialize itself. A default value will be used if a property is
31 * not found or has an invalid value.
33 * <li>java.util.logging.StreamHandler.encoding specifies the encoding this
34 * handler will use to encode log messages. Default is the encoding used by the
36 * <li>java.util.logging.StreamHandler.filter specifies the name of the filter
37 * class to be associated with this handler. No <code>Filter</code> is used by
39 * <li>java.util.logging.StreamHandler.formatter specifies the name of the
40 * formatter class to be associated with this handler. Default is
41 * {@code java.util.logging.SimpleFormatter}.
42 * <li>java.util.logging.StreamHandler.level specifies the logging level.
43 * Defaults is {@code Level.INFO}.
46 * This class is not thread-safe.
48 public class StreamHandler extends Handler {
50 // the output stream this handler writes to
51 private OutputStream os;
53 // the writer that writes to the output stream
54 private Writer writer;
56 // the flag indicating whether the writer has been initialized
57 private boolean writerNotInitialized;
60 * Constructs a {@code StreamHandler} object. The new stream handler
61 * does not have an associated output stream.
63 public StreamHandler() {
64 initProperties("INFO", null, "java.util.logging.SimpleFormatter", null);
67 this.writerNotInitialized = true;
71 * Constructs a {@code StreamHandler} object with the supplied output
72 * stream. Default properties are read.
75 * the output stream this handler writes to.
77 StreamHandler(OutputStream os) {
83 * Constructs a {@code StreamHandler} object. The specified default values
84 * will be used if the corresponding properties are not found in the log
85 * manager's properties.
87 StreamHandler(String defaultLevel, String defaultFilter,
88 String defaultFormatter, String defaultEncoding) {
89 initProperties(defaultLevel, defaultFilter, defaultFormatter,
93 this.writerNotInitialized = true;
97 * Constructs a {@code StreamHandler} object with the supplied output stream
101 * the output stream this handler writes to.
103 * the formatter this handler uses to format the output.
104 * @throws NullPointerException
105 * if {@code os} or {@code formatter} is {@code null}.
107 public StreamHandler(OutputStream os, Formatter formatter) {
110 throw new NullPointerException("os == null");
112 if (formatter == null) {
113 throw new NullPointerException("formatter == null");
116 internalSetFormatter(formatter);
119 // initialize the writer
120 private void initializeWriter() {
121 this.writerNotInitialized = false;
122 if (null == getEncoding()) {
123 this.writer = new OutputStreamWriter(this.os);
126 this.writer = new OutputStreamWriter(this.os, getEncoding());
127 } catch (UnsupportedEncodingException e) {
129 * Should not happen because it's checked in
130 * super.initProperties().
134 write(getFormatter().getHead(this));
137 // Write a string to the output stream.
138 private void write(String s) {
140 this.writer.write(s);
141 } catch (Exception e) {
142 getErrorManager().error("Exception occurred when writing to the output stream", e,
143 ErrorManager.WRITE_FAILURE);
148 * Sets the output stream this handler writes to. Note it does nothing else.
151 * the new output stream
153 void internalSetOutputStream(OutputStream newOs) {
158 * Sets the output stream this handler writes to. If there's an existing
159 * output stream, the tail string of the associated formatter will be
160 * written to it. Then it will be flushed, closed and replaced with
164 * the new output stream.
165 * @throws SecurityException
166 * if a security manager determines that the caller does not
167 * have the required permission.
168 * @throws NullPointerException
169 * if {@code os} is {@code null}.
171 protected void setOutputStream(OutputStream os) {
173 throw new NullPointerException();
175 LogManager.getLogManager().checkAccess();
179 this.writerNotInitialized = true;
183 * Sets the character encoding used by this handler. A {@code null} value
184 * indicates that the default encoding should be used.
187 * the character encoding to set.
188 * @throws SecurityException
189 * if a security manager determines that the caller does not
190 * have the required permission.
191 * @throws UnsupportedEncodingException
192 * if the specified encoding is not supported by the runtime.
195 public void setEncoding(String encoding) throws SecurityException,
196 UnsupportedEncodingException {
197 // flush first before set new encoding
199 super.setEncoding(encoding);
200 // renew writer only if the writer exists
201 if (null != this.writer) {
202 if (null == getEncoding()) {
203 this.writer = new OutputStreamWriter(this.os);
206 this.writer = new OutputStreamWriter(this.os, getEncoding());
207 } catch (UnsupportedEncodingException e) {
209 * Should not happen because it's checked in
210 * super.initProperties().
212 throw new AssertionError(e);
219 * Closes this handler, but the underlying output stream is only closed if
220 * {@code closeStream} is {@code true}. Security is not checked.
223 * whether to close the underlying output stream.
225 void close(boolean closeStream) {
226 if (null != this.os) {
227 if (this.writerNotInitialized) {
230 write(getFormatter().getTail(this));
238 } catch (Exception e) {
239 getErrorManager().error("Exception occurred when closing the output stream", e,
240 ErrorManager.CLOSE_FAILURE);
246 * Closes this handler. The tail string of the formatter associated with
247 * this handler is written out. A flush operation and a subsequent close
248 * operation is then performed upon the output stream. Client applications
249 * should not use a handler after closing it.
251 * @throws SecurityException
252 * if a security manager determines that the caller does not
253 * have the required permission.
256 public void close() {
257 LogManager.getLogManager().checkAccess();
262 * Flushes any buffered output.
265 public void flush() {
266 if (null != this.os) {
268 if (null != this.writer) {
273 } catch (Exception e) {
274 getErrorManager().error("Exception occurred when flushing the output stream",
275 e, ErrorManager.FLUSH_FAILURE);
281 * Accepts a logging request. The log record is formatted and written to the
282 * output stream if the following three conditions are met:
284 * <li>the supplied log record has at least the required logging level;
285 * <li>the supplied log record passes the filter associated with this
287 * <li>the output stream associated with this handler is not {@code null}.
289 * If it is the first time a log record is written out, the head string of
290 * the formatter associated with this handler is written out first.
293 * the log record to be logged.
296 public synchronized void publish(LogRecord record) {
298 if (this.isLoggable(record)) {
299 if (this.writerNotInitialized) {
304 msg = getFormatter().format(record);
305 } catch (Exception e) {
306 getErrorManager().error("Exception occurred when formatting the log record",
307 e, ErrorManager.FORMAT_FAILURE);
311 } catch (Exception e) {
312 getErrorManager().error("Exception occurred when logging the record", e,
313 ErrorManager.GENERIC_FAILURE);
318 * Determines whether the supplied log record needs to be logged. The
319 * logging levels are checked as well as the filter. The output stream of
320 * this handler is also checked. If it is {@code null}, this method returns
323 * Notice : Case of no output stream will return {@code false}.
326 * the log record to be checked.
327 * @return {@code true} if {@code record} needs to be logged, {@code false}
331 public boolean isLoggable(LogRecord record) {
332 if (null == record) {
335 if (null != this.os && super.isLoggable(record)) {