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