Frames | No Frames |
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: }