Source for java.util.logging.MemoryHandler

   1: /* MemoryHandler.java -- a class for buffering log messages in a memory buffer
   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: package java.util.logging;
  39: 
  40: /**
  41:  * A <code>MemoryHandler</code> maintains a circular buffer of
  42:  * log records.
  43:  *
  44:  * <p><strong>Configuration:</strong> Values of the subsequent
  45:  * <code>LogManager</code> properties are taken into consideration
  46:  * when a <code>MemoryHandler</code> is initialized.
  47:  * If a property is not defined, or if it has an invalid
  48:  * value, a default is taken without an exception being thrown.
  49:  *
  50:  * <ul>
  51:  * <li><code>java.util.MemoryHandler.level</code> - specifies
  52:  *     the initial severity level threshold. Default value:
  53:  *     <code>Level.ALL</code>.</li>
  54:  * <li><code>java.util.MemoryHandler.filter</code> - specifies
  55:  *     the name of a Filter class. Default value: No Filter.</li>
  56:  * <li><code>java.util.MemoryHandler.size</code> - specifies the
  57:  *     maximum number of log records that are kept in the circular
  58:  *     buffer.  Default value: 1000.</li>
  59:  * <li><code>java.util.MemoryHandler.push</code> - specifies the
  60:  *     <code>pushLevel</code>. Default value:
  61:  *     <code>Level.SEVERE</code>.</li>
  62:  * <li><code>java.util.MemoryHandler.target</code> - specifies the
  63:  *     name of a subclass of {@link Handler} that will be used as the
  64:  *     target handler.  There is no default value for this property;
  65:  *     if it is not set, the no-argument MemoryHandler constructor
  66:  *     will throw an exception.</li>
  67:  * </ul>
  68:  *
  69:  * @author Sascha Brawer (brawer@acm.org)
  70:  */
  71: public class MemoryHandler
  72:   extends Handler
  73: {
  74:   /**
  75:    * The storage area used for buffering the unpushed log records in
  76:    * memory.
  77:    */
  78:   private final LogRecord[] buffer;
  79: 
  80: 
  81:   /**
  82:    * The current position in the circular buffer. For a new
  83:    * MemoryHandler, or immediately after {@link #push()} was called,
  84:    * the value of this variable is zero.  Each call to {@link
  85:    * #publish(LogRecord)} will store the published LogRecord into
  86:    * <code>buffer[position]</code> before position is incremented by
  87:    * one.  If position becomes greater than the size of the buffer, it
  88:    * is reset to zero.
  89:    */
  90:   private int position;
  91: 
  92: 
  93:   /**
  94:    * The number of log records which have been published, but not
  95:    * pushed yet to the target handler.
  96:    */
  97:   private int numPublished;
  98: 
  99: 
 100:   /**
 101:    * The push level threshold for this <code>Handler</code>.  When a
 102:    * record is published whose severity level is greater than or equal
 103:    * to the <code>pushLevel</code> of this <code>MemoryHandler</code>,
 104:    * the {@link #push()} method will be invoked for pushing the buffer
 105:    * contents to the target <code>Handler</code>.
 106:    */
 107:   private Level pushLevel;
 108: 
 109: 
 110:   /**
 111:    * The Handler to which log records are forwarded for actual
 112:    * publication.
 113:    */
 114:   private final Handler target;
 115: 
 116: 
 117:   /**
 118:    * Constructs a <code>MemoryHandler</code> for keeping a circular
 119:    * buffer of LogRecords; the initial configuration is determined by
 120:    * the <code>LogManager</code> properties described above.
 121:    */
 122:   public MemoryHandler()
 123:   {
 124:     this((Handler) LogManager.getInstanceProperty(
 125:        "java.util.logging.MemoryHandler.target",
 126:        Handler.class, /* default */ null),
 127:      LogManager.getIntPropertyClamped(
 128:        "java.util.logging.MemoryHandler.size",
 129:        /* default */ 1000,
 130:        /* minimum value */ 1,
 131:        /* maximum value */ Integer.MAX_VALUE),
 132:      LogManager.getLevelProperty(
 133:        "java.util.logging.MemoryHandler.push",
 134:        /* default push level */ Level.SEVERE));
 135:   }
 136: 
 137:   
 138:   /**
 139:    * Constructs a <code>MemoryHandler</code> for keeping a circular
 140:    * buffer of LogRecords, given some parameters. The values of the
 141:    * other parameters are taken from LogManager properties, as
 142:    * described above.
 143:    *
 144:    * @param target the target handler that will receive those
 145:    *               log records that are passed on for publication.
 146:    *
 147:    * @param size the number of log records that are kept in the buffer.
 148:    *             The value must be a at least one.
 149:    *
 150:    * @param pushLevel the push level threshold for this
 151:    *     <code>MemoryHandler</code>.  When a record is published whose
 152:    *     severity level is greater than or equal to
 153:    *     <code>pushLevel</code>, the {@link #push()} method will be
 154:    *     invoked in order to push the bufffer contents to
 155:    *     <code>target</code>.
 156:    *
 157:    * @throws java.lang.IllegalArgumentException if <code>size</code>
 158:    *         is negative or zero. The GNU implementation also throws
 159:    *         an IllegalArgumentException if <code>target</code> or
 160:    *         <code>pushLevel</code> are <code>null</code>, but the
 161:    *         API specification does not prescribe what should happen
 162:    *         in those cases.
 163:    */
 164:   public MemoryHandler(Handler target, int size, Level pushLevel)
 165:   { 
 166:     if ((target == null) || (size <= 0) || (pushLevel == null))
 167:       throw new IllegalArgumentException();
 168: 
 169:     buffer = new LogRecord[size];
 170:     this.pushLevel = pushLevel;
 171:     this.target = target;
 172: 
 173:     setLevel(LogManager.getLevelProperty(
 174:       "java.util.logging.MemoryHandler.level",
 175:       /* default value */ Level.ALL));
 176: 
 177:     setFilter((Filter) LogManager.getInstanceProperty(
 178:       "java.util.logging.MemoryHandler.filter",
 179:       /* must be instance of */ Filter.class,
 180:       /* default value */ null));
 181:   }
 182: 
 183: 
 184:   /**
 185:    * Stores a <code>LogRecord</code> in a fixed-size circular buffer,
 186:    * provided the record passes all tests for being loggable.  If the
 187:    * buffer is full, the oldest record will be discarded.
 188:    *
 189:    * <p>If the record has a severity level which is greater than or
 190:    * equal to the <code>pushLevel</code> of this
 191:    * <code>MemoryHandler</code>, the {@link #push()} method will be
 192:    * invoked for pushing the buffer contents to the target
 193:    * <code>Handler</code>.
 194:    *
 195:    * <p>Most applications do not need to call this method directly.
 196:    * Instead, they will use use a {@link Logger}, which will create
 197:    * LogRecords and distribute them to registered handlers.
 198:    *
 199:    * @param record the log event to be published.
 200:    */
 201:   public void publish(LogRecord record)
 202:   {
 203:     if (!isLoggable(record))
 204:       return;
 205: 
 206:     buffer[position] = record;
 207:     position = (position + 1) % buffer.length;
 208:     numPublished = numPublished + 1;
 209: 
 210:     if (record.getLevel().intValue() >= pushLevel.intValue())
 211:       push();
 212:   }
 213: 
 214: 
 215:   /**
 216:    * Pushes the contents of the memory buffer to the target
 217:    * <code>Handler</code> and clears the buffer. Note that
 218:    * the target handler will discard those records that do
 219:    * not satisfy its own severity level threshold, or that are
 220:    * not considered loggable by an installed {@link Filter}.
 221:    *
 222:    * <p>In case of an I/O failure, the {@link ErrorManager} of the
 223:    * target <code>Handler</code> will be notified, but the caller of
 224:    * this method will not receive an exception.
 225:    */
 226:   public void push()
 227:   {
 228:     int i;
 229: 
 230:     if (numPublished < buffer.length)
 231:     {
 232:       for (i = 0; i < position; i++)
 233:         target.publish(buffer[i]);
 234:     }
 235:     else
 236:     {
 237:       for (i = position; i < buffer.length; i++)
 238:     target.publish(buffer[i]);
 239:       for (i = 0; i < position; i++)
 240:     target.publish(buffer[i]);
 241:     }
 242: 
 243:     numPublished = 0;
 244:     position = 0;
 245:   }
 246: 
 247: 
 248:   /**
 249:    * Forces any data that may have been buffered by the target
 250:    * <code>Handler</code> to the underlying output device, but
 251:    * does <em>not</em> push the contents of the circular memory
 252:    * buffer to the target handler.
 253:    *
 254:    * <p>In case of an I/O failure, the {@link ErrorManager} of the
 255:    * target <code>Handler</code> will be notified, but the caller of
 256:    * this method will not receive an exception.
 257:    *
 258:    * @see #push()
 259:    */
 260:   public void flush()
 261:   {
 262:     target.flush();
 263:   }
 264: 
 265: 
 266:   /**
 267:    * Closes this <code>MemoryHandler</code> and its associated target
 268:    * handler, discarding the contents of the memory buffer.  However,
 269:    * any data that may have been buffered by the target
 270:    * <code>Handler</code> is forced to the underlying output device.
 271:    *
 272:    * <p>As soon as <code>close</code> has been called,
 273:    * a <code>Handler</code> should not be used anymore. Attempts
 274:    * to publish log records, to flush buffers, or to modify the
 275:    * <code>Handler</code> in any other way may throw runtime
 276:    * exceptions after calling <code>close</code>.</p>
 277:    *
 278:    * <p>In case of an I/O failure, the <code>ErrorManager</code> of
 279:    * the associated target <code>Handler</code> will be informed, but
 280:    * the caller of this method will not receive an exception.</p>
 281:    *
 282:    * @throws SecurityException if a security manager exists and
 283:    *         the caller is not granted the permission to control
 284:    *         the logging infrastructure.
 285:    *
 286:    * @see #push()
 287:    */
 288:   public void close()
 289:     throws SecurityException
 290:   {
 291:     push();
 292: 
 293:     /* This will check for LoggingPermission("control"). If the
 294:      * current security context does not grant this permission,
 295:      * push() has been executed, but this does not impose a
 296:      * security risk.
 297:      */
 298:     target.close();
 299:   }
 300: 
 301:     
 302: 
 303:   /**
 304:    * Returns the push level threshold for this <code>Handler</code>.
 305:    * When a record is published whose severity level is greater
 306:    * than or equal to the <code>pushLevel</code> of this
 307:    * <code>MemoryHandler</code>, the {@link #push()} method will be
 308:    * invoked for pushing the buffer contents to the target
 309:    * <code>Handler</code>.
 310:    *
 311:    * @return the push level threshold for automatic pushing.
 312:    */
 313:   public Level getPushLevel()
 314:   {
 315:     return pushLevel;
 316:   }
 317: 
 318: 
 319:   /**
 320:    * Sets the push level threshold for this <code>Handler</code>.
 321:    * When a record is published whose severity level is greater
 322:    * than or equal to the <code>pushLevel</code> of this
 323:    * <code>MemoryHandler</code>, the {@link #push()} method will be
 324:    * invoked for pushing the buffer contents to the target
 325:    * <code>Handler</code>.
 326:    *
 327:    * @param pushLevel the push level threshold for automatic pushing.
 328:    *
 329:    * @exception SecurityException if a security manager exists and
 330:    *            the caller is not granted the permission to control
 331:    *            the logging infrastructure.
 332:    *
 333:    * @exception NullPointerException if <code>pushLevel</code> is
 334:    *            <code>null</code>.
 335:    */
 336:   public void setPushLevel(Level pushLevel)
 337:   {
 338:     LogManager.getLogManager().checkAccess();
 339: 
 340:     /* Throws a NullPointerException if pushLevel is null. */
 341:     pushLevel.getClass();
 342: 
 343:     this.pushLevel = pushLevel;
 344:   }
 345: }