Handler.java revision 49965c1dc9da104344f4893a05e45795a5740d20
1/*
2 * Copyright (c) 2000, 2012, 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 LogManager manager = LogManager.getLogManager();
51    private Filter filter;
52    private Formatter formatter;
53    private Level logLevel = Level.ALL;
54    private ErrorManager errorManager = new ErrorManager();
55    private String encoding;
56
57    // Package private support for security checking.  When sealed
58    // is true, we access check updates to the class.
59    boolean sealed = true;
60
61    /**
62     * Default constructor.  The resulting <tt>Handler</tt> has a log
63     * level of <tt>Level.ALL</tt>, no <tt>Formatter</tt>, and no
64     * <tt>Filter</tt>.  A default <tt>ErrorManager</tt> instance is installed
65     * as the <tt>ErrorManager</tt>.
66     */
67    protected Handler() {
68    }
69
70    /**
71     * Publish a <tt>LogRecord</tt>.
72     * <p>
73     * The logging request was made initially to a <tt>Logger</tt> object,
74     * which initialized the <tt>LogRecord</tt> and forwarded it here.
75     * <p>
76     * The <tt>Handler</tt>  is responsible for formatting the message, when and
77     * if necessary.  The formatting should include localization.
78     *
79     * @param  record  description of the log event. A null record is
80     *                 silently ignored and is not published
81     */
82    public abstract void publish(LogRecord record);
83
84    /**
85     * Flush any buffered output.
86     */
87    public abstract void flush();
88
89    /**
90     * Close the <tt>Handler</tt> and free all associated resources.
91     * <p>
92     * The close method will perform a <tt>flush</tt> and then close the
93     * <tt>Handler</tt>.   After close has been called this <tt>Handler</tt>
94     * should no longer be used.  Method calls may either be silently
95     * ignored or may throw runtime exceptions.
96     *
97     * @exception  SecurityException  if a security manager exists and if
98     *             the caller does not have <tt>LoggingPermission("control")</tt>.
99     */
100    public abstract void close() throws SecurityException;
101
102    /**
103     * Set a <tt>Formatter</tt>.  This <tt>Formatter</tt> will be used
104     * to format <tt>LogRecords</tt> for this <tt>Handler</tt>.
105     * <p>
106     * Some <tt>Handlers</tt> may not use <tt>Formatters</tt>, in
107     * which case the <tt>Formatter</tt> will be remembered, but not used.
108     * <p>
109     * @param newFormatter the <tt>Formatter</tt> to use (may not be null)
110     * @exception  SecurityException  if a security manager exists and if
111     *             the caller does not have <tt>LoggingPermission("control")</tt>.
112     */
113    public void setFormatter(Formatter newFormatter) throws SecurityException {
114        checkPermission();
115        // Check for a null pointer:
116        newFormatter.getClass();
117        formatter = newFormatter;
118    }
119
120    /**
121     * Return the <tt>Formatter</tt> for this <tt>Handler</tt>.
122     * @return the <tt>Formatter</tt> (may be null).
123     */
124    public Formatter getFormatter() {
125        return formatter;
126    }
127
128    /**
129     * Set the character encoding used by this <tt>Handler</tt>.
130     * <p>
131     * The encoding should be set before any <tt>LogRecords</tt> are written
132     * to the <tt>Handler</tt>.
133     *
134     * @param encoding  The name of a supported character encoding.
135     *        May be null, to indicate the default platform encoding.
136     * @exception  SecurityException  if a security manager exists and if
137     *             the caller does not have <tt>LoggingPermission("control")</tt>.
138     * @exception  UnsupportedEncodingException if the named encoding is
139     *          not supported.
140     */
141    public void setEncoding(String encoding)
142                        throws SecurityException, java.io.UnsupportedEncodingException {
143        checkPermission();
144        if (encoding != null) {
145            try {
146                if(!java.nio.charset.Charset.isSupported(encoding)) {
147                    throw new UnsupportedEncodingException(encoding);
148                }
149            } catch (java.nio.charset.IllegalCharsetNameException e) {
150                throw new UnsupportedEncodingException(encoding);
151            }
152        }
153        this.encoding = encoding;
154    }
155
156    /**
157     * Return the character encoding for this <tt>Handler</tt>.
158     *
159     * @return  The encoding name.  May be null, which indicates the
160     *          default encoding should be used.
161     */
162    public String getEncoding() {
163        return encoding;
164    }
165
166    /**
167     * Set a <tt>Filter</tt> to control output on this <tt>Handler</tt>.
168     * <P>
169     * For each call of <tt>publish</tt> the <tt>Handler</tt> will call
170     * this <tt>Filter</tt> (if it is non-null) to check if the
171     * <tt>LogRecord</tt> should be published or discarded.
172     *
173     * @param   newFilter  a <tt>Filter</tt> object (may be null)
174     * @exception  SecurityException  if a security manager exists and if
175     *             the caller does not have <tt>LoggingPermission("control")</tt>.
176     */
177    public void setFilter(Filter newFilter) throws SecurityException {
178        checkPermission();
179        filter = newFilter;
180    }
181
182    /**
183     * Get the current <tt>Filter</tt> for this <tt>Handler</tt>.
184     *
185     * @return  a <tt>Filter</tt> object (may be null)
186     */
187    public Filter getFilter() {
188        return filter;
189    }
190
191    /**
192     * Define an ErrorManager for this Handler.
193     * <p>
194     * The ErrorManager's "error" method will be invoked if any
195     * errors occur while using this Handler.
196     *
197     * @param em  the new ErrorManager
198     * @exception  SecurityException  if a security manager exists and if
199     *             the caller does not have <tt>LoggingPermission("control")</tt>.
200     */
201    public void setErrorManager(ErrorManager em) {
202        checkPermission();
203        if (em == null) {
204           throw new NullPointerException();
205        }
206        errorManager = em;
207    }
208
209    /**
210     * Retrieves the ErrorManager for this Handler.
211     *
212     * @exception  SecurityException  if a security manager exists and if
213     *             the caller does not have <tt>LoggingPermission("control")</tt>.
214     */
215    public ErrorManager getErrorManager() {
216        checkPermission();
217        return errorManager;
218    }
219
220   /**
221     * Protected convenience method to report an error to this Handler's
222     * ErrorManager.  Note that this method retrieves and uses the ErrorManager
223     * without doing a security check.  It can therefore be used in
224     * environments where the caller may be non-privileged.
225     *
226     * @param msg    a descriptive string (may be null)
227     * @param ex     an exception (may be null)
228     * @param code   an error code defined in ErrorManager
229     */
230    protected void reportError(String msg, Exception ex, int code) {
231        try {
232            errorManager.error(msg, ex, code);
233        } catch (Exception ex2) {
234            System.err.println("Handler.reportError caught:");
235            ex2.printStackTrace();
236        }
237    }
238
239    /**
240     * Set the log level specifying which message levels will be
241     * logged by this <tt>Handler</tt>.  Message levels lower than this
242     * value will be discarded.
243     * <p>
244     * The intention is to allow developers to turn on voluminous
245     * logging, but to limit the messages that are sent to certain
246     * <tt>Handlers</tt>.
247     *
248     * @param newLevel   the new value for the log level
249     * @exception  SecurityException  if a security manager exists and if
250     *             the caller does not have <tt>LoggingPermission("control")</tt>.
251     */
252    public synchronized void setLevel(Level newLevel) throws SecurityException {
253        if (newLevel == null) {
254            throw new NullPointerException();
255        }
256        checkPermission();
257        logLevel = newLevel;
258    }
259
260    /**
261     * Get the log level specifying which messages will be
262     * logged by this <tt>Handler</tt>.  Message levels lower
263     * than this level will be discarded.
264     * @return  the level of messages being logged.
265     */
266    public synchronized Level getLevel() {
267        return logLevel;
268    }
269
270    /**
271     * Check if this <tt>Handler</tt> would actually log a given <tt>LogRecord</tt>.
272     * <p>
273     * This method checks if the <tt>LogRecord</tt> has an appropriate
274     * <tt>Level</tt> and  whether it satisfies any <tt>Filter</tt>.  It also
275     * may make other <tt>Handler</tt> specific checks that might prevent a
276     * handler from logging the <tt>LogRecord</tt>. It will return false if
277     * the <tt>LogRecord</tt> is null.
278     * <p>
279     * @param record  a <tt>LogRecord</tt>
280     * @return true if the <tt>LogRecord</tt> would be logged.
281     *
282     */
283    public boolean isLoggable(LogRecord record) {
284        int levelValue = getLevel().intValue();
285        if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
286            return false;
287        }
288        Filter filter = getFilter();
289        if (filter == null) {
290            return true;
291        }
292        return filter.isLoggable(record);
293    }
294
295    // Package-private support method for security checks.
296    // If "sealed" is true, we check that the caller has
297    // appropriate security privileges to update Handler
298    // state and if not throw a SecurityException.
299    void checkPermission() throws SecurityException {
300        if (sealed) {
301            manager.checkPermission();
302        }
303    }
304}
305