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