OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / java / util / logging / StreamHandler.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 java.util.logging;
19
20 import java.io.OutputStream;
21 import java.io.OutputStreamWriter;
22 import java.io.UnsupportedEncodingException;
23 import java.io.Writer;
24
25 /**
26  * A {@code StreamHandler} object writes log messages to an output stream, that
27  * is, objects of the class {@link java.io.OutputStream}.
28  * <p>
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.
32  * <ul>
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
35  * current platform.
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
38  * default.
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}.
44  * </ul>
45  * <p>
46  * This class is not thread-safe.
47  */
48 public class StreamHandler extends Handler {
49
50     // the output stream this handler writes to
51     private OutputStream os;
52
53     // the writer that writes to the output stream
54     private Writer writer;
55
56     // the flag indicating whether the writer has been initialized
57     private boolean writerNotInitialized;
58
59     /**
60      * Constructs a {@code StreamHandler} object. The new stream handler
61      * does not have an associated output stream.
62      */
63     public StreamHandler() {
64         initProperties("INFO", null, "java.util.logging.SimpleFormatter", null);
65         this.os = null;
66         this.writer = null;
67         this.writerNotInitialized = true;
68     }
69
70     /**
71      * Constructs a {@code StreamHandler} object with the supplied output
72      * stream. Default properties are read.
73      *
74      * @param os
75      *            the output stream this handler writes to.
76      */
77     StreamHandler(OutputStream os) {
78         this();
79         this.os = os;
80     }
81
82     /**
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.
86      */
87     StreamHandler(String defaultLevel, String defaultFilter,
88             String defaultFormatter, String defaultEncoding) {
89         initProperties(defaultLevel, defaultFilter, defaultFormatter,
90                 defaultEncoding);
91         this.os = null;
92         this.writer = null;
93         this.writerNotInitialized = true;
94     }
95
96     /**
97      * Constructs a {@code StreamHandler} object with the supplied output stream
98      * and formatter.
99      *
100      * @param os
101      *            the output stream this handler writes to.
102      * @param formatter
103      *            the formatter this handler uses to format the output.
104      * @throws NullPointerException
105      *             if {@code os} or {@code formatter} is {@code null}.
106      */
107     public StreamHandler(OutputStream os, Formatter formatter) {
108         this();
109         if (os == null) {
110             throw new NullPointerException("os == null");
111         }
112         if (formatter == null) {
113             throw new NullPointerException("formatter == null");
114         }
115         this.os = os;
116         internalSetFormatter(formatter);
117     }
118
119     // initialize the writer
120     private void initializeWriter() {
121         this.writerNotInitialized = false;
122         if (null == getEncoding()) {
123             this.writer = new OutputStreamWriter(this.os);
124         } else {
125             try {
126                 this.writer = new OutputStreamWriter(this.os, getEncoding());
127             } catch (UnsupportedEncodingException e) {
128                 /*
129                  * Should not happen because it's checked in
130                  * super.initProperties().
131                  */
132             }
133         }
134         write(getFormatter().getHead(this));
135     }
136
137     // Write a string to the output stream.
138     private void write(String s) {
139         try {
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);
144         }
145     }
146
147     /**
148      * Sets the output stream this handler writes to. Note it does nothing else.
149      *
150      * @param newOs
151      *            the new output stream
152      */
153     void internalSetOutputStream(OutputStream newOs) {
154         this.os = newOs;
155     }
156
157     /**
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
161      * {@code os}.
162      *
163      * @param os
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}.
170      */
171     protected void setOutputStream(OutputStream os) {
172         if (null == os) {
173             throw new NullPointerException();
174         }
175         LogManager.getLogManager().checkAccess();
176         close(true);
177         this.writer = null;
178         this.os = os;
179         this.writerNotInitialized = true;
180     }
181
182     /**
183      * Sets the character encoding used by this handler. A {@code null} value
184      * indicates that the default encoding should be used.
185      *
186      * @param encoding
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.
193      */
194     @Override
195     public void setEncoding(String encoding) throws SecurityException,
196             UnsupportedEncodingException {
197         // flush first before set new encoding
198         this.flush();
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);
204             } else {
205                 try {
206                     this.writer = new OutputStreamWriter(this.os, getEncoding());
207                 } catch (UnsupportedEncodingException e) {
208                     /*
209                      * Should not happen because it's checked in
210                      * super.initProperties().
211                      */
212                     throw new AssertionError(e);
213                 }
214             }
215         }
216     }
217
218     /**
219      * Closes this handler, but the underlying output stream is only closed if
220      * {@code closeStream} is {@code true}. Security is not checked.
221      *
222      * @param closeStream
223      *            whether to close the underlying output stream.
224      */
225     void close(boolean closeStream) {
226         if (null != this.os) {
227             if (this.writerNotInitialized) {
228                 initializeWriter();
229             }
230             write(getFormatter().getTail(this));
231             try {
232                 this.writer.flush();
233                 if (closeStream) {
234                     this.writer.close();
235                     this.writer = null;
236                     this.os = null;
237                 }
238             } catch (Exception e) {
239                 getErrorManager().error("Exception occurred when closing the output stream", e,
240                         ErrorManager.CLOSE_FAILURE);
241             }
242         }
243     }
244
245     /**
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.
250      *
251      * @throws SecurityException
252      *             if a security manager determines that the caller does not
253      *             have the required permission.
254      */
255     @Override
256     public void close() {
257         LogManager.getLogManager().checkAccess();
258         close(true);
259     }
260
261     /**
262      * Flushes any buffered output.
263      */
264     @Override
265     public void flush() {
266         if (null != this.os) {
267             try {
268                 if (null != this.writer) {
269                     this.writer.flush();
270                 } else {
271                     this.os.flush();
272                 }
273             } catch (Exception e) {
274                 getErrorManager().error("Exception occurred when flushing the output stream",
275                         e, ErrorManager.FLUSH_FAILURE);
276             }
277         }
278     }
279
280     /**
281      * Accepts a logging request. The log record is formatted and written to the
282      * output stream if the following three conditions are met:
283      * <ul>
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
286      * handler, if any;
287      * <li>the output stream associated with this handler is not {@code null}.
288      * </ul>
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.
291      *
292      * @param record
293      *            the log record to be logged.
294      */
295     @Override
296     public synchronized void publish(LogRecord record) {
297         try {
298             if (this.isLoggable(record)) {
299                 if (this.writerNotInitialized) {
300                     initializeWriter();
301                 }
302                 String msg = null;
303                 try {
304                     msg = getFormatter().format(record);
305                 } catch (Exception e) {
306                     getErrorManager().error("Exception occurred when formatting the log record",
307                             e, ErrorManager.FORMAT_FAILURE);
308                 }
309                 write(msg);
310             }
311         } catch (Exception e) {
312             getErrorManager().error("Exception occurred when logging the record", e,
313                     ErrorManager.GENERIC_FAILURE);
314         }
315     }
316
317     /**
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
321      * {@code false}.
322      * <p>
323      * Notice : Case of no output stream will return {@code false}.
324      *
325      * @param record
326      *            the log record to be checked.
327      * @return {@code true} if {@code record} needs to be logged, {@code false}
328      *         otherwise.
329      */
330     @Override
331     public boolean isLoggable(LogRecord record) {
332         if (null == record) {
333             return false;
334         }
335         if (null != this.os && super.isLoggable(record)) {
336             return true;
337         }
338         return false;
339     }
340 }