MemoryHandler.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /* MemoryHandler.java -- a class for buffering log messages in a memory buffer
  2. Copyright (C) 2002, 2004 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. package java.util.logging;
  32. /**
  33. * A <code>MemoryHandler</code> maintains a circular buffer of
  34. * log records.
  35. *
  36. * <p><strong>Configuration:</strong> Values of the subsequent
  37. * <code>LogManager</code> properties are taken into consideration
  38. * when a <code>MemoryHandler</code> is initialized.
  39. * If a property is not defined, or if it has an invalid
  40. * value, a default is taken without an exception being thrown.
  41. *
  42. * <ul>
  43. * <li><code>java.util.MemoryHandler.level</code> - specifies
  44. * the initial severity level threshold. Default value:
  45. * <code>Level.ALL</code>.</li>
  46. * <li><code>java.util.MemoryHandler.filter</code> - specifies
  47. * the name of a Filter class. Default value: No Filter.</li>
  48. * <li><code>java.util.MemoryHandler.size</code> - specifies the
  49. * maximum number of log records that are kept in the circular
  50. * buffer. Default value: 1000.</li>
  51. * <li><code>java.util.MemoryHandler.push</code> - specifies the
  52. * <code>pushLevel</code>. Default value:
  53. * <code>Level.SEVERE</code>.</li>
  54. * <li><code>java.util.MemoryHandler.target</code> - specifies the
  55. * name of a subclass of {@link Handler} that will be used as the
  56. * target handler. There is no default value for this property;
  57. * if it is not set, the no-argument MemoryHandler constructor
  58. * will throw an exception.</li>
  59. * </ul>
  60. *
  61. * @author Sascha Brawer (brawer@acm.org)
  62. */
  63. public class MemoryHandler
  64. extends Handler
  65. {
  66. /**
  67. * The storage area used for buffering the unpushed log records in
  68. * memory.
  69. */
  70. private final LogRecord[] buffer;
  71. /**
  72. * The current position in the circular buffer. For a new
  73. * MemoryHandler, or immediately after {@link #push()} was called,
  74. * the value of this variable is zero. Each call to {@link
  75. * #publish(LogRecord)} will store the published LogRecord into
  76. * <code>buffer[position]</code> before position is incremented by
  77. * one. If position becomes greater than the size of the buffer, it
  78. * is reset to zero.
  79. */
  80. private int position;
  81. /**
  82. * The number of log records which have been published, but not
  83. * pushed yet to the target handler.
  84. */
  85. private int numPublished;
  86. /**
  87. * The push level threshold for this <code>Handler</code>. When a
  88. * record is published whose severity level is greater than or equal
  89. * to the <code>pushLevel</code> of this <code>MemoryHandler</code>,
  90. * the {@link #push()} method will be invoked for pushing the buffer
  91. * contents to the target <code>Handler</code>.
  92. */
  93. private Level pushLevel;
  94. /**
  95. * The Handler to which log records are forwarded for actual
  96. * publication.
  97. */
  98. private final Handler target;
  99. /**
  100. * Constructs a <code>MemoryHandler</code> for keeping a circular
  101. * buffer of LogRecords; the initial configuration is determined by
  102. * the <code>LogManager</code> properties described above.
  103. */
  104. public MemoryHandler()
  105. {
  106. this((Handler) LogManager.getInstanceProperty(
  107. "java.util.logging.MemoryHandler.target",
  108. Handler.class, /* default */ null),
  109. LogManager.getIntPropertyClamped(
  110. "java.util.logging.MemoryHandler.size",
  111. /* default */ 1000,
  112. /* minimum value */ 1,
  113. /* maximum value */ Integer.MAX_VALUE),
  114. LogManager.getLevelProperty(
  115. "java.util.logging.MemoryHandler.push",
  116. /* default push level */ Level.SEVERE));
  117. }
  118. /**
  119. * Constructs a <code>MemoryHandler</code> for keeping a circular
  120. * buffer of LogRecords, given some parameters. The values of the
  121. * other parameters are taken from LogManager properties, as
  122. * described above.
  123. *
  124. * @param target the target handler that will receive those
  125. * log records that are passed on for publication.
  126. *
  127. * @param size the number of log records that are kept in the buffer.
  128. * The value must be a at least one.
  129. *
  130. * @param pushLevel the push level threshold for this
  131. * <code>MemoryHandler</code>. When a record is published whose
  132. * severity level is greater than or equal to
  133. * <code>pushLevel</code>, the {@link #push()} method will be
  134. * invoked in order to push the bufffer contents to
  135. * <code>target</code>.
  136. *
  137. * @throws java.lang.IllegalArgumentException if <code>size</code>
  138. * is negative or zero. The GNU implementation also throws
  139. * an IllegalArgumentException if <code>target</code> or
  140. * <code>pushLevel</code> are <code>null</code>, but the
  141. * API specification does not prescribe what should happen
  142. * in those cases.
  143. */
  144. public MemoryHandler(Handler target, int size, Level pushLevel)
  145. {
  146. if ((target == null) || (size <= 0) || (pushLevel == null))
  147. throw new IllegalArgumentException();
  148. buffer = new LogRecord[size];
  149. this.pushLevel = pushLevel;
  150. this.target = target;
  151. setLevel(LogManager.getLevelProperty(
  152. "java.util.logging.MemoryHandler.level",
  153. /* default value */ Level.ALL));
  154. setFilter((Filter) LogManager.getInstanceProperty(
  155. "java.util.logging.MemoryHandler.filter",
  156. /* must be instance of */ Filter.class,
  157. /* default value */ null));
  158. }
  159. /**
  160. * Stores a <code>LogRecord</code> in a fixed-size circular buffer,
  161. * provided the record passes all tests for being loggable. If the
  162. * buffer is full, the oldest record will be discarded.
  163. *
  164. * <p>If the record has a severity level which is greater than or
  165. * equal to the <code>pushLevel</code> of this
  166. * <code>MemoryHandler</code>, the {@link #push()} method will be
  167. * invoked for pushing the buffer contents to the target
  168. * <code>Handler</code>.
  169. *
  170. * <p>Most applications do not need to call this method directly.
  171. * Instead, they will use use a {@link Logger}, which will create
  172. * LogRecords and distribute them to registered handlers.
  173. *
  174. * @param record the log event to be published.
  175. */
  176. public void publish(LogRecord record)
  177. {
  178. if (!isLoggable(record))
  179. return;
  180. buffer[position] = record;
  181. position = (position + 1) % buffer.length;
  182. numPublished = numPublished + 1;
  183. if (record.getLevel().intValue() >= pushLevel.intValue())
  184. push();
  185. }
  186. /**
  187. * Pushes the contents of the memory buffer to the target
  188. * <code>Handler</code> and clears the buffer. Note that
  189. * the target handler will discard those records that do
  190. * not satisfy its own severity level threshold, or that are
  191. * not considered loggable by an installed {@link Filter}.
  192. *
  193. * <p>In case of an I/O failure, the {@link ErrorManager} of the
  194. * target <code>Handler</code> will be notified, but the caller of
  195. * this method will not receive an exception.
  196. */
  197. public void push()
  198. {
  199. int i;
  200. if (numPublished < buffer.length)
  201. {
  202. for (i = 0; i < position; i++)
  203. target.publish(buffer[i]);
  204. }
  205. else
  206. {
  207. for (i = position; i < buffer.length; i++)
  208. target.publish(buffer[i]);
  209. for (i = 0; i < position; i++)
  210. target.publish(buffer[i]);
  211. }
  212. numPublished = 0;
  213. position = 0;
  214. }
  215. /**
  216. * Forces any data that may have been buffered by the target
  217. * <code>Handler</code> to the underlying output device, but
  218. * does <em>not</em> push the contents of the circular memory
  219. * buffer to the target handler.
  220. *
  221. * <p>In case of an I/O failure, the {@link ErrorManager} of the
  222. * target <code>Handler</code> will be notified, but the caller of
  223. * this method will not receive an exception.
  224. *
  225. * @see #push()
  226. */
  227. public void flush()
  228. {
  229. target.flush();
  230. }
  231. /**
  232. * Closes this <code>MemoryHandler</code> and its associated target
  233. * handler, discarding the contents of the memory buffer. However,
  234. * any data that may have been buffered by the target
  235. * <code>Handler</code> is forced to the underlying output device.
  236. *
  237. * <p>As soon as <code>close</code> has been called,
  238. * a <code>Handler</code> should not be used anymore. Attempts
  239. * to publish log records, to flush buffers, or to modify the
  240. * <code>Handler</code> in any other way may throw runtime
  241. * exceptions after calling <code>close</code>.</p>
  242. *
  243. * <p>In case of an I/O failure, the <code>ErrorManager</code> of
  244. * the associated target <code>Handler</code> will be informed, but
  245. * the caller of this method will not receive an exception.</p>
  246. *
  247. * @throws SecurityException if a security manager exists and
  248. * the caller is not granted the permission to control
  249. * the logging infrastructure.
  250. *
  251. * @see #push()
  252. */
  253. public void close()
  254. throws SecurityException
  255. {
  256. push();
  257. /* This will check for LoggingPermission("control"). If the
  258. * current security context does not grant this permission,
  259. * push() has been executed, but this does not impose a
  260. * security risk.
  261. */
  262. target.close();
  263. }
  264. /**
  265. * Returns the push level threshold for this <code>Handler</code>.
  266. * When a record is published whose severity level is greater
  267. * than or equal to the <code>pushLevel</code> of this
  268. * <code>MemoryHandler</code>, the {@link #push()} method will be
  269. * invoked for pushing the buffer contents to the target
  270. * <code>Handler</code>.
  271. *
  272. * @return the push level threshold for automatic pushing.
  273. */
  274. public Level getPushLevel()
  275. {
  276. return pushLevel;
  277. }
  278. /**
  279. * Sets the push level threshold for this <code>Handler</code>.
  280. * When a record is published whose severity level is greater
  281. * than or equal to the <code>pushLevel</code> of this
  282. * <code>MemoryHandler</code>, the {@link #push()} method will be
  283. * invoked for pushing the buffer contents to the target
  284. * <code>Handler</code>.
  285. *
  286. * @param pushLevel the push level threshold for automatic pushing.
  287. *
  288. * @exception SecurityException if a security manager exists and
  289. * the caller is not granted the permission to control
  290. * the logging infrastructure.
  291. *
  292. * @exception NullPointerException if <code>pushLevel</code> is
  293. * <code>null</code>.
  294. */
  295. public void setPushLevel(Level pushLevel)
  296. {
  297. LogManager.getLogManager().checkAccess();
  298. /* Throws a NullPointerException if pushLevel is null. */
  299. pushLevel.getClass();
  300. this.pushLevel = pushLevel;
  301. }
  302. }