| /* MemoryHandler.java -- a class for buffering log messages in a memory buffer | |
| Copyright (C) 2002, 2004 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package java.util.logging; | |
| /** | |
| * A <code>MemoryHandler</code> maintains a circular buffer of | |
| * log records. | |
| * | |
| * <p><strong>Configuration:</strong> Values of the subsequent | |
| * <code>LogManager</code> properties are taken into consideration | |
| * when a <code>MemoryHandler</code> is initialized. | |
| * If a property is not defined, or if it has an invalid | |
| * value, a default is taken without an exception being thrown. | |
| * | |
| * <ul> | |
| * <li><code>java.util.MemoryHandler.level</code> - specifies | |
| * the initial severity level threshold. Default value: | |
| * <code>Level.ALL</code>.</li> | |
| * <li><code>java.util.MemoryHandler.filter</code> - specifies | |
| * the name of a Filter class. Default value: No Filter.</li> | |
| * <li><code>java.util.MemoryHandler.size</code> - specifies the | |
| * maximum number of log records that are kept in the circular | |
| * buffer. Default value: 1000.</li> | |
| * <li><code>java.util.MemoryHandler.push</code> - specifies the | |
| * <code>pushLevel</code>. Default value: | |
| * <code>Level.SEVERE</code>.</li> | |
| * <li><code>java.util.MemoryHandler.target</code> - specifies the | |
| * name of a subclass of {@link Handler} that will be used as the | |
| * target handler. There is no default value for this property; | |
| * if it is not set, the no-argument MemoryHandler constructor | |
| * will throw an exception.</li> | |
| * </ul> | |
| * | |
| * @author Sascha Brawer (brawer@acm.org) | |
| */ | |
| public class MemoryHandler | |
| extends Handler | |
| { | |
| /** | |
| * The storage area used for buffering the unpushed log records in | |
| * memory. | |
| */ | |
| private final LogRecord[] buffer; | |
| /** | |
| * The current position in the circular buffer. For a new | |
| * MemoryHandler, or immediately after {@link #push()} was called, | |
| * the value of this variable is zero. Each call to {@link | |
| * #publish(LogRecord)} will store the published LogRecord into | |
| * <code>buffer[position]</code> before position is incremented by | |
| * one. If position becomes greater than the size of the buffer, it | |
| * is reset to zero. | |
| */ | |
| private int position; | |
| /** | |
| * The number of log records which have been published, but not | |
| * pushed yet to the target handler. | |
| */ | |
| private int numPublished; | |
| /** | |
| * The push level threshold for this <code>Handler</code>. When a | |
| * record is published whose severity level is greater than or equal | |
| * to the <code>pushLevel</code> of this <code>MemoryHandler</code>, | |
| * the {@link #push()} method will be invoked for pushing the buffer | |
| * contents to the target <code>Handler</code>. | |
| */ | |
| private Level pushLevel; | |
| /** | |
| * The Handler to which log records are forwarded for actual | |
| * publication. | |
| */ | |
| private final Handler target; | |
| /** | |
| * Constructs a <code>MemoryHandler</code> for keeping a circular | |
| * buffer of LogRecords; the initial configuration is determined by | |
| * the <code>LogManager</code> properties described above. | |
| */ | |
| public MemoryHandler() | |
| { | |
| this((Handler) LogManager.getInstanceProperty( | |
| "java.util.logging.MemoryHandler.target", | |
| Handler.class, /* default */ null), | |
| LogManager.getIntPropertyClamped( | |
| "java.util.logging.MemoryHandler.size", | |
| /* default */ 1000, | |
| /* minimum value */ 1, | |
| /* maximum value */ Integer.MAX_VALUE), | |
| LogManager.getLevelProperty( | |
| "java.util.logging.MemoryHandler.push", | |
| /* default push level */ Level.SEVERE)); | |
| } | |
| /** | |
| * Constructs a <code>MemoryHandler</code> for keeping a circular | |
| * buffer of LogRecords, given some parameters. The values of the | |
| * other parameters are taken from LogManager properties, as | |
| * described above. | |
| * | |
| * @param target the target handler that will receive those | |
| * log records that are passed on for publication. | |
| * | |
| * @param size the number of log records that are kept in the buffer. | |
| * The value must be a at least one. | |
| * | |
| * @param pushLevel the push level threshold for this | |
| * <code>MemoryHandler</code>. When a record is published whose | |
| * severity level is greater than or equal to | |
| * <code>pushLevel</code>, the {@link #push()} method will be | |
| * invoked in order to push the bufffer contents to | |
| * <code>target</code>. | |
| * | |
| * @throws java.lang.IllegalArgumentException if <code>size</code> | |
| * is negative or zero. The GNU implementation also throws | |
| * an IllegalArgumentException if <code>target</code> or | |
| * <code>pushLevel</code> are <code>null</code>, but the | |
| * API specification does not prescribe what should happen | |
| * in those cases. | |
| */ | |
| public MemoryHandler(Handler target, int size, Level pushLevel) | |
| { | |
| if ((target == null) || (size <= 0) || (pushLevel == null)) | |
| throw new IllegalArgumentException(); | |
| buffer = new LogRecord[size]; | |
| this.pushLevel = pushLevel; | |
| this.target = target; | |
| setLevel(LogManager.getLevelProperty( | |
| "java.util.logging.MemoryHandler.level", | |
| /* default value */ Level.ALL)); | |
| setFilter((Filter) LogManager.getInstanceProperty( | |
| "java.util.logging.MemoryHandler.filter", | |
| /* must be instance of */ Filter.class, | |
| /* default value */ null)); | |
| } | |
| /** | |
| * Stores a <code>LogRecord</code> in a fixed-size circular buffer, | |
| * provided the record passes all tests for being loggable. If the | |
| * buffer is full, the oldest record will be discarded. | |
| * | |
| * <p>If the record has a severity level which is greater than or | |
| * equal to the <code>pushLevel</code> of this | |
| * <code>MemoryHandler</code>, the {@link #push()} method will be | |
| * invoked for pushing the buffer contents to the target | |
| * <code>Handler</code>. | |
| * | |
| * <p>Most applications do not need to call this method directly. | |
| * Instead, they will use use a {@link Logger}, which will create | |
| * LogRecords and distribute them to registered handlers. | |
| * | |
| * @param record the log event to be published. | |
| */ | |
| public void publish(LogRecord record) | |
| { | |
| if (!isLoggable(record)) | |
| return; | |
| buffer[position] = record; | |
| position = (position + 1) % buffer.length; | |
| numPublished = numPublished + 1; | |
| if (record.getLevel().intValue() >= pushLevel.intValue()) | |
| push(); | |
| } | |
| /** | |
| * Pushes the contents of the memory buffer to the target | |
| * <code>Handler</code> and clears the buffer. Note that | |
| * the target handler will discard those records that do | |
| * not satisfy its own severity level threshold, or that are | |
| * not considered loggable by an installed {@link Filter}. | |
| * | |
| * <p>In case of an I/O failure, the {@link ErrorManager} of the | |
| * target <code>Handler</code> will be notified, but the caller of | |
| * this method will not receive an exception. | |
| */ | |
| public void push() | |
| { | |
| int i; | |
| if (numPublished < buffer.length) | |
| { | |
| for (i = 0; i < position; i++) | |
| target.publish(buffer[i]); | |
| } | |
| else | |
| { | |
| for (i = position; i < buffer.length; i++) | |
| target.publish(buffer[i]); | |
| for (i = 0; i < position; i++) | |
| target.publish(buffer[i]); | |
| } | |
| numPublished = 0; | |
| position = 0; | |
| } | |
| /** | |
| * Forces any data that may have been buffered by the target | |
| * <code>Handler</code> to the underlying output device, but | |
| * does <em>not</em> push the contents of the circular memory | |
| * buffer to the target handler. | |
| * | |
| * <p>In case of an I/O failure, the {@link ErrorManager} of the | |
| * target <code>Handler</code> will be notified, but the caller of | |
| * this method will not receive an exception. | |
| * | |
| * @see #push() | |
| */ | |
| public void flush() | |
| { | |
| target.flush(); | |
| } | |
| /** | |
| * Closes this <code>MemoryHandler</code> and its associated target | |
| * handler, discarding the contents of the memory buffer. However, | |
| * any data that may have been buffered by the target | |
| * <code>Handler</code> is forced to the underlying output device. | |
| * | |
| * <p>As soon as <code>close</code> has been called, | |
| * a <code>Handler</code> should not be used anymore. Attempts | |
| * to publish log records, to flush buffers, or to modify the | |
| * <code>Handler</code> in any other way may throw runtime | |
| * exceptions after calling <code>close</code>.</p> | |
| * | |
| * <p>In case of an I/O failure, the <code>ErrorManager</code> of | |
| * the associated target <code>Handler</code> will be informed, but | |
| * the caller of this method will not receive an exception.</p> | |
| * | |
| * @throws SecurityException if a security manager exists and | |
| * the caller is not granted the permission to control | |
| * the logging infrastructure. | |
| * | |
| * @see #push() | |
| */ | |
| public void close() | |
| throws SecurityException | |
| { | |
| push(); | |
| /* This will check for LoggingPermission("control"). If the | |
| * current security context does not grant this permission, | |
| * push() has been executed, but this does not impose a | |
| * security risk. | |
| */ | |
| target.close(); | |
| } | |
| /** | |
| * Returns the push level threshold for this <code>Handler</code>. | |
| * When a record is published whose severity level is greater | |
| * than or equal to the <code>pushLevel</code> of this | |
| * <code>MemoryHandler</code>, the {@link #push()} method will be | |
| * invoked for pushing the buffer contents to the target | |
| * <code>Handler</code>. | |
| * | |
| * @return the push level threshold for automatic pushing. | |
| */ | |
| public Level getPushLevel() | |
| { | |
| return pushLevel; | |
| } | |
| /** | |
| * Sets the push level threshold for this <code>Handler</code>. | |
| * When a record is published whose severity level is greater | |
| * than or equal to the <code>pushLevel</code> of this | |
| * <code>MemoryHandler</code>, the {@link #push()} method will be | |
| * invoked for pushing the buffer contents to the target | |
| * <code>Handler</code>. | |
| * | |
| * @param pushLevel the push level threshold for automatic pushing. | |
| * | |
| * @exception SecurityException if a security manager exists and | |
| * the caller is not granted the permission to control | |
| * the logging infrastructure. | |
| * | |
| * @exception NullPointerException if <code>pushLevel</code> is | |
| * <code>null</code>. | |
| */ | |
| public void setPushLevel(Level pushLevel) | |
| { | |
| LogManager.getLogManager().checkAccess(); | |
| /* Throws a NullPointerException if pushLevel is null. */ | |
| pushLevel.getClass(); | |
| this.pushLevel = pushLevel; | |
| } | |
| } |