Path: blob/master/src/java.logging/share/classes/java/util/logging/Handler.java
41159 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526package java.util.logging;2728import java.util.Objects;29import java.io.UnsupportedEncodingException;30import java.security.AccessController;31import java.security.PrivilegedAction;3233/**34* A {@code Handler} object takes log messages from a {@code Logger} and35* exports them. It might for example, write them to a console36* or write them to a file, or send them to a network logging service,37* or forward them to an OS log, or whatever.38* <p>39* A {@code Handler} can be disabled by doing a {@code setLevel(Level.OFF)}40* and can be re-enabled by doing a {@code setLevel} with an appropriate level.41* <p>42* {@code Handler} classes typically use {@code LogManager} properties to set43* default values for the {@code Handler}'s {@code Filter}, {@code Formatter},44* and {@code Level}. See the specific documentation for each concrete45* {@code Handler} class.46*47*48* @since 1.449*/5051public abstract class Handler {52private static final int offValue = Level.OFF.intValue();53private final LogManager manager = LogManager.getLogManager();5455// We're using volatile here to avoid synchronizing getters, which56// would prevent other threads from calling isLoggable()57// while publish() is executing.58// On the other hand, setters will be synchronized to exclude concurrent59// execution with more complex methods, such as StreamHandler.publish().60// We wouldn't want 'level' to be changed by another thread in the middle61// of the execution of a 'publish' call.62private volatile Filter filter;63private volatile Formatter formatter;64private volatile Level logLevel = Level.ALL;65private volatile ErrorManager errorManager = new ErrorManager();66private volatile String encoding;6768/**69* Default constructor. The resulting {@code Handler} has a log70* level of {@code Level.ALL}, no {@code Formatter}, and no71* {@code Filter}. A default {@code ErrorManager} instance is installed72* as the {@code ErrorManager}.73*/74protected Handler() {75}7677/**78* Package-private constructor for chaining from subclass constructors79* that wish to configure the handler with specific default and/or80* specified values.81*82* @param defaultLevel a default {@link Level} to configure if one is83* not found in LogManager configuration properties84* @param defaultFormatter a default {@link Formatter} to configure if one is85* not specified by {@code specifiedFormatter} parameter86* nor found in LogManager configuration properties87* @param specifiedFormatter if not null, this is the formatter to configure88*/89@SuppressWarnings("removal")90Handler(Level defaultLevel, Formatter defaultFormatter,91Formatter specifiedFormatter) {9293LogManager manager = LogManager.getLogManager();94String cname = getClass().getName();9596final Level level = manager.getLevelProperty(cname + ".level", defaultLevel);97final Filter filter = manager.getFilterProperty(cname + ".filter", null);98final Formatter formatter = specifiedFormatter == null99? manager.getFormatterProperty(cname + ".formatter", defaultFormatter)100: specifiedFormatter;101final String encoding = manager.getStringProperty(cname + ".encoding", null);102103AccessController.doPrivileged(new PrivilegedAction<Void>() {104@Override105public Void run() {106setLevel(level);107setFilter(filter);108setFormatter(formatter);109try {110setEncoding(encoding);111} catch (Exception ex) {112try {113setEncoding(null);114} catch (Exception ex2) {115// doing a setEncoding with null should always work.116// assert false;117}118}119return null;120}121}, null, LogManager.controlPermission);122}123124/**125* Publish a {@code LogRecord}.126* <p>127* The logging request was made initially to a {@code Logger} object,128* which initialized the {@code LogRecord} and forwarded it here.129* <p>130* The {@code Handler} is responsible for formatting the message, when and131* if necessary. The formatting should include localization.132*133* @param record description of the log event. A null record is134* silently ignored and is not published135*/136public abstract void publish(LogRecord record);137138/**139* Flush any buffered output.140*/141public abstract void flush();142143/**144* Close the {@code Handler} and free all associated resources.145* <p>146* The close method will perform a {@code flush} and then close the147* {@code Handler}. After close has been called this {@code Handler}148* should no longer be used. Method calls may either be silently149* ignored or may throw runtime exceptions.150*151* @throws SecurityException if a security manager exists and if152* the caller does not have {@code LoggingPermission("control")}.153*/154public abstract void close() throws SecurityException;155156/**157* Set a {@code Formatter}. This {@code Formatter} will be used158* to format {@code LogRecords} for this {@code Handler}.159* <p>160* Some {@code Handlers} may not use {@code Formatters}, in161* which case the {@code Formatter} will be remembered, but not used.162*163* @param newFormatter the {@code Formatter} to use (may not be null)164* @throws SecurityException if a security manager exists and if165* the caller does not have {@code LoggingPermission("control")}.166*/167public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {168checkPermission();169formatter = Objects.requireNonNull(newFormatter);170}171172/**173* Return the {@code Formatter} for this {@code Handler}.174* @return the {@code Formatter} (may be null).175*/176public Formatter getFormatter() {177return formatter;178}179180/**181* Set the character encoding used by this {@code Handler}.182* <p>183* The encoding should be set before any {@code LogRecords} are written184* to the {@code Handler}.185*186* @param encoding The name of a supported character encoding.187* May be null, to indicate the default platform encoding.188* @throws SecurityException if a security manager exists and if189* the caller does not have {@code LoggingPermission("control")}.190* @throws UnsupportedEncodingException if the named encoding is191* not supported.192*/193public synchronized void setEncoding(String encoding)194throws SecurityException, java.io.UnsupportedEncodingException {195checkPermission();196if (encoding != null) {197try {198if(!java.nio.charset.Charset.isSupported(encoding)) {199throw new UnsupportedEncodingException(encoding);200}201} catch (java.nio.charset.IllegalCharsetNameException e) {202throw new UnsupportedEncodingException(encoding);203}204}205this.encoding = encoding;206}207208/**209* Return the character encoding for this {@code Handler}.210*211* @return The encoding name. May be null, which indicates the212* default encoding should be used.213*/214public String getEncoding() {215return encoding;216}217218/**219* Set a {@code Filter} to control output on this {@code Handler}.220* <P>221* For each call of {@code publish} the {@code Handler} will call222* this {@code Filter} (if it is non-null) to check if the223* {@code LogRecord} should be published or discarded.224*225* @param newFilter a {@code Filter} object (may be null)226* @throws SecurityException if a security manager exists and if227* the caller does not have {@code LoggingPermission("control")}.228*/229public synchronized void setFilter(Filter newFilter) throws SecurityException {230checkPermission();231filter = newFilter;232}233234/**235* Get the current {@code Filter} for this {@code Handler}.236*237* @return a {@code Filter} object (may be null)238*/239public Filter getFilter() {240return filter;241}242243/**244* Define an ErrorManager for this Handler.245* <p>246* The ErrorManager's "error" method will be invoked if any247* errors occur while using this Handler.248*249* @param em the new ErrorManager250* @throws SecurityException if a security manager exists and if251* the caller does not have {@code LoggingPermission("control")}.252*/253public synchronized void setErrorManager(ErrorManager em) {254checkPermission();255if (em == null) {256throw new NullPointerException();257}258errorManager = em;259}260261/**262* Retrieves the ErrorManager for this Handler.263*264* @return the ErrorManager for this Handler265* @throws SecurityException if a security manager exists and if266* the caller does not have {@code LoggingPermission("control")}.267*/268public ErrorManager getErrorManager() {269checkPermission();270return errorManager;271}272273/**274* Protected convenience method to report an error to this Handler's275* ErrorManager. Note that this method retrieves and uses the ErrorManager276* without doing a security check. It can therefore be used in277* environments where the caller may be non-privileged.278*279* @param msg a descriptive string (may be null)280* @param ex an exception (may be null)281* @param code an error code defined in ErrorManager282*/283protected void reportError(String msg, Exception ex, int code) {284try {285errorManager.error(msg, ex, code);286} catch (Exception ex2) {287System.err.println("Handler.reportError caught:");288ex2.printStackTrace();289}290}291292/**293* Set the log level specifying which message levels will be294* logged by this {@code Handler}. Message levels lower than this295* value will be discarded.296* <p>297* The intention is to allow developers to turn on voluminous298* logging, but to limit the messages that are sent to certain299* {@code Handlers}.300*301* @param newLevel the new value for the log level302* @throws SecurityException if a security manager exists and if303* the caller does not have {@code LoggingPermission("control")}.304*/305public synchronized void setLevel(Level newLevel) throws SecurityException {306if (newLevel == null) {307throw new NullPointerException();308}309checkPermission();310logLevel = newLevel;311}312313/**314* Get the log level specifying which messages will be315* logged by this {@code Handler}. Message levels lower316* than this level will be discarded.317* @return the level of messages being logged.318*/319public Level getLevel() {320return logLevel;321}322323/**324* Check if this {@code Handler} would actually log a given {@code LogRecord}.325* <p>326* This method checks if the {@code LogRecord} has an appropriate327* {@code Level} and whether it satisfies any {@code Filter}. It also328* may make other {@code Handler} specific checks that might prevent a329* handler from logging the {@code LogRecord}. It will return false if330* the {@code LogRecord} is null.331*332* @param record a {@code LogRecord} (may be null).333* @return true if the {@code LogRecord} would be logged.334*335*/336public boolean isLoggable(LogRecord record) {337final int levelValue = getLevel().intValue();338if (record == null) return false;339if (record.getLevel().intValue() < levelValue || levelValue == offValue) {340return false;341}342final Filter filter = getFilter();343if (filter == null) {344return true;345}346return filter.isLoggable(record);347}348349// Package-private support method for security checks.350// We check that the caller has appropriate security privileges351// to update Handler state and if not throw a SecurityException.352void checkPermission() throws SecurityException {353manager.checkPermission();354}355}356357358