Source for java.util.logging.Handler

   1: /* Handler.java -- a class for publishing log messages
   2:    Copyright (C) 2002, 2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.util.logging;
  40: 
  41: import java.io.UnsupportedEncodingException;
  42: 
  43: /**
  44:  * A <code>Handler</code> publishes <code>LogRecords</code> to
  45:  * a sink, for example a file, the console or a network socket.
  46:  * There are different subclasses of <code>Handler</code>
  47:  * to deal with different kinds of sinks.
  48:  *
  49:  * <p>FIXME: Are handlers thread-safe, or is the assumption that only
  50:  * loggers are, and a handler can belong only to one single logger? If
  51:  * the latter, should we enforce it? (Spec not clear). In any
  52:  * case, it needs documentation.
  53:  *
  54:  * @author Sascha Brawer (brawer@acm.org)
  55:  */
  56: public abstract class Handler
  57: {
  58:   Formatter     formatter;
  59:   Filter        filter;
  60:   Level         level;
  61:   ErrorManager  errorManager;
  62:   String        encoding;
  63: 
  64:   /**
  65:    * Constructs a Handler with a logging severity level of
  66:    * <code>Level.ALL</code>, no formatter, no filter, and
  67:    * an instance of <code>ErrorManager</code> managing errors.
  68:    *
  69:    * <p><strong>Specification Note:</strong> The specification of the
  70:    * Java<sup>TM</sup> Logging API does not mention which character
  71:    * encoding is to be used by freshly constructed Handlers.  The GNU
  72:    * implementation uses the default platform encoding, but other
  73:    * Java implementations might behave differently.
  74:    *
  75:    * <p><strong>Specification Note:</strong> While a freshly constructed
  76:    * Handler is required to have <em>no filter</em> according to the
  77:    * specification, <code>null</code> is not a valid parameter for
  78:    * <code>Handler.setFormatter</code>.  Therefore, the following
  79:    * code will throw a <code>java.lang.NullPointerException</code>:
  80:    *
  81:    * <p><pre>Handler h = new MyConcreteSubclassOfHandler();
  82: h.setFormatter(h.getFormatter());</pre>
  83:    *
  84:    * It seems strange that a freshly constructed Handler is not
  85:    * supposed to provide a Formatter, but this is what the specification
  86:    * says.
  87:    */
  88:   protected Handler()
  89:   {
  90:     level = Level.ALL;
  91:   }
  92: 
  93: 
  94:   /**
  95:    * Publishes a <code>LogRecord</code> to an appropriate sink,
  96:    * provided the record passes all tests for being loggable.  The
  97:    * <code>Handler</code> will localize the message of the log
  98:    * record and substitute any message parameters.
  99:    *
 100:    * <p>Most applications do not need to call this method directly.
 101:    * Instead, they will use use a {@link Logger}, which will
 102:    * create LogRecords and distribute them to registered handlers.
 103:    *
 104:    * <p>In case of an I/O failure, the <code>ErrorManager</code>
 105:    * of this <code>Handler</code> will be informed, but the caller
 106:    * of this method will not receive an exception.
 107:    *
 108:    * @param record the log event to be published.
 109:    */
 110:   public abstract void publish(LogRecord record);
 111: 
 112: 
 113:   /**
 114:    * Forces any data that may have been buffered to the underlying
 115:    * output device.
 116:    *
 117:    * <p>In case of an I/O failure, the <code>ErrorManager</code>
 118:    * of this <code>Handler</code> will be informed, but the caller
 119:    * of this method will not receive an exception.
 120:    */
 121:   public abstract void flush();
 122: 
 123: 
 124:   /**
 125:    * Closes this <code>Handler</code> after having flushed
 126:    * the buffers.  As soon as <code>close</code> has been called,
 127:    * a <code>Handler</code> should not be used anymore. Attempts
 128:    * to publish log records, to flush buffers, or to modify the
 129:    * <code>Handler</code> in any other way may throw runtime
 130:    * exceptions after calling <code>close</code>.
 131:    *
 132:    * <p>In case of an I/O failure, the <code>ErrorManager</code>
 133:    * of this <code>Handler</code> will be informed, but the caller
 134:    * of this method will not receive an exception.
 135:    *
 136:    * @throws SecurityException if a security manager exists and
 137:    *         the caller is not granted the permission to control
 138:    *         the logging infrastructure.
 139:    */
 140:   public abstract void close()
 141:     throws SecurityException;
 142: 
 143: 
 144:   /**
 145:    * Returns the <code>Formatter</code> which will be used to
 146:    * localize the text of log messages and to substitute
 147:    * message parameters.  A <code>Handler</code> is encouraged,
 148:    * but not required to actually use an assigned
 149:    * <code>Formatter</code>.
 150:    *
 151:    * @return the <code>Formatter</code> being used, or
 152:    *         <code>null</code> if this <code>Handler</code>
 153:    *         does not use formatters and no formatter has
 154:    *         ever been set by calling <code>setFormatter</code>.
 155:    */
 156:   public Formatter getFormatter()
 157:   {
 158:     return formatter;
 159:   }
 160: 
 161: 
 162:   /**
 163:    * Sets the <code>Formatter</code> which will be used to
 164:    * localize the text of log messages and to substitute
 165:    * message parameters.  A <code>Handler</code> is encouraged,
 166:    * but not required to actually use an assigned
 167:    * <code>Formatter</code>.
 168:    *
 169:    * @param formatter the new <code>Formatter</code> to use.
 170:    *
 171:    * @throws SecurityException if a security manager exists and
 172:    *         the caller is not granted the permission to control
 173:    *         the logging infrastructure.
 174:    *
 175:    * @throws NullPointerException if <code>formatter</code> is
 176:    *         <code>null</code>.
 177:    */
 178:   public void setFormatter(Formatter formatter)
 179:     throws SecurityException
 180:   {
 181:     LogManager.getLogManager().checkAccess();
 182:     
 183:     /* Throws a NullPointerException if formatter is null. */
 184:     formatter.getClass();
 185: 
 186:     this.formatter = formatter;
 187:   }
 188: 
 189: 
 190:   /**
 191:    * Returns the character encoding which this handler uses for publishing
 192:    * log records.
 193:    *
 194:    * @return the name of a character encoding, or <code>null</code>
 195:    *         for the default platform encoding.
 196:    */
 197:   public String getEncoding()
 198:   {
 199:     return encoding;
 200:   }
 201: 
 202: 
 203:   /**
 204:    * Sets the character encoding which this handler uses for publishing
 205:    * log records.  The encoding of a <code>Handler</code> must be
 206:    * set before any log records have been published.
 207:    *
 208:    * @param encoding the name of a character encoding, or <code>null</code>
 209:    *            for the default encoding.
 210:    *
 211:    * @exception SecurityException if a security manager exists and
 212:    *            the caller is not granted the permission to control
 213:    *            the logging infrastructure.
 214:    *
 215:    */
 216:   public void setEncoding(String encoding)
 217:     throws SecurityException, UnsupportedEncodingException
 218:   {
 219:     /* Should any developer ever change this implementation, they are
 220:      * advised to have a look at StreamHandler.setEncoding(String),
 221:      * which overrides this method without calling super.setEncoding.
 222:      */
 223:     LogManager.getLogManager().checkAccess();
 224: 
 225:     /* Simple check for supported encodings. This is more expensive
 226:      * than it could be, but this method is overwritten by StreamHandler
 227:      * anyway.
 228:      */
 229:     if (encoding != null)
 230:       new String(new byte[0], encoding);
 231: 
 232:     this.encoding = encoding;
 233:   }
 234: 
 235: 
 236:   /**
 237:    * Returns the <code>Filter</code> that currently controls which
 238:    * log records are being published by this <code>Handler</code>.
 239:    *
 240:    * @return the currently active <code>Filter</code>, or
 241:    *         <code>null</code> if no filter has been associated.
 242:    *         In the latter case, log records are filtered purely
 243:    *         based on their severity level.
 244:    */
 245:   public Filter getFilter()
 246:   {
 247:     return filter;
 248:   }
 249: 
 250: 
 251:   /**
 252:    * Sets the <code>Filter</code> for controlling which
 253:    * log records will be published by this <code>Handler</code>.
 254:    *
 255:    * @param filter the <code>Filter</code> to use, or
 256:    *         <code>null</code> to filter log records purely based
 257:    *         on their severity level.
 258:    */
 259:   public void setFilter(Filter filter)
 260:     throws SecurityException
 261:   {
 262:     LogManager.getLogManager().checkAccess();
 263:     this.filter = filter;
 264:   }
 265: 
 266: 
 267:   /**
 268:    * Returns the <code>ErrorManager</code> that currently deals
 269:    * with errors originating from this Handler.
 270:    *
 271:    * @exception SecurityException if a security manager exists and
 272:    *            the caller is not granted the permission to control
 273:    *            the logging infrastructure.
 274:    */
 275:   public ErrorManager getErrorManager()
 276:   {
 277:     LogManager.getLogManager().checkAccess();
 278: 
 279:     /* Developers wanting to change the subsequent code should
 280:      * have a look at Handler.reportError -- it also can create
 281:      * an ErrorManager, but does so without checking permissions
 282:      * to control the logging infrastructure.
 283:      */
 284:     if (errorManager == null)
 285:       errorManager = new ErrorManager();
 286: 
 287:     return errorManager;
 288:   }
 289: 
 290: 
 291:   public void setErrorManager(ErrorManager manager)
 292:   {
 293:     LogManager.getLogManager().checkAccess();
 294: 
 295:     /* Make sure manager is not null. */
 296:     manager.getClass();
 297: 
 298:     this.errorManager = manager;
 299:   }
 300: 
 301: 
 302:   protected void reportError(String message, Exception ex, int code)
 303:   {
 304:     if (errorManager == null)
 305:       errorManager = new ErrorManager();
 306: 
 307:     errorManager.error(message, ex, code);
 308:   }
 309: 
 310: 
 311:   /**
 312:    * Returns the severity level threshold for this <code>Handler</code>
 313:    * All log records with a lower severity level will be discarded;
 314:    * a log record of the same or a higher level will be published
 315:    * unless an installed <code>Filter</code> decides to discard it.
 316:    *
 317:    * @return the severity level below which all log messages
 318:    *         will be discarded.
 319:    */
 320:   public Level getLevel()
 321:   {
 322:     return level;
 323:   }
 324: 
 325: 
 326:   /**
 327:    * Sets the severity level threshold for this <code>Handler</code>.
 328:    * All log records with a lower severity level will be discarded;
 329:    * a log record of the same or a higher level will be published
 330:    * unless an installed <code>Filter</code> decides to discard it.
 331:    *
 332:    * @param level the severity level below which all log messages
 333:    *              will be discarded.
 334:    *
 335:    * @exception SecurityException if a security manager exists and
 336:    *            the caller is not granted the permission to control
 337:    *            the logging infrastructure.
 338:    *
 339:    * @exception NullPointerException if <code>level</code> is
 340:    *            <code>null</code>.
 341:    */
 342:   public void setLevel(Level level)
 343:   {
 344:     LogManager.getLogManager().checkAccess();
 345: 
 346:     /* Throw NullPointerException if level is null.  */
 347:     level.getClass();
 348:     this.level = level;
 349:   }
 350: 
 351: 
 352:   /**
 353:    * Checks whether a <code>LogRecord</code> would be logged
 354:    * if it was passed to this <code>Handler</code> for publication.
 355:    *
 356:    * <p>The <code>Handler</code> implementation considers a record as
 357:    * loggable if its level is greater than or equal to the severity
 358:    * level threshold.  In a second step, if a {@link Filter} has
 359:    * been installed, its {@link Filter#isLoggable(LogRecord) isLoggable}
 360:    * method is invoked. Subclasses of <code>Handler</code> can override
 361:    * this method to impose their own constraints.
 362:    *
 363:    * @param record the <code>LogRecord</code> to be checked.
 364:    *
 365:    * @return <code>true</code> if <code>record</code> would
 366:    *         be published by {@link #publish(LogRecord) publish},
 367:    *         <code>false</code> if it would be discarded.
 368:    *
 369:    * @see #setLevel(Level)
 370:    * @see #setFilter(Filter)
 371:    * @see Filter#isLoggable(LogRecord)
 372:    *
 373:    * @throws NullPointerException if <code>record</code>
 374:    *         is <code>null</code>.
 375:    */
 376:   public boolean isLoggable(LogRecord record)
 377:   {
 378:     if (record.getLevel().intValue() < level.intValue())
 379:       return false;
 380:     
 381:     if (filter != null)
 382:       return filter.isLoggable(record);
 383:     else
 384:       return true;
 385:   }
 386: }