1 /* Logger.java -- a class for logging messages
2    Copyright (C) 2002, 2004, 2006, 2007 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.util.List;
42 import java.util.MissingResourceException;
43 import java.util.ResourceBundle;
44 import java.security.AccessController;
45 import java.security.PrivilegedAction;
46 
47 /**
48  * A Logger is used for logging information about events. Usually, there
49  * is a seprate logger for each subsystem or component, although there
50  * is a shared instance for components that make only occasional use of
51  * the logging framework.
52  *
53  * <p>It is common to name a logger after the name of a corresponding
54  * Java package.  Loggers are organized into a hierarchical namespace;
55  * for example, the logger <code>"org.gnu.foo"</code> is the
56  * <em>parent</em> of logger <code>"org.gnu.foo.bar"</code>.
57  *
58  * <p>A logger for a named subsystem can be obtained through {@link
59  * java.util.logging.Logger#getLogger(java.lang.String)}.  However,
60  * only code which has been granted the permission to control the
61  * logging infrastructure will be allowed to customize that logger.
62  * Untrusted code can obtain a private, anonymous logger through
63  * {@link #getAnonymousLogger()} if it wants to perform any
64  * modifications to the logger.
65  *
66  * <p>FIXME: Write more documentation.
67  *
68  * @author Sascha Brawer (brawer@acm.org)
69  */
70 public class Logger
71 {
72 
73   static final Logger root = new Logger("", null);
74 
75   /**
76    * A logger provided to applications that make only occasional use
77    * of the logging framework, typically early prototypes.  Serious
78    * products are supposed to create and use their own Loggers, so
79    * they can be controlled individually.
80    */
81   public static final Logger global;
82 
83   static
84     {
85       // Our class might be initialized from an unprivileged context
86       global = (Logger) AccessController.doPrivileged
87 	(new PrivilegedAction()
88 	  {
89 	    public Object run()
90 	    {
91 	      return getLogger("global");
92 	    }
93 	  });
94     }
95 
96 
97   /**
98    * The name of the Logger, or <code>null</code> if the logger is
99    * anonymous.
100    *
101    * <p>A previous version of the GNU Classpath implementation granted
102    * untrusted code the permission to control any logger whose name
103    * was null.  However, test code revealed that the Sun J2SE 1.4
104    * reference implementation enforces the security control for any
105    * logger that was not created through getAnonymousLogger, even if
106    * it has a null name.  Therefore, a separate flag {@link
107    * Logger#anonymous} was introduced.
108    */
109   private final String name;
110 
111 
112   /**
113    * The name of the resource bundle used for localization.
114    *
115    * <p>This variable cannot be declared as <code>final</code>
116    * because its value can change as a result of calling
117    * getLogger(String,String).
118    */
119   private String resourceBundleName;
120 
121 
122   /**
123    * The resource bundle used for localization.
124    *
125    * <p>This variable cannot be declared as <code>final</code>
126    * because its value can change as a result of calling
127    * getLogger(String,String).
128    */
129   private ResourceBundle resourceBundle;
130 
131   private Filter filter;
132 
133   private final List handlerList = new java.util.ArrayList(4);
134   private Handler[] handlers = new Handler[0];
135 
136   /**
137    * Indicates whether or not this logger is anonymous.  While
138    * a LoggingPermission is required for any modifications to
139    * a normal logger, untrusted code can obtain an anonymous logger
140    * and modify it according to its needs.
141    *
142    * <p>A previous version of the GNU Classpath implementation
143    * granted access to every logger whose name was null.
144    * However, test code revealed that the Sun J2SE 1.4 reference
145    * implementation enforces the security control for any logger
146    * that was not created through getAnonymousLogger, even
147    * if it has a null name.
148    */
149   private boolean anonymous;
150 
151 
152   private boolean useParentHandlers;
153 
154   private Level level;
155 
156   private Logger parent;
157 
158   /**
159    * Constructs a Logger for a subsystem.  Most applications do not
160    * need to create new Loggers explicitly; instead, they should call
161    * the static factory methods
162    * {@link #getLogger(java.lang.String,java.lang.String) getLogger}
163    * (with ResourceBundle for localization) or
164    * {@link #getLogger(java.lang.String) getLogger} (without
165    * ResourceBundle), respectively.
166    *
167    * @param name the name for the logger, for example "java.awt"
168    *             or "com.foo.bar". The name should be based on
169    *             the name of the package issuing log records
170    *             and consist of dot-separated Java identifiers.
171    *
172    * @param resourceBundleName the name of a resource bundle
173    *        for localizing messages, or <code>null</code>
174    *	    to indicate that messages do not need to be localized.
175    *
176    * @throws java.util.MissingResourceException if
177    *         <code>resourceBundleName</code> is not <code>null</code>
178    *         and no such bundle could be located.
179    */
Logger(String name, String resourceBundleName)180   protected Logger(String name, String resourceBundleName)
181     throws MissingResourceException
182   {
183     this.name = name;
184     this.resourceBundleName = resourceBundleName;
185 
186     if (resourceBundleName == null)
187       resourceBundle = null;
188     else
189       resourceBundle = ResourceBundle.getBundle(resourceBundleName);
190 
191     level = null;
192 
193     /* This is null when the root logger is being constructed,
194      * and the root logger afterwards.
195      */
196     parent = root;
197 
198     useParentHandlers = (parent != null);
199   }
200 
201 
202 
203   /**
204    * Finds a registered logger for a subsystem, or creates one in
205    * case no logger has been registered yet.
206    *
207    * @param name the name for the logger, for example "java.awt"
208    *             or "com.foo.bar". The name should be based on
209    *             the name of the package issuing log records
210    *             and consist of dot-separated Java identifiers.
211    *
212    * @throws IllegalArgumentException if a logger for the subsystem
213    *         identified by <code>name</code> has already been created,
214    *         but uses a a resource bundle for localizing messages.
215    *
216    * @throws NullPointerException if <code>name</code> is
217    *         <code>null</code>.
218    *
219    * @return a logger for the subsystem specified by <code>name</code>
220    *         that does not localize messages.
221    */
getLogger(String name)222   public static Logger getLogger(String name)
223   {
224     return getLogger(name, null);
225   }
226 
227 
228   /**
229    * Finds a registered logger for a subsystem, or creates one in case
230    * no logger has been registered yet.
231    *
232    * <p>If a logger with the specified name has already been
233    * registered, the behavior depends on the resource bundle that is
234    * currently associated with the existing logger.
235    *
236    * <ul><li>If the existing logger uses the same resource bundle as
237    * specified by <code>resourceBundleName</code>, the existing logger
238    * is returned.</li>
239    *
240    * <li>If the existing logger currently does not localize messages,
241    * the existing logger is modified to use the bundle specified by
242    * <code>resourceBundleName</code>.  The existing logger is then
243    * returned.  Therefore, all subsystems currently using this logger
244    * will produce localized messages from now on.</li>
245    *
246    * <li>If the existing logger already has an associated resource
247    * bundle, but a different one than specified by
248    * <code>resourceBundleName</code>, an
249    * <code>IllegalArgumentException</code> is thrown.</li></ul>
250    *
251    * @param name the name for the logger, for example "java.awt"
252    *             or "org.gnu.foo". The name should be based on
253    *             the name of the package issuing log records
254    *             and consist of dot-separated Java identifiers.
255    *
256    * @param resourceBundleName the name of a resource bundle
257    *        for localizing messages, or <code>null</code>
258    *	    to indicate that messages do not need to be localized.
259    *
260    * @return a logger for the subsystem specified by <code>name</code>.
261    *
262    * @throws java.util.MissingResourceException if
263    *         <code>resourceBundleName</code> is not <code>null</code>
264    *         and no such bundle could be located.
265    *
266    * @throws IllegalArgumentException if a logger for the subsystem
267    *         identified by <code>name</code> has already been created,
268    *         but uses a different resource bundle for localizing
269    *         messages.
270    *
271    * @throws NullPointerException if <code>name</code> is
272    *         <code>null</code>.
273    */
getLogger(String name, String resourceBundleName)274   public static Logger getLogger(String name, String resourceBundleName)
275   {
276     LogManager lm = LogManager.getLogManager();
277     Logger     result;
278 
279     if (name == null)
280       throw new NullPointerException();
281 
282     /* Without synchronized(lm), it could happen that another thread
283      * would create a logger between our calls to getLogger and
284      * addLogger.  While addLogger would indicate this by returning
285      * false, we could not be sure that this other logger was still
286      * existing when we called getLogger a second time in order
287      * to retrieve it -- note that LogManager is only allowed to
288      * keep weak references to registered loggers, so Loggers
289      * can be garbage collected at any time in general, and between
290      * our call to addLogger and our second call go getLogger
291      * in particular.
292      *
293      * Of course, we assume here that LogManager.addLogger etc.
294      * are synchronizing on the global LogManager object. There
295      * is a comment in the implementation of LogManager.addLogger
296      * referring to this comment here, so that any change in
297      * the synchronization of LogManager will be reflected here.
298      */
299     synchronized (lm)
300     {
301       result = lm.getLogger(name);
302       if (result == null)
303       {
304 	boolean couldBeAdded;
305 
306 	result = new Logger(name, resourceBundleName);
307 	couldBeAdded = lm.addLogger(result);
308 	if (!couldBeAdded)
309 	  throw new IllegalStateException("cannot register new logger");
310       }
311       else
312       {
313 	/* The logger already exists. Make sure it uses
314 	 * the same resource bundle for localizing messages.
315 	 */
316 	String existingBundleName = result.getResourceBundleName();
317 
318 	/* The Sun J2SE 1.4 reference implementation will return the
319 	 * registered logger object, even if it does not have a resource
320 	 * bundle associated with it. However, it seems to change the
321 	 * resourceBundle of the registered logger to the bundle
322 	 * whose name was passed to getLogger.
323 	 */
324 	if ((existingBundleName == null) && (resourceBundleName != null))
325 	{
326 	  /* If ResourceBundle.getBundle throws an exception, the
327 	   * existing logger will be unchanged.  This would be
328 	   * different if the assignment to resourceBundleName
329 	   * came first.
330 	   */
331 	  result.resourceBundle = ResourceBundle.getBundle(resourceBundleName);
332 	  result.resourceBundleName = resourceBundleName;
333 	  return result;
334 	}
335 
336 	if ((existingBundleName != resourceBundleName)
337 	    && ((existingBundleName == null)
338 		|| !existingBundleName.equals(resourceBundleName)))
339 	{
340 	  throw new IllegalArgumentException();
341 	}
342       }
343     }
344 
345     return result;
346   }
347 
348 
349   /**
350    * Creates a new, unnamed logger.  Unnamed loggers are not
351    * registered in the namespace of the LogManager, and no special
352    * security permission is required for changing their state.
353    * Therefore, untrusted applets are able to modify their private
354    * logger instance obtained through this method.
355    *
356    * <p>The parent of the newly created logger will the the root
357    * logger, from which the level threshold and the handlers are
358    * inherited.
359    */
getAnonymousLogger()360   public static Logger getAnonymousLogger()
361   {
362     return getAnonymousLogger(null);
363   }
364 
365 
366   /**
367    * Creates a new, unnamed logger.  Unnamed loggers are not
368    * registered in the namespace of the LogManager, and no special
369    * security permission is required for changing their state.
370    * Therefore, untrusted applets are able to modify their private
371    * logger instance obtained through this method.
372    *
373    * <p>The parent of the newly created logger will the the root
374    * logger, from which the level threshold and the handlers are
375    * inherited.
376    *
377    * @param resourceBundleName the name of a resource bundle
378    *        for localizing messages, or <code>null</code>
379    *	    to indicate that messages do not need to be localized.
380    *
381    * @throws java.util.MissingResourceException if
382    *         <code>resourceBundleName</code> is not <code>null</code>
383    *         and no such bundle could be located.
384    */
getAnonymousLogger(String resourceBundleName)385   public static Logger getAnonymousLogger(String resourceBundleName)
386     throws MissingResourceException
387   {
388     Logger  result;
389 
390     result = new Logger(null, resourceBundleName);
391     result.anonymous = true;
392     return result;
393   }
394 
395 
396   /**
397    * Returns the name of the resource bundle that is being used for
398    * localizing messages.
399    *
400    * @return the name of the resource bundle used for localizing messages,
401    *         or <code>null</code> if the parent's resource bundle
402    *         is used for this purpose.
403    */
getResourceBundleName()404   public synchronized String getResourceBundleName()
405   {
406     return resourceBundleName;
407   }
408 
409 
410   /**
411    * Returns the resource bundle that is being used for localizing
412    * messages.
413    *
414    * @return the resource bundle used for localizing messages,
415    *         or <code>null</code> if the parent's resource bundle
416    *         is used for this purpose.
417    */
getResourceBundle()418   public synchronized ResourceBundle getResourceBundle()
419   {
420     return resourceBundle;
421   }
422 
423 
424   /**
425    * Returns the severity level threshold for this <code>Handler</code>.
426    * All log records with a lower severity level will be discarded;
427    * a log record of the same or a higher level will be published
428    * unless an installed <code>Filter</code> decides to discard it.
429    *
430    * @return the severity level below which all log messages will be
431    *         discarded, or <code>null</code> if the logger inherits
432    *         the threshold from its parent.
433    */
getLevel()434   public synchronized Level getLevel()
435   {
436     return level;
437   }
438 
439 
440   /**
441    * Returns whether or not a message of the specified level
442    * would be logged by this logger.
443    *
444    * @throws NullPointerException if <code>level</code>
445    *         is <code>null</code>.
446    */
isLoggable(Level level)447   public synchronized boolean isLoggable(Level level)
448   {
449     if (this.level != null)
450       return this.level.intValue() <= level.intValue();
451 
452     if (parent != null)
453       return parent.isLoggable(level);
454     else
455       return false;
456   }
457 
458 
459   /**
460    * Sets the severity level threshold for this <code>Handler</code>.
461    * All log records with a lower severity level will be discarded
462    * immediately.  A log record of the same or a higher level will be
463    * published unless an installed <code>Filter</code> decides to
464    * discard it.
465    *
466    * @param level the severity level below which all log messages
467    *              will be discarded, or <code>null</code> to
468    *              indicate that the logger should inherit the
469    *              threshold from its parent.
470    *
471    * @throws SecurityException if this logger is not anonymous, a
472    *     security manager exists, and the caller is not granted
473    *     the permission to control the logging infrastructure by
474    *     having LoggingPermission("control").  Untrusted code can
475    *     obtain an anonymous logger through the static factory method
476    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
477    */
setLevel(Level level)478   public synchronized void setLevel(Level level)
479   {
480     /* An application is allowed to control an anonymous logger
481      * without having the permission to control the logging
482      * infrastructure.
483      */
484     if (!anonymous)
485       LogManager.getLogManager().checkAccess();
486 
487     this.level = level;
488   }
489 
490 
getFilter()491   public synchronized Filter getFilter()
492   {
493     return filter;
494   }
495 
496 
497   /**
498    * @throws SecurityException if this logger is not anonymous, a
499    *     security manager exists, and the caller is not granted
500    *     the permission to control the logging infrastructure by
501    *     having LoggingPermission("control").  Untrusted code can
502    *     obtain an anonymous logger through the static factory method
503    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
504    */
setFilter(Filter filter)505   public synchronized void setFilter(Filter filter)
506     throws SecurityException
507   {
508     /* An application is allowed to control an anonymous logger
509      * without having the permission to control the logging
510      * infrastructure.
511      */
512     if (!anonymous)
513       LogManager.getLogManager().checkAccess();
514 
515     this.filter = filter;
516   }
517 
518 
519 
520 
521   /**
522    * Returns the name of this logger.
523    *
524    * @return the name of this logger, or <code>null</code> if
525    *         the logger is anonymous.
526    */
getName()527   public String getName()
528   {
529     /* Note that the name of a logger cannot be changed during
530      * its lifetime, so no synchronization is needed.
531      */
532     return name;
533   }
534 
535 
536   /**
537    * Passes a record to registered handlers, provided the record
538    * is considered as loggable both by {@link #isLoggable(Level)}
539    * and a possibly installed custom {@link #setFilter(Filter) filter}.
540    *
541    * <p>If the logger has been configured to use parent handlers,
542    * the record will be forwarded to the parent of this logger
543    * in addition to being processed by the handlers registered with
544    * this logger.
545    *
546    * <p>The other logging methods in this class are convenience methods
547    * that merely create a new LogRecord and pass it to this method.
548    * Therefore, subclasses usually just need to override this single
549    * method for customizing the logging behavior.
550    *
551    * @param record the log record to be inspected and possibly forwarded.
552    */
log(LogRecord record)553   public synchronized void log(LogRecord record)
554   {
555     if (!isLoggable(record.getLevel()))
556       return;
557 
558     if ((filter != null) && !filter.isLoggable(record))
559       return;
560 
561     /* If no logger name has been set for the log record,
562      * use the name of this logger.
563      */
564     if (record.getLoggerName() == null)
565       record.setLoggerName(name);
566 
567     /* Avoid that some other thread is changing the logger hierarchy
568      * while we are traversing it.
569      */
570     synchronized (LogManager.getLogManager())
571     {
572       Logger curLogger = this;
573 
574       do
575       {
576         /* The Sun J2SE 1.4 reference implementation seems to call the
577 	 * filter only for the logger whose log method is called,
578 	 * never for any of its parents.  Also, parent loggers publish
579 	 * log record whatever their level might be.  This is pretty
580 	 * weird, but GNU Classpath tries to be as compatible as
581 	 * possible to the reference implementation.
582 	 */
583         for (int i = 0; i < curLogger.handlers.length; i++)
584           curLogger.handlers[i].publish(record);
585 
586 	if (curLogger.getUseParentHandlers() == false)
587 	  break;
588 
589 	curLogger = curLogger.getParent();
590       }
591       while (parent != null);
592     }
593   }
594 
595 
log(Level level, String message)596   public void log(Level level, String message)
597   {
598     if (isLoggable(level))
599       log(level, message, (Object[]) null);
600   }
601 
602 
log(Level level, String message, Object param)603   public synchronized void log(Level level,
604 			       String message,
605 			       Object param)
606   {
607     if (isLoggable(level))
608       {
609         StackTraceElement caller = getCallerStackFrame();
610         logp(level,
611              caller != null ? caller.getClassName() : "<unknown>",
612              caller != null ? caller.getMethodName() : "<unknown>",
613              message,
614              param);
615       }
616   }
617 
618 
log(Level level, String message, Object[] params)619   public synchronized void log(Level level,
620 			       String message,
621 			       Object[] params)
622   {
623     if (isLoggable(level))
624       {
625         StackTraceElement caller = getCallerStackFrame();
626         logp(level,
627              caller != null ? caller.getClassName() : "<unknown>",
628              caller != null ? caller.getMethodName() : "<unknown>",
629              message,
630              params);
631       }
632   }
633 
634 
log(Level level, String message, Throwable thrown)635   public synchronized void log(Level level,
636 			       String message,
637 			       Throwable thrown)
638   {
639     if (isLoggable(level))
640       {
641         StackTraceElement caller = getCallerStackFrame();
642         logp(level,
643              caller != null ? caller.getClassName() : "<unknown>",
644              caller != null ? caller.getMethodName() : "<unknown>",
645              message,
646              thrown);
647       }
648   }
649 
650 
logp(Level level, String sourceClass, String sourceMethod, String message)651   public synchronized void logp(Level level,
652 				String sourceClass,
653 				String sourceMethod,
654 				String message)
655   {
656     logp(level, sourceClass, sourceMethod, message,
657 	 (Object[]) null);
658   }
659 
660 
logp(Level level, String sourceClass, String sourceMethod, String message, Object param)661   public synchronized void logp(Level level,
662 				String sourceClass,
663 				String sourceMethod,
664 				String message,
665 				Object param)
666   {
667     logp(level, sourceClass, sourceMethod, message,
668 	 new Object[] { param });
669   }
670 
671 
findResourceBundle()672   private synchronized ResourceBundle findResourceBundle()
673   {
674     if (resourceBundle != null)
675       return resourceBundle;
676 
677     if (parent != null)
678       return parent.findResourceBundle();
679 
680     return null;
681   }
682 
683 
logImpl(Level level, String sourceClass, String sourceMethod, String message, Object[] params)684   private synchronized void logImpl(Level level,
685 				    String sourceClass,
686 				    String sourceMethod,
687 				    String message,
688 				    Object[] params)
689   {
690     LogRecord rec = new LogRecord(level, message);
691 
692     rec.setResourceBundle(findResourceBundle());
693     rec.setSourceClassName(sourceClass);
694     rec.setSourceMethodName(sourceMethod);
695     rec.setParameters(params);
696 
697     log(rec);
698   }
699 
700 
logp(Level level, String sourceClass, String sourceMethod, String message, Object[] params)701   public synchronized void logp(Level level,
702 				String sourceClass,
703 				String sourceMethod,
704 				String message,
705 				Object[] params)
706   {
707     logImpl(level, sourceClass, sourceMethod, message, params);
708   }
709 
710 
logp(Level level, String sourceClass, String sourceMethod, String message, Throwable thrown)711   public synchronized void logp(Level level,
712 				String sourceClass,
713 				String sourceMethod,
714 				String message,
715 				Throwable thrown)
716   {
717     LogRecord rec = new LogRecord(level, message);
718 
719     rec.setResourceBundle(resourceBundle);
720     rec.setSourceClassName(sourceClass);
721     rec.setSourceMethodName(sourceMethod);
722     rec.setThrown(thrown);
723 
724     log(rec);
725   }
726 
727 
logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String message)728   public synchronized void logrb(Level level,
729 				 String sourceClass,
730 				 String sourceMethod,
731 				 String bundleName,
732 				 String message)
733   {
734     logrb(level, sourceClass, sourceMethod, bundleName,
735 	  message, (Object[]) null);
736   }
737 
738 
logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String message, Object param)739   public synchronized void logrb(Level level,
740 				 String sourceClass,
741 				 String sourceMethod,
742 				 String bundleName,
743 				 String message,
744 				 Object param)
745   {
746     logrb(level, sourceClass, sourceMethod, bundleName,
747 	  message, new Object[] { param });
748   }
749 
750 
logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String message, Object[] params)751   public synchronized void logrb(Level level,
752 				 String sourceClass,
753 				 String sourceMethod,
754 				 String bundleName,
755 				 String message,
756 				 Object[] params)
757   {
758     LogRecord rec = new LogRecord(level, message);
759 
760     rec.setResourceBundleName(bundleName);
761     rec.setSourceClassName(sourceClass);
762     rec.setSourceMethodName(sourceMethod);
763     rec.setParameters(params);
764 
765     log(rec);
766   }
767 
768 
logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String message, Throwable thrown)769   public synchronized void logrb(Level level,
770 				 String sourceClass,
771 				 String sourceMethod,
772 				 String bundleName,
773 				 String message,
774 				 Throwable thrown)
775   {
776     LogRecord rec = new LogRecord(level, message);
777 
778     rec.setResourceBundleName(bundleName);
779     rec.setSourceClassName(sourceClass);
780     rec.setSourceMethodName(sourceMethod);
781     rec.setThrown(thrown);
782 
783     log(rec);
784   }
785 
786 
entering(String sourceClass, String sourceMethod)787   public synchronized void entering(String sourceClass,
788 				    String sourceMethod)
789   {
790     if (isLoggable(Level.FINER))
791       logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
792   }
793 
794 
entering(String sourceClass, String sourceMethod, Object param)795   public synchronized void entering(String sourceClass,
796 				    String sourceMethod,
797 				    Object param)
798   {
799     if (isLoggable(Level.FINER))
800       logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param);
801   }
802 
803 
entering(String sourceClass, String sourceMethod, Object[] params)804   public synchronized void entering(String sourceClass,
805 				    String sourceMethod,
806 				    Object[] params)
807   {
808     if (isLoggable(Level.FINER))
809     {
810       StringBuffer buf = new StringBuffer(80);
811       buf.append("ENTRY");
812       for (int i = 0; i < params.length; i++)
813       {
814 	buf.append(" {");
815 	buf.append(i);
816 	buf.append('}');
817       }
818 
819       logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params);
820     }
821   }
822 
823 
exiting(String sourceClass, String sourceMethod)824   public synchronized void exiting(String sourceClass,
825 				   String sourceMethod)
826   {
827     if (isLoggable(Level.FINER))
828       logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
829   }
830 
831 
exiting(String sourceClass, String sourceMethod, Object result)832   public synchronized void exiting(String sourceClass,
833 				   String sourceMethod,
834 				   Object result)
835   {
836     if (isLoggable(Level.FINER))
837       logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
838   }
839 
840 
throwing(String sourceClass, String sourceMethod, Throwable thrown)841   public synchronized void throwing(String sourceClass,
842 				    String sourceMethod,
843 				    Throwable thrown)
844   {
845     if (isLoggable(Level.FINER))
846       logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown);
847   }
848 
849 
850   /**
851    * Logs a message with severity level SEVERE, indicating a serious
852    * failure that prevents normal program execution.  Messages at this
853    * level should be understandable to an inexperienced, non-technical
854    * end user.  Ideally, they explain in simple words what actions the
855    * user can take in order to resolve the problem.
856    *
857    * @see Level#SEVERE
858    *
859    * @param message the message text, also used as look-up key if the
860    *                logger is localizing messages with a resource
861    *                bundle.  While it is possible to pass
862    *                <code>null</code>, this is not recommended, since
863    *                a logging message without text is unlikely to be
864    *                helpful.
865    */
severe(String message)866   public synchronized void severe(String message)
867   {
868     if (isLoggable(Level.SEVERE))
869       log(Level.SEVERE, message);
870   }
871 
872 
873   /**
874    * Logs a message with severity level WARNING, indicating a
875    * potential problem that does not prevent normal program execution.
876    * Messages at this level should be understandable to an
877    * inexperienced, non-technical end user.  Ideally, they explain in
878    * simple words what actions the user can take in order to resolve
879    * the problem.
880    *
881    * @see Level#WARNING
882    *
883    * @param message the message text, also used as look-up key if the
884    *                logger is localizing messages with a resource
885    *                bundle.  While it is possible to pass
886    *                <code>null</code>, this is not recommended, since
887    *                a logging message without text is unlikely to be
888    *                helpful.
889    */
warning(String message)890   public synchronized void warning(String message)
891   {
892     if (isLoggable(Level.WARNING))
893       log(Level.WARNING, message);
894   }
895 
896 
897   /**
898    * Logs a message with severity level INFO.  {@link Level#INFO} is
899    * intended for purely informational messages that do not indicate
900    * error or warning situations. In the default logging
901    * configuration, INFO messages will be written to the system
902    * console.  For this reason, the INFO level should be used only for
903    * messages that are important to end users and system
904    * administrators.  Messages at this level should be understandable
905    * to an inexperienced, non-technical user.
906    *
907    * @param message the message text, also used as look-up key if the
908    *                logger is localizing messages with a resource
909    *                bundle.  While it is possible to pass
910    *                <code>null</code>, this is not recommended, since
911    *                a logging message without text is unlikely to be
912    *                helpful.
913    */
info(String message)914   public synchronized void info(String message)
915   {
916     if (isLoggable(Level.INFO))
917       log(Level.INFO, message);
918   }
919 
920 
921   /**
922    * Logs a message with severity level CONFIG.  {@link Level#CONFIG} is
923    * intended for static configuration messages, for example about the
924    * windowing environment, the operating system version, etc.
925    *
926    * @param message the message text, also used as look-up key if the
927    *     logger is localizing messages with a resource bundle.  While
928    *     it is possible to pass <code>null</code>, this is not
929    *     recommended, since a logging message without text is unlikely
930    *     to be helpful.
931    */
config(String message)932   public synchronized void config(String message)
933   {
934     if (isLoggable(Level.CONFIG))
935       log(Level.CONFIG, message);
936   }
937 
938 
939   /**
940    * Logs a message with severity level FINE.  {@link Level#FINE} is
941    * intended for messages that are relevant for developers using
942    * the component generating log messages. Examples include minor,
943    * recoverable failures, or possible inefficiencies.
944    *
945    * @param message the message text, also used as look-up key if the
946    *                logger is localizing messages with a resource
947    *                bundle.  While it is possible to pass
948    *                <code>null</code>, this is not recommended, since
949    *                a logging message without text is unlikely to be
950    *                helpful.
951    */
fine(String message)952   public synchronized void fine(String message)
953   {
954     if (isLoggable(Level.FINE))
955       log(Level.FINE, message);
956   }
957 
958 
959   /**
960    * Logs a message with severity level FINER.  {@link Level#FINER} is
961    * intended for rather detailed tracing, for example entering a
962    * method, returning from a method, or throwing an exception.
963    *
964    * @param message the message text, also used as look-up key if the
965    *                logger is localizing messages with a resource
966    *                bundle.  While it is possible to pass
967    *                <code>null</code>, this is not recommended, since
968    *                a logging message without text is unlikely to be
969    *                helpful.
970    */
finer(String message)971   public synchronized void finer(String message)
972   {
973     if (isLoggable(Level.FINER))
974       log(Level.FINER, message);
975   }
976 
977 
978   /**
979    * Logs a message with severity level FINEST.  {@link Level#FINEST}
980    * is intended for highly detailed tracing, for example reaching a
981    * certain point inside the body of a method.
982    *
983    * @param message the message text, also used as look-up key if the
984    *                logger is localizing messages with a resource
985    *                bundle.  While it is possible to pass
986    *                <code>null</code>, this is not recommended, since
987    *                a logging message without text is unlikely to be
988    *                helpful.
989    */
finest(String message)990   public synchronized void finest(String message)
991   {
992     if (isLoggable(Level.FINEST))
993       log(Level.FINEST, message);
994   }
995 
996 
997   /**
998    * Adds a handler to the set of handlers that get notified
999    * when a log record is to be published.
1000    *
1001    * @param handler the handler to be added.
1002    *
1003    * @throws NullPointerException if <code>handler</code>
1004    *     is <code>null</code>.
1005    *
1006    * @throws SecurityException if this logger is not anonymous, a
1007    *     security manager exists, and the caller is not granted
1008    *     the permission to control the logging infrastructure by
1009    *     having LoggingPermission("control").  Untrusted code can
1010    *     obtain an anonymous logger through the static factory method
1011    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1012    */
addHandler(Handler handler)1013   public synchronized void addHandler(Handler handler)
1014     throws SecurityException
1015   {
1016     if (handler == null)
1017       throw new NullPointerException();
1018 
1019     /* An application is allowed to control an anonymous logger
1020      * without having the permission to control the logging
1021      * infrastructure.
1022      */
1023     if (!anonymous)
1024       LogManager.getLogManager().checkAccess();
1025 
1026     if (!handlerList.contains(handler))
1027     {
1028       handlerList.add(handler);
1029       handlers = getHandlers();
1030     }
1031   }
1032 
1033 
1034   /**
1035    * Removes a handler from the set of handlers that get notified
1036    * when a log record is to be published.
1037    *
1038    * @param handler the handler to be removed.
1039    *
1040    * @throws SecurityException if this logger is not anonymous, a
1041    *     security manager exists, and the caller is not granted the
1042    *     permission to control the logging infrastructure by having
1043    *     LoggingPermission("control").  Untrusted code can obtain an
1044    *     anonymous logger through the static factory method {@link
1045    *     #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1046    *
1047    * @throws NullPointerException if <code>handler</code>
1048    *     is <code>null</code>.
1049    */
removeHandler(Handler handler)1050   public synchronized void removeHandler(Handler handler)
1051     throws SecurityException
1052   {
1053     /* An application is allowed to control an anonymous logger
1054      * without having the permission to control the logging
1055      * infrastructure.
1056      */
1057     if (!anonymous)
1058       LogManager.getLogManager().checkAccess();
1059 
1060     if (handler == null)
1061       throw new NullPointerException();
1062 
1063     handlerList.remove(handler);
1064     handlers = getHandlers();
1065   }
1066 
1067 
1068   /**
1069    * Returns the handlers currently registered for this Logger.
1070    * When a log record has been deemed as being loggable,
1071    * it will be passed to all registered handlers for
1072    * publication.  In addition, if the logger uses parent handlers
1073    * (see {@link #getUseParentHandlers() getUseParentHandlers}
1074    * and {@link #setUseParentHandlers(boolean) setUseParentHandlers},
1075    * the log record will be passed to the parent's handlers.
1076    */
getHandlers()1077   public synchronized Handler[] getHandlers()
1078   {
1079     /* We cannot return our internal handlers array
1080      * because we do not have any guarantee that the
1081      * caller would not change the array entries.
1082      */
1083     return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]);
1084   }
1085 
1086 
1087   /**
1088    * Returns whether or not this Logger forwards log records to
1089    * handlers registered for its parent loggers.
1090    *
1091    * @return <code>false</code> if this Logger sends log records
1092    *         merely to Handlers registered with itself;
1093    *         <code>true</code> if this Logger sends log records
1094    *         not only to Handlers registered with itself, but also
1095    *         to those Handlers registered with parent loggers.
1096    */
getUseParentHandlers()1097   public synchronized boolean getUseParentHandlers()
1098   {
1099     return useParentHandlers;
1100   }
1101 
1102 
1103   /**
1104    * Sets whether or not this Logger forwards log records to
1105    * handlers registered for its parent loggers.
1106    *
1107    * @param useParentHandlers <code>false</code> to let this
1108    *         Logger send log records merely to Handlers registered
1109    *         with itself; <code>true</code> to let this Logger
1110    *         send log records not only to Handlers registered
1111    *         with itself, but also to those Handlers registered with
1112    *         parent loggers.
1113    *
1114    * @throws SecurityException if this logger is not anonymous, a
1115    *     security manager exists, and the caller is not granted
1116    *     the permission to control the logging infrastructure by
1117    *     having LoggingPermission("control").  Untrusted code can
1118    *     obtain an anonymous logger through the static factory method
1119    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1120    *
1121    */
setUseParentHandlers(boolean useParentHandlers)1122   public synchronized void setUseParentHandlers(boolean useParentHandlers)
1123   {
1124     /* An application is allowed to control an anonymous logger
1125      * without having the permission to control the logging
1126      * infrastructure.
1127      */
1128     if (!anonymous)
1129       LogManager.getLogManager().checkAccess();
1130 
1131     this.useParentHandlers = useParentHandlers;
1132   }
1133 
1134 
1135   /**
1136    * Returns the parent of this logger.  By default, the parent is
1137    * assigned by the LogManager by inspecting the logger's name.
1138    *
1139    * @return the parent of this logger (as detemined by the LogManager
1140    *     by inspecting logger names), the root logger if no other
1141    *     logger has a name which is a prefix of this logger's name, or
1142    *     <code>null</code> for the root logger.
1143    */
getParent()1144   public synchronized Logger getParent()
1145   {
1146     return parent;
1147   }
1148 
1149 
1150   /**
1151    * Sets the parent of this logger.  Usually, applications do not
1152    * call this method directly.  Instead, the LogManager will ensure
1153    * that the tree of loggers reflects the hierarchical logger
1154    * namespace.  Basically, this method should not be public at all,
1155    * but the GNU implementation follows the API specification.
1156    *
1157    * @throws NullPointerException if <code>parent</code> is
1158    *     <code>null</code>.
1159    *
1160    * @throws SecurityException if this logger is not anonymous, a
1161    *     security manager exists, and the caller is not granted
1162    *     the permission to control the logging infrastructure by
1163    *     having LoggingPermission("control").  Untrusted code can
1164    *     obtain an anonymous logger through the static factory method
1165    *     {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}.
1166    */
setParent(Logger parent)1167   public synchronized void setParent(Logger parent)
1168   {
1169     if (parent == null)
1170       throw new NullPointerException();
1171 
1172     if (this == root)
1173         throw new IllegalArgumentException(
1174           "the root logger can only have a null parent");
1175 
1176     /* An application is allowed to control an anonymous logger
1177      * without having the permission to control the logging
1178      * infrastructure.
1179      */
1180     if (!anonymous)
1181       LogManager.getLogManager().checkAccess();
1182 
1183     this.parent = parent;
1184   }
1185 
1186   /**
1187    * Gets the StackTraceElement of the first class that is not this class.
1188    * That should be the initial caller of a logging method.
1189    * @return caller of the initial logging method or null if unknown.
1190    */
getCallerStackFrame()1191   private native StackTraceElement getCallerStackFrame();
1192 
1193   /**
1194    * Reset and close handlers attached to this logger. This function is package
1195    * private because it must only be avaiable to the LogManager.
1196    */
resetLogger()1197   void resetLogger()
1198   {
1199     for (int i = 0; i < handlers.length; i++)
1200       {
1201         handlers[i].close();
1202         handlerList.remove(handlers[i]);
1203       }
1204     handlers = getHandlers();
1205   }
1206 }
1207