Handler.java revision 4ff539dbc5a809ef3eacbe2d9f2b97f640b7e9cf
1/*
2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package java.util.logging;
28
29import java.io.UnsupportedEncodingException;
30/**
31 * A <tt>Handler</tt> object takes log messages from a <tt>Logger</tt> and
32 * exports them.  It might for example, write them to a console
33 * or write them to a file, or send them to a network logging service,
34 * or forward them to an OS log, or whatever.
35 * <p>
36 * A <tt>Handler</tt> can be disabled by doing a <tt>setLevel(Level.OFF)</tt>
37 * and can  be re-enabled by doing a <tt>setLevel</tt> with an appropriate level.
38 * <p>
39 * <tt>Handler</tt> classes typically use <tt>LogManager</tt> properties to set
40 * default values for the <tt>Handler</tt>'s <tt>Filter</tt>, <tt>Formatter</tt>,
41 * and <tt>Level</tt>.  See the specific documentation for each concrete
42 * <tt>Handler</tt> class.
43 *
44 *
45 * @since 1.4
46 */
47
48public abstract class Handler {
49    private static final int offValue = Level.OFF.intValue();
50    private final LogManager manager = LogManager.getLogManager();
51
52    // We're using volatile here to avoid synchronizing getters, which
53    // would prevent other threads from calling isLoggable()
54    // while publish() is executing.
55    // On the other hand, setters will be synchronized to exclude concurrent
56    // execution with more complex methods, such as StreamHandler.publish().
57    // We wouldn't want 'level' to be changed by another thread in the middle
58    // of the execution of a 'publish' call.
59    private volatile Filter filter;
60    private volatile Formatter formatter;
61    private volatile Level logLevel = Level.ALL;
62    private volatile ErrorManager errorManager = new ErrorManager();
63    private volatile String encoding;
64
65    // Package private support for security checking.  When sealed
66    // is true, we access check updates to the class.
67    boolean sealed = true;
68
69    /**
70     * Default constructor.  The resulting <tt>Handler</tt> has a log
71     * level of <tt>Level.ALL</tt>, no <tt>Formatter</tt>, and no
72     * <tt>Filter</tt>.  A default <tt>ErrorManager</tt> instance is installed
73     * as the <tt>ErrorManager</tt>.
74     */
75    protected Handler() {
76    }
77
78    /**
79     * Publish a <tt>LogRecord</tt>.
80     * <p>
81     * The logging request was made initially to a <tt>Logger</tt> object,
82     * which initialized the <tt>LogRecord</tt> and forwarded it here.
83     * <p>
84     * The <tt>Handler</tt>  is responsible for formatting the message, when and
85     * if necessary.  The formatting should include localization.
86     *
87     * @param  record  description of the log event. A null record is
88     *                 silently ignored and is not published
89     */
90    public abstract void publish(LogRecord record);
91
92    /**
93     * Flush any buffered output.
94     */
95    public abstract void flush();
96
97    /**
98     * Close the <tt>Handler</tt> and free all associated resources.
99     * <p>
100     * The close method will perform a <tt>flush</tt> and then close the
101     * <tt>Handler</tt>.   After close has been called this <tt>Handler</tt>
102     * should no longer be used.  Method calls may either be silently
103     * ignored or may throw runtime exceptions.
104     *
105     * @exception  SecurityException  if a security manager exists and if
106     *             the caller does not have <tt>LoggingPermission("control")</tt>.
107     */
108    public abstract void close() throws SecurityException;
109
110    /**
111     * Set a <tt>Formatter</tt>.  This <tt>Formatter</tt> will be used
112     * to format <tt>LogRecords</tt> for this <tt>Handler</tt>.
113     * <p>
114     * Some <tt>Handlers</tt> may not use <tt>Formatters</tt>, in
115     * which case the <tt>Formatter</tt> will be remembered, but not used.
116     * <p>
117     * @param newFormatter the <tt>Formatter</tt> to use (may not be null)
118     * @exception  SecurityException  if a security manager exists and if
119     *             the caller does not have <tt>LoggingPermission("control")</tt>.
120     */
121    public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
122        checkPermission();
123        // Check for a null pointer:
124        newFormatter.getClass();
125        formatter = newFormatter;
126    }
127
128    /**
129     * Return the <tt>Formatter</tt> for this <tt>Handler</tt>.
130     * @return the <tt>Formatter</tt> (may be null).
131     */
132    public Formatter getFormatter() {
133        return formatter;
134    }
135
136    /**
137     * Set the character encoding used by this <tt>Handler</tt>.
138     * <p>
139     * The encoding should be set before any <tt>LogRecords</tt> are written
140     * to the <tt>Handler</tt>.
141     *
142     * @param encoding  The name of a supported character encoding.
143     *        May be null, to indicate the default platform encoding.
144     * @exception  SecurityException  if a security manager exists and if
145     *             the caller does not have <tt>LoggingPermission("control")</tt>.
146     * @exception  UnsupportedEncodingException if the named encoding is
147     *          not supported.
148     */
149    public synchronized void setEncoding(String encoding)
150                        throws SecurityException, java.io.UnsupportedEncodingException {
151        checkPermission();
152        if (encoding != null) {
153            try {
154                if(!java.nio.charset.Charset.isSupported(encoding)) {
155                    throw new UnsupportedEncodingException(encoding);
156                }
157            } catch (java.nio.charset.IllegalCharsetNameException e) {
158                throw new UnsupportedEncodingException(encoding);
159            }
160        }
161        this.encoding = encoding;
162    }
163
164    /**
165     * Return the character encoding for this <tt>Handler</tt>.
166     *
167     * @return  The encoding name.  May be null, which indicates the
168     *          default encoding should be used.
169     */
170    public String getEncoding() {
171        return encoding;
172    }
173
174    /**
175     * Set a <tt>Filter</tt> to control output on this <tt>Handler</tt>.
176     * <P>
177     * For each call of <tt>publish</tt> the <tt>Handler</tt> will call
178     * this <tt>Filter</tt> (if it is non-null) to check if the
179     * <tt>LogRecord</tt> should be published or discarded.
180     *
181     * @param   newFilter  a <tt>Filter</tt> object (may be null)
182     * @exception  SecurityException  if a security manager exists and if
183     *             the caller does not have <tt>LoggingPermission("control")</tt>.
184     */
185    public synchronized void setFilter(Filter newFilter) throws SecurityException {
186        checkPermission();
187        filter = newFilter;
188    }
189
190    /**
191     * Get the current <tt>Filter</tt> for this <tt>Handler</tt>.
192     *
193     * @return  a <tt>Filter</tt> object (may be null)
194     */
195    public Filter getFilter() {
196        return filter;
197    }
198
199    /**
200     * Define an ErrorManager for this Handler.
201     * <p>
202     * The ErrorManager's "error" method will be invoked if any
203     * errors occur while using this Handler.
204     *
205     * @param em  the new ErrorManager
206     * @exception  SecurityException  if a security manager exists and if
207     *             the caller does not have <tt>LoggingPermission("control")</tt>.
208     */
209    public synchronized void setErrorManager(ErrorManager em) {
210        checkPermission();
211        if (em == null) {
212           throw new NullPointerException();
213        }
214        errorManager = em;
215    }
216
217    /**
218     * Retrieves the ErrorManager for this Handler.
219     *
220     * @return the ErrorManager for this Handler
221     * @exception  SecurityException  if a security manager exists and if
222     *             the caller does not have <tt>LoggingPermission("control")</tt>.
223     */
224    public ErrorManager getErrorManager() {
225        checkPermission();
226        return errorManager;
227    }
228
229   /**
230     * Protected convenience method to report an error to this Handler's
231     * ErrorManager.  Note that this method retrieves and uses the ErrorManager
232     * without doing a security check.  It can therefore be used in
233     * environments where the caller may be non-privileged.
234     *
235     * @param msg    a descriptive string (may be null)
236     * @param ex     an exception (may be null)
237     * @param code   an error code defined in ErrorManager
238     */
239    protected void reportError(String msg, Exception ex, int code) {
240        try {
241            errorManager.error(msg, ex, code);
242        } catch (Exception ex2) {
243            System.err.println("Handler.reportError caught:");
244            ex2.printStackTrace();
245        }
246    }
247
248    /**
249     * Set the log level specifying which message levels will be
250     * logged by this <tt>Handler</tt>.  Message levels lower than this
251     * value will be discarded.
252     * <p>
253     * The intention is to allow developers to turn on voluminous
254     * logging, but to limit the messages that are sent to certain
255     * <tt>Handlers</tt>.
256     *
257     * @param newLevel   the new value for the log level
258     * @exception  SecurityException  if a security manager exists and if
259     *             the caller does not have <tt>LoggingPermission("control")</tt>.
260     */
261    public synchronized void setLevel(Level newLevel) throws SecurityException {
262        if (newLevel == null) {
263            throw new NullPointerException();
264        }
265        checkPermission();
266        logLevel = newLevel;
267    }
268
269    /**
270     * Get the log level specifying which messages will be
271     * logged by this <tt>Handler</tt>.  Message levels lower
272     * than this level will be discarded.
273     * @return  the level of messages being logged.
274     */
275    public Level getLevel() {
276        return logLevel;
277    }
278
279    /**
280     * Check if this <tt>Handler</tt> would actually log a given <tt>LogRecord</tt>.
281     * <p>
282     * This method checks if the <tt>LogRecord</tt> has an appropriate
283     * <tt>Level</tt> and  whether it satisfies any <tt>Filter</tt>.  It also
284     * may make other <tt>Handler</tt> specific checks that might prevent a
285     * handler from logging the <tt>LogRecord</tt>. It will return false if
286     * the <tt>LogRecord</tt> is null.
287     * <p>
288     * @param record  a <tt>LogRecord</tt>
289     * @return true if the <tt>LogRecord</tt> would be logged.
290     *
291     */
292    public boolean isLoggable(LogRecord record) {
293        final int levelValue = getLevel().intValue();
294        if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
295            return false;
296        }
297        final Filter filter = getFilter();
298        if (filter == null) {
299            return true;
300        }
301        return filter.isLoggable(record);
302    }
303
304    // Package-private support method for security checks.
305    // If "sealed" is true, we check that the caller has
306    // appropriate security privileges to update Handler
307    // state and if not throw a SecurityException.
308    void checkPermission() throws SecurityException {
309        if (sealed) {
310            manager.checkPermission();
311        }
312    }
313}
314