KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > logging > LogManager


1 /*
2  * @(#)LogManager.java 1.48 07/01/08
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8
9 package java.util.logging;
10
11 import java.io.*;
12 import java.util.*;
13 import java.security.*;
14 import java.beans.PropertyChangeListener JavaDoc;
15 import java.beans.PropertyChangeSupport JavaDoc;
16 import java.net.URL JavaDoc;
17 import sun.security.action.GetPropertyAction;
18
19 /**
20  * There is a single global LogManager object that is used to
21  * maintain a set of shared state about Loggers and log services.
22  * <p>
23  * This LogManager object:
24  * <ul>
25  * <li> Manages a hierarchical namespace of Logger objects. All
26  * named Loggers are stored in this namespace.
27  * <li> Manages a set of logging control properties. These are
28  * simple key-value pairs that can be used by Handlers and
29  * other logging objects to configure themselves.
30  * </ul>
31  * <p>
32  * The global LogManager object can be retrieved using LogManager.getLogManager().
33  * The LogManager object is created during class initialization and
34  * cannot subsequently be changed.
35  * <p>
36  * At startup the LogManager class is located using the
37  * java.util.logging.manager system property.
38  * <p>
39  * By default, the LogManager reads its initial configuration from
40  * a properties file "lib/logging.properties" in the JRE directory.
41  * If you edit that property file you can change the default logging
42  * configuration for all uses of that JRE.
43  * <p>
44  * In addition, the LogManager uses two optional system properties that
45  * allow more control over reading the initial configuration:
46  * <ul>
47  * <li>"java.util.logging.config.class"
48  * <li>"java.util.logging.config.file"
49  * </ul>
50  * These two properties may be set via the Preferences API, or as
51  * command line property definitions to the "java" command, or as
52  * system property definitions passed to JNI_CreateJavaVM.
53  * <p>
54  * If the "java.util.logging.config.class" property is set, then the
55  * property value is treated as a class name. The given class will be
56  * loaded, an object will be instantiated, and that object's constructor
57  * is responsible for reading in the initial configuration. (That object
58  * may use other system properties to control its configuration.) The
59  * alternate configuration class can use <tt>readConfiguration(InputStream)</tt>
60  * to define properties in the LogManager.
61  * <p>
62  * If "java.util.logging.config.class" property is <b>not</b> set,
63  * then the "java.util.logging.config.file" system property can be used
64  * to specify a properties file (in java.util.Properties format). The
65  * initial logging configuration will be read from this file.
66  * <p>
67  * If neither of these properties is defined then, as described
68  * above, the LogManager will read its initial configuration from
69  * a properties file "lib/logging.properties" in the JRE directory.
70  * <p>
71  * The properties for loggers and Handlers will have names starting
72  * with the dot-separated name for the handler or logger.
73  * <p>
74  * The global logging properties may include:
75  * <ul>
76  * <li>A property "handlers". This defines a whitespace separated
77  * list of class names for handler classes to load and register as
78  * handlers on the root Logger (the Logger named ""). Each class
79  * name must be for a Handler class which has a default constructor.
80  * Note that these Handlers may be created lazily, when they are
81  * first used.
82  *
83  * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
84  * comma separated list of class names for handlers classes to
85  * load and register as handlers to the specified logger. Each class
86  * name must be for a Handler class which has a default constructor.
87  * Note that these Handlers may be created lazily, when they are
88  * first used.
89  *
90  * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
91  * value. By default every logger calls its parent in addition to
92  * handling the logging message itself, this often result in messages
93  * being handled by the root logger as well. When setting this property
94  * to false a Handler needs to be configured for this logger otherwise
95  * no logging messages are delivered.
96  *
97  * <li>A property "config". This property is intended to allow
98  * arbitrary configuration code to be run. The property defines a
99  * whitespace separated list of class names. A new instance will be
100  * created for each named class. The default constructor of each class
101  * may execute arbitrary code to update the logging configuration, such as
102  * setting logger levels, adding handlers, adding filters, etc.
103  * </ul>
104  * <p>
105  * Note that all classes loaded during LogManager configuration are
106  * first searched on the system class path before any user class path.
107  * That includes the LogManager class, any config classes, and any
108  * handler classes.
109  * <p>
110  * Loggers are organized into a naming hierarchy based on their
111  * dot separated names. Thus "a.b.c" is a child of "a.b", but
112  * "a.b1" and a.b2" are peers.
113  * <p>
114  * All properties whose names end with ".level" are assumed to define
115  * log levels for Loggers. Thus "foo.level" defines a log level for
116  * the logger called "foo" and (recursively) for any of its children
117  * in the naming hierarchy. Log Levels are applied in the order they
118  * are defined in the properties file. Thus level settings for child
119  * nodes in the tree should come after settings for their parents.
120  * The property name ".level" can be used to set the level for the
121  * root of the tree.
122  * <p>
123  * All methods on the LogManager object are multi-thread safe.
124  *
125  * @version 1.48, 01/08/07
126  * @since 1.4
127 */

128
129 public class LogManager {
130     // The global LogManager object
131
private static LogManager JavaDoc manager;
132
133     private final static Handler JavaDoc[] emptyHandlers = { };
134     private Properties props = new Properties();
135     private PropertyChangeSupport JavaDoc changes
136              = new PropertyChangeSupport JavaDoc(LogManager JavaDoc.class);
137     private final static Level JavaDoc defaultLevel = Level.INFO;
138
139     // Table of known loggers. Maps names to Loggers.
140
private Hashtable<String JavaDoc,Logger JavaDoc> loggers = new Hashtable<String JavaDoc,Logger JavaDoc>();
141     // Tree of known loggers
142
private LogNode root = new LogNode(null);
143     private Logger JavaDoc rootLogger;
144
145     // Have we done the primordial reading of the configuration file?
146
// (Must be done after a suitable amount of java.lang.System
147
// initialization has been done)
148
private volatile boolean readPrimordialConfiguration;
149     // Have we initialized global (root) handlers yet?
150
// This gets set to false in readConfiguration
151
private boolean initializedGlobalHandlers = true;
152     // True if JVM death is imminent and the exit hook has been called.
153
private boolean deathImminent;
154
155     static {
156     AccessController.doPrivileged(new PrivilegedAction() {
157                 public Object JavaDoc run() {
158                     String JavaDoc cname = null;
159                     try {
160                         cname = System.getProperty("java.util.logging.manager");
161                         if (cname != null) {
162                 try {
163                                 Class JavaDoc clz = ClassLoader.getSystemClassLoader().loadClass(cname);
164                                 manager = (LogManager JavaDoc) clz.newInstance();
165                 } catch (ClassNotFoundException JavaDoc ex) {
166                     Class JavaDoc clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
167                     manager = (LogManager JavaDoc) clz.newInstance();
168                 }
169                         }
170                     } catch (Exception JavaDoc ex) {
171                         System.err.println("Could not load Logmanager \"" + cname + "\"");
172                         ex.printStackTrace();
173                     }
174                     if (manager == null) {
175                         manager = new LogManager JavaDoc();
176                     }
177
178                     // Create and retain Logger for the root of the namespace.
179
manager.rootLogger = manager.new RootLogger();
180                     manager.addLogger(manager.rootLogger);
181
182                     // Adding the global Logger. Doing so in the Logger.<clinit>
183
// would deadlock with the LogManager.<clinit>.
184
Logger.global.setLogManager(manager);
185                     manager.addLogger(Logger.global);
186
187                     // We don't call readConfiguration() here, as we may be running
188
// very early in the JVM startup sequence. Instead readConfiguration
189
// will be called lazily in getLogManager().
190
return null;
191                 }
192             });
193     }
194
195
196     // This private class is used as a shutdown hook.
197
// It does a "reset" to close all open handlers.
198
private class Cleaner extends Thread JavaDoc {
199     public void run() {
200         // This is to ensure the LogManager.<clinit> is completed
201
// before synchronized block. Otherwise deadlocks are possible.
202
LogManager JavaDoc mgr = manager;
203  
204         // If the global handlers haven't been initialized yet, we
205
// don't want to initialize them just so we can close them!
206
synchronized (LogManager.this) {
207         // Note that death is imminent.
208
deathImminent = true;
209         initializedGlobalHandlers = true;
210         }
211
212         // Do a reset to close all active handlers.
213
reset();
214     }
215     }
216
217
218     /**
219      * Protected constructor. This is protected so that container applications
220      * (such as J2EE containers) can subclass the object. It is non-public as
221      * it is intended that there only be one LogManager object, whose value is
222      * retrieved by calling Logmanager.getLogManager.
223      */

224     protected LogManager() {
225     // Add a shutdown hook to close the global handlers.
226
try {
227         Runtime.getRuntime().addShutdownHook(new Cleaner());
228         } catch (IllegalStateException JavaDoc e) {
229             // If the VM is already shutting down,
230
// We do not need to register shutdownHook.
231
}
232     }
233
234     /**
235      * Return the global LogManager object.
236      */

237     public static LogManager JavaDoc getLogManager() {
238         if (manager != null) {
239             manager.readPrimordialConfiguration();
240         }
241     return manager;
242     }
243
244     private void readPrimordialConfiguration() {
245         if (!readPrimordialConfiguration) {
246             synchronized (this) {
247                 if (!readPrimordialConfiguration) {
248                     // If System.in/out/err are null, it's a good
249
// indication that we're still in the
250
// bootstrapping phase
251
if (System.out == null) {
252                         return;
253                     }
254                     readPrimordialConfiguration = true;
255                     try {
256                         AccessController.doPrivileged(new PrivilegedExceptionAction() {
257                                 public Object JavaDoc run() throws Exception JavaDoc {
258                                     readConfiguration();
259                                     return null;
260                                 }
261                             });
262                     } catch (Exception JavaDoc ex) {
263                         // System.err.println("Can't read logging configuration:");
264
// ex.printStackTrace();
265
}
266                 }
267             }
268         }
269     }
270
271     /**
272      * Adds an event listener to be invoked when the logging
273      * properties are re-read. Adding multiple instances of
274      * the same event Listener results in multiple entries
275      * in the property event listener table.
276      *
277      * @param l event listener
278      * @exception SecurityException if a security manager exists and if
279      * the caller does not have LoggingPermission("control").
280      * @exception NullPointerException if the PropertyChangeListener is null.
281      */

282     public void addPropertyChangeListener(PropertyChangeListener JavaDoc l) throws SecurityException JavaDoc {
283     if (l == null) {
284         throw new NullPointerException JavaDoc();
285     }
286     checkAccess();
287     changes.addPropertyChangeListener(l);
288     }
289
290     /**
291      * Removes an event listener for property change events.
292      * If the same listener instance has been added to the listener table
293      * through multiple invocations of <CODE>addPropertyChangeListener</CODE>,
294      * then an equivalent number of
295      * <CODE>removePropertyChangeListener</CODE> invocations are required to remove
296      * all instances of that listener from the listener table.
297      * <P>
298      * Returns silently if the given listener is not found.
299      *
300      * @param l event listener (can be null)
301      * @exception SecurityException if a security manager exists and if
302      * the caller does not have LoggingPermission("control").
303      */

304     public void removePropertyChangeListener(PropertyChangeListener JavaDoc l) throws SecurityException JavaDoc {
305     checkAccess();
306     changes.removePropertyChangeListener(l);
307     }
308
309     /**
310      * Add a named logger. This does nothing and returns false if a logger
311      * with the same name is already registered.
312      * <p>
313      * The Logger factory methods call this method to register each
314      * newly created Logger.
315      * <p>
316      * The application should retain its own reference to the Logger
317      * object to avoid it being garbage collected. The LogManager
318      * may only retain a weak reference.
319      *
320      * @param logger the new logger.
321      * @return true if the argument logger was registered successfully,
322      * false if a logger of that name already exists.
323      * @exception NullPointerException if the logger name is null.
324      */

325     public synchronized boolean addLogger(Logger JavaDoc logger) {
326     final String JavaDoc name = logger.getName();
327     if (name == null) {
328         throw new NullPointerException JavaDoc();
329     }
330
331     Logger JavaDoc old = loggers.get(name);
332     if (old != null) {
333         // We already have a registered logger with the given name.
334
return false;
335     }
336
337     // We're adding a new logger.
338
// Note that we are creating a strong reference here that will
339
// keep the Logger in existence indefinitely.
340
loggers.put(name, logger);
341
342     // Apply any initial level defined for the new logger.
343
Level JavaDoc level = getLevelProperty(name+".level", null);
344     if (level != null) {
345         doSetLevel(logger, level);
346     }
347
348         // Do we have a per logger handler too?
349
// Note: this will add a 200ms penalty
350
if (getProperty(name+".handlers") != null) {
351            // This code is taken from the root handler initialization
352
AccessController.doPrivileged(new PrivilegedAction() {
353               public Object JavaDoc run() {
354                 // Add new per logger handlers.
355
String JavaDoc names[] = parseClassNames(name+".handlers");
356                 for (int i = 0; i < names.length; i++) {
357                     String JavaDoc word = names[i];
358                     try {
359                         Class JavaDoc clz = ClassLoader.getSystemClassLoader().loadClass(word);
360                         Handler JavaDoc h = (Handler JavaDoc) clz.newInstance();
361                         try {
362                             // Check if there is a property defining the
363
// this handler's level.
364
String JavaDoc levs = getProperty(word + ".level");
365                             if (levs != null) {
366                                 h.setLevel(Level.parse(levs));
367                             }
368                             boolean useParent = getBooleanProperty(name + ".useParentHandlers", true);
369                             if (!useParent) {
370                                 getLogger(name).setUseParentHandlers(false);
371                             }
372                         } catch (Exception JavaDoc ex) {
373                             System.err.println("Can't set level for " + word);
374                             // Probably a bad level. Drop through.
375
}
376                         // Add this Handler to the logger
377
getLogger(name).addHandler(h);
378                     } catch (Exception JavaDoc ex) {
379                         System.err.println("Can't load log handler \"" + word + "\"");
380                         System.err.println("" + ex);
381                         ex.printStackTrace();
382                     }
383                 }
384                 return null;
385             }});
386         } // do we have per logger handlers
387

388     // If any of the logger's parents have levels defined,
389
// make sure they are instantiated.
390
int ix = 1;
391     for (;;) {
392         int ix2 = name.indexOf(".", ix);
393         if (ix2 < 0) {
394         break;
395         }
396         String JavaDoc pname = name.substring(0,ix2);
397         if (getProperty(pname+".level") != null) {
398         // This pname has a level definition. Make sure it exists.
399
Logger JavaDoc plogger = Logger.getLogger(pname);
400         }
401             // While we are walking up the tree I can check for our
402
// own root logger and get its handlers initialized too with
403
// the same code
404
if (getProperty(pname+".handlers") != null) {
405                final String JavaDoc nname=pname;
406                                                                                 
407                AccessController.doPrivileged(new PrivilegedAction() {
408                    public Object JavaDoc run() {
409                    String JavaDoc names[] = parseClassNames(nname+".handlers");
410                                                                                 
411                    for (int i = 0; i < names.length; i++) {
412                        String JavaDoc word = names[i];
413                        try {
414                            Class JavaDoc clz = ClassLoader.getSystemClassLoader().loadClass(word);
415                            Handler JavaDoc h = (Handler JavaDoc) clz.newInstance();
416                            try {
417                               // Check if there is a property defining the
418
// handler's level.
419
String JavaDoc levs = getProperty(word + ".level");
420                               if (levs != null) {
421                                   h.setLevel(Level.parse(levs));
422                               }
423                            } catch (Exception JavaDoc ex) {
424                                 System.err.println("Can't set level for " + word);
425                             // Probably a bad level. Drop through.
426
}
427                            if (getLogger(nname) == null ) {
428                                Logger JavaDoc nplogger=Logger.getLogger(nname);
429                                addLogger(nplogger);
430                            }
431                            boolean useParent = getBooleanProperty(nname + ".useParentHandlers", true);
432                            if (!useParent) {
433                                getLogger(nname).setUseParentHandlers(false);
434                            }
435                        } catch (Exception JavaDoc ex) {
436                           System.err.println("Can't load log handler \"" + word + "\"");
437                           System.err.println("" + ex);
438                           ex.printStackTrace();
439                        }
440                    }
441                    return null;
442                    }});
443             } //found a parent handler
444

445         ix = ix2+1;
446     }
447
448     // Find the new node and its parent.
449
LogNode node = findNode(name);
450     node.logger = logger;
451     Logger JavaDoc parent = null;
452     LogNode nodep = node.parent;
453     while (nodep != null) {
454         if (nodep.logger != null) {
455         parent = nodep.logger;
456         break;
457         }
458         nodep = nodep.parent;
459     }
460
461     if (parent != null) {
462             doSetParent(logger, parent);
463     }
464     // Walk over the children and tell them we are their new parent.
465
node.walkAndSetParent(logger);
466
467     return true;
468     }
469
470
471     // Private method to set a level on a logger.
472
// If necessary, we raise privilege before doing the call.
473
private static void doSetLevel(final Logger JavaDoc logger, final Level JavaDoc level) {
474     SecurityManager JavaDoc sm = System.getSecurityManager();
475     if (sm == null) {
476         // There is no security manager, so things are easy.
477
logger.setLevel(level);
478         return;
479     }
480     // There is a security manager. Raise privilege before
481
// calling setLevel.
482
AccessController.doPrivileged(new PrivilegedAction() {
483         public Object JavaDoc run() {
484             logger.setLevel(level);
485         return null;
486         }});
487     }
488
489
490
491     // Private method to set a parent on a logger.
492
// If necessary, we raise privilege before doing the setParent call.
493
private static void doSetParent(final Logger JavaDoc logger, final Logger JavaDoc parent) {
494     SecurityManager JavaDoc sm = System.getSecurityManager();
495     if (sm == null) {
496         // There is no security manager, so things are easy.
497
logger.setParent(parent);
498         return;
499     }
500     // There is a security manager. Raise privilege before
501
// calling setParent.
502
AccessController.doPrivileged(new PrivilegedAction() {
503         public Object JavaDoc run() {
504         logger.setParent(parent);
505         return null;
506         }});
507     }
508
509     // Find a node in our tree of logger nodes.
510
// If necessary, create it.
511
private LogNode findNode(String JavaDoc name) {
512     if (name == null || name.equals("")) {
513         return root;
514     }
515     LogNode node = root;
516     while (name.length() > 0) {
517         int ix = name.indexOf(".");
518         String JavaDoc head;
519         if (ix > 0) {
520         head = name.substring(0,ix);
521         name = name.substring(ix+1);
522         } else {
523         head = name;
524         name = "";
525         }
526         if (node.children == null) {
527         node.children = new HashMap<Object JavaDoc,Object JavaDoc>();
528         }
529         LogNode child = (LogNode)node.children.get(head);
530         if (child == null) {
531         child = new LogNode(node);
532         node.children.put(head, child);
533         }
534         node = child;
535     }
536     return node;
537     }
538
539     /**
540      * Method to find a named logger.
541      * <p>
542      * Note that since untrusted code may create loggers with
543      * arbitrary names this method should not be relied on to
544      * find Loggers for security sensitive logging.
545      * <p>
546      * @param name name of the logger
547      * @return matching logger or null if none is found
548      */

549     public synchronized Logger JavaDoc getLogger(String JavaDoc name) {
550     return loggers.get(name);
551     }
552
553     /**
554      * Get an enumeration of known logger names.
555      * <p>
556      * Note: Loggers may be added dynamically as new classes are loaded.
557      * This method only reports on the loggers that are currently registered.
558      * <p>
559      * @return enumeration of logger name strings
560      */

561     public synchronized Enumeration<String JavaDoc> getLoggerNames() {
562     return loggers.keys();
563     }
564
565     /**
566      * Reinitialize the logging properties and reread the logging configuration.
567      * <p>
568      * The same rules are used for locating the configuration properties
569      * as are used at startup. So normally the logging properties will
570      * be re-read from the same file that was used at startup.
571      * <P>
572      * Any log level definitions in the new configuration file will be
573      * applied using Logger.setLevel(), if the target Logger exists.
574      * <p>
575      * A PropertyChangeEvent will be fired after the properties are read.
576      *
577      * @exception SecurityException if a security manager exists and if
578      * the caller does not have LoggingPermission("control").
579      * @exception IOException if there are IO problems reading the configuration.
580      */

581     public void readConfiguration() throws IOException, SecurityException JavaDoc {
582     checkAccess();
583
584     // if a configuration class is specified, load it and use it.
585
String JavaDoc cname = System.getProperty("java.util.logging.config.class");
586     if (cname != null) {
587         try {
588         // Instantiate the named class. It is its contructor's
589
// responsibility to initialize the logging configuration, by
590
// calling readConfiguration(InputStream) with a suitable stream.
591
try {
592             Class JavaDoc clz = ClassLoader.getSystemClassLoader().loadClass(cname);
593             clz.newInstance();
594             return;
595         } catch (ClassNotFoundException JavaDoc ex) {
596             Class JavaDoc clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
597             clz.newInstance();
598             return;
599         }
600         } catch (Exception JavaDoc ex) {
601             System.err.println("Logging configuration class \"" + cname + "\" failed");
602             System.err.println("" + ex);
603             // keep going and useful config file.
604
}
605     }
606
607     String JavaDoc fname = System.getProperty("java.util.logging.config.file");
608     if (fname == null) {
609         fname = System.getProperty("java.home");
610         if (fname == null) {
611         throw new Error JavaDoc("Can't find java.home ??");
612         }
613         File f = new File(fname, "lib");
614         f = new File(f, "logging.properties");
615         fname = f.getCanonicalPath();
616     }
617     InputStream in = new FileInputStream(fname);
618     BufferedInputStream bin = new BufferedInputStream(in);
619     try {
620         readConfiguration(bin);
621     } finally {
622         if (in != null) {
623             in.close();
624         }
625     }
626     }
627
628     /**
629      * Reset the logging configuration.
630      * <p>
631      * For all named loggers, the reset operation removes and closes
632      * all Handlers and (except for the root logger) sets the level
633      * to null. The root logger's level is set to Level.INFO.
634      *
635      * @exception SecurityException if a security manager exists and if
636      * the caller does not have LoggingPermission("control").
637      */

638
639     public void reset() throws SecurityException JavaDoc {
640     checkAccess();
641     synchronized (this) {
642         props = new Properties();
643         // Since we are doing a reset we no longer want to initialize
644
// the global handlers, if they haven't been initialized yet.
645
initializedGlobalHandlers = true;
646     }
647     Enumeration enum_ = getLoggerNames();
648     while (enum_.hasMoreElements()) {
649         String JavaDoc name = (String JavaDoc)enum_.nextElement();
650         resetLogger(name);
651     }
652     }
653
654
655     // Private method to reset an individual target logger.
656
private void resetLogger(String JavaDoc name) {
657     Logger JavaDoc logger = getLogger(name);
658     if (logger == null) {
659         return;
660     }
661     // Close all the Logger's handlers.
662
Handler JavaDoc[] targets = logger.getHandlers();
663     for (int i = 0; i < targets.length; i++) {
664         Handler JavaDoc h = targets[i];
665         logger.removeHandler(h);
666         try {
667             h.close();
668         } catch (Exception JavaDoc ex) {
669         // Problems closing a handler? Keep going...
670
}
671     }
672     if (name != null && name.equals("")) {
673         // This is the root logger.
674
logger.setLevel(defaultLevel);
675     } else {
676         logger.setLevel(null);
677     }
678     }
679
680     // get a list of whitespace separated classnames from a property.
681
private String JavaDoc[] parseClassNames(String JavaDoc propertyName) {
682     String JavaDoc hands = getProperty(propertyName);
683     if (hands == null) {
684         return new String JavaDoc[0];
685     }
686     hands = hands.trim();
687     int ix = 0;
688     Vector<String JavaDoc> result = new Vector<String JavaDoc>();
689     while (ix < hands.length()) {
690         int end = ix;
691         while (end < hands.length()) {
692         if (Character.isWhitespace(hands.charAt(end))) {
693             break;
694         }
695         if (hands.charAt(end) == ',') {
696             break;
697         }
698         end++;
699         }
700         String JavaDoc word = hands.substring(ix, end);
701         ix = end+1;
702         word = word.trim();
703         if (word.length() == 0) {
704         continue;
705         }
706         result.add(word);
707     }
708     return result.toArray(new String JavaDoc[result.size()]);
709     }
710
711     /**
712      * Reinitialize the logging properties and reread the logging configuration
713      * from the given stream, which should be in java.util.Properties format.
714      * A PropertyChangeEvent will be fired after the properties are read.
715      * <p>
716      * Any log level definitions in the new configuration file will be
717      * applied using Logger.setLevel(), if the target Logger exists.
718      *
719      * @param ins stream to read properties from
720      * @exception SecurityException if a security manager exists and if
721      * the caller does not have LoggingPermission("control").
722      * @exception IOException if there are problems reading from the stream.
723      */

724     public void readConfiguration(InputStream ins) throws IOException, SecurityException JavaDoc {
725     checkAccess();
726     reset();
727
728     // Load the properties
729
props.load(ins);
730     // Instantiate new configuration objects.
731
String JavaDoc names[] = parseClassNames("config");
732
733     for (int i = 0; i < names.length; i++) {
734         String JavaDoc word = names[i];
735         try {
736         Class JavaDoc clz = ClassLoader.getSystemClassLoader().loadClass(word);
737         clz.newInstance();
738         } catch (Exception JavaDoc ex) {
739         System.err.println("Can't load config class \"" + word + "\"");
740         System.err.println("" + ex);
741         // ex.printStackTrace();
742
}
743     }
744
745     // Set levels on any pre-existing loggers, based on the new properties.
746
setLevelsOnExistingLoggers();
747
748     // Notify any interested parties that our properties have changed.
749
changes.firePropertyChange(null, null, null);
750
751     // Note that we need to reinitialize global handles when
752
// they are first referenced.
753
synchronized (this) {
754         initializedGlobalHandlers = false;
755     }
756     }
757
758     /**
759      * Get the value of a logging property.
760      * The method returns null if the property is not found.
761      * @param name property name
762      * @return property value
763      */

764     public String JavaDoc getProperty(String JavaDoc name) {
765     return props.getProperty(name);
766     }
767
768     // Package private method to get a String property.
769
// If the property is not defined we return the given
770
// default value.
771
String JavaDoc getStringProperty(String JavaDoc name, String JavaDoc defaultValue) {
772     String JavaDoc val = getProperty(name);
773     if (val == null) {
774         return defaultValue;
775     }
776     return val.trim();
777     }
778
779     // Package private method to get an integer property.
780
// If the property is not defined or cannot be parsed
781
// we return the given default value.
782
int getIntProperty(String JavaDoc name, int defaultValue) {
783     String JavaDoc val = getProperty(name);
784     if (val == null) {
785         return defaultValue;
786     }
787     try {
788         return Integer.parseInt(val.trim());
789     } catch (Exception JavaDoc ex) {
790         return defaultValue;
791     }
792     }
793
794     // Package private method to get a boolean property.
795
// If the property is not defined or cannot be parsed
796
// we return the given default value.
797
boolean getBooleanProperty(String JavaDoc name, boolean defaultValue) {
798     String JavaDoc val = getProperty(name);
799     if (val == null) {
800         return defaultValue;
801     }
802     val = val.toLowerCase();
803     if (val.equals("true") || val.equals("1")) {
804         return true;
805     } else if (val.equals("false") || val.equals("0")) {
806         return false;
807     }
808         return defaultValue;
809     }
810
811     // Package private method to get a Level property.
812
// If the property is not defined or cannot be parsed
813
// we return the given default value.
814
Level JavaDoc getLevelProperty(String JavaDoc name, Level JavaDoc defaultValue) {
815     String JavaDoc val = getProperty(name);
816     if (val == null) {
817         return defaultValue;
818     }
819     try {
820         return Level.parse(val.trim());
821     } catch (Exception JavaDoc ex) {
822         return defaultValue;
823     }
824     }
825
826     // Package private method to get a filter property.
827
// We return an instance of the class named by the "name"
828
// property. If the property is not defined or has problems
829
// we return the defaultValue.
830
Filter JavaDoc getFilterProperty(String JavaDoc name, Filter JavaDoc defaultValue) {
831     String JavaDoc val = getProperty(name);
832     try {
833         if (val != null) {
834         Class JavaDoc clz = ClassLoader.getSystemClassLoader().loadClass(val);
835             return (Filter JavaDoc) clz.newInstance();
836         }
837     } catch (Exception JavaDoc ex) {
838         // We got one of a variety of exceptions in creating the
839
// class or creating an instance.
840
// Drop through.
841
}
842     // We got an exception. Return the defaultValue.
843
return defaultValue;
844     }
845
846
847     // Package private method to get a formatter property.
848
// We return an instance of the class named by the "name"
849
// property. If the property is not defined or has problems
850
// we return the defaultValue.
851
Formatter JavaDoc getFormatterProperty(String JavaDoc name, Formatter JavaDoc defaultValue) {
852     String JavaDoc val = getProperty(name);
853     try {
854         if (val != null) {
855         Class JavaDoc clz = ClassLoader.getSystemClassLoader().loadClass(val);
856             return (Formatter JavaDoc) clz.newInstance();
857         }
858     } catch (Exception JavaDoc ex) {
859         // We got one of a variety of exceptions in creating the
860
// class or creating an instance.
861
// Drop through.
862
}
863     // We got an exception. Return the defaultValue.
864
return defaultValue;
865     }
866
867     // Private method to load the global handlers.
868
// We do the real work lazily, when the global handlers
869
// are first used.
870
private synchronized void initializeGlobalHandlers() {
871     if (initializedGlobalHandlers) {
872         return;
873     }
874
875     initializedGlobalHandlers = true;
876
877     if (deathImminent) {
878         // Aaargh...
879
// The VM is shutting down and our exit hook has been called.
880
// Avoid allocating global handlers.
881
return;
882     }
883
884         // We need to raise privilege here. All our decisions will
885
// be made based on the logging configuration, which can
886
// only be modified by trusted code.
887
AccessController.doPrivileged(new PrivilegedAction() {
888         public Object JavaDoc run() {
889         // Add new global handlers.
890
String JavaDoc names[] = parseClassNames("handlers");
891         for (int i = 0; i < names.length; i++) {
892                 String JavaDoc word = names[i];
893                 try {
894                 Class JavaDoc clz = ClassLoader.getSystemClassLoader().loadClass(word);
895                 Handler JavaDoc h = (Handler JavaDoc) clz.newInstance();
896             try {
897                     // Check if there is a property defining the
898
// handler's level.
899
String JavaDoc levs = getProperty(word + ".level");
900                     if (levs != null) {
901                 h.setLevel(Level.parse(levs));
902                     }
903             } catch (Exception JavaDoc ex) {
904                 System.err.println("Can't set level for " + word);
905                     // Probably a bad level. Drop through.
906
}
907             rootLogger.addHandler(h);
908                 } catch (Exception JavaDoc ex) {
909             System.err.println("Can't load log handler \"" + word + "\"");
910             System.err.println("" + ex);
911             ex.printStackTrace();
912             }
913         }
914         return null;
915         }});
916     }
917
918
919     private Permission ourPermission = new LoggingPermission JavaDoc("control", null);
920
921     /**
922      * Check that the current context is trusted to modify the logging
923      * configuration. This requires LoggingPermission("control").
924      * <p>
925      * If the check fails we throw a SecurityException, otherwise
926      * we return normally.
927      *
928      * @exception SecurityException if a security manager exists and if
929      * the caller does not have LoggingPermission("control").
930      */

931     public void checkAccess() throws SecurityException JavaDoc {
932     SecurityManager JavaDoc sm = System.getSecurityManager();
933     if (sm == null) {
934         return;
935     }
936         sm.checkPermission(ourPermission);
937     }
938
939     // Nested class to represent a node in our tree of named loggers.
940
private static class LogNode {
941     HashMap<Object JavaDoc,Object JavaDoc> children;
942     Logger JavaDoc logger;
943     LogNode parent;
944
945     LogNode(LogNode parent) {
946         this.parent = parent;
947     }
948
949     // Recursive method to walk the tree below a node and set
950
// a new parent logger.
951
void walkAndSetParent(Logger JavaDoc parent) {
952         if (children == null) {
953             return;
954         }
955         Iterator values = children.values().iterator();
956         while (values.hasNext()) {
957             LogNode node = (LogNode) values.next();
958             if (node.logger == null) {
959                 node.walkAndSetParent(parent);
960             } else {
961                 doSetParent(node.logger, parent);
962         }
963         }
964     }
965     }
966
967     // We use a subclass of Logger for the root logger, so
968
// that we only instantiate the global handlers when they
969
// are first needed.
970
private class RootLogger extends Logger JavaDoc {
971
972     private RootLogger() {
973         super("", null);
974         setLevel(defaultLevel);
975     }
976
977         public void log(LogRecord JavaDoc record) {
978         // Make sure that the global handlers have been instantiated.
979
initializeGlobalHandlers();
980         super.log(record);
981     }
982
983     public void addHandler(Handler JavaDoc h) {
984         initializeGlobalHandlers();
985         super.addHandler(h);
986     }
987
988     public void removeHandler(Handler JavaDoc h) {
989         initializeGlobalHandlers();
990         super.removeHandler(h);
991     }
992
993     public Handler JavaDoc[] getHandlers() {
994         initializeGlobalHandlers();
995         return super.getHandlers();
996     }
997     }
998
999
1000    // Private method to be called when the configuration has
1001
// changed to apply any level settings to any pre-existing loggers.
1002
synchronized private void setLevelsOnExistingLoggers() {
1003    Enumeration enum_ = props.propertyNames();
1004    while (enum_.hasMoreElements()) {
1005        String JavaDoc key = (String JavaDoc)enum_.nextElement();
1006        if (!key.endsWith(".level")) {
1007        // Not a level definition.
1008
continue;
1009        }
1010        int ix = key.length() - 6;
1011        String JavaDoc name = key.substring(0, ix);
1012        Level JavaDoc level = getLevelProperty(key, null);
1013        if (level == null) {
1014        System.err.println("Bad level value for property: " + key);
1015        continue;
1016        }
1017        Logger JavaDoc l = getLogger(name);
1018        if (l == null) {
1019        continue;
1020        }
1021        l.setLevel(level);
1022    }
1023    }
1024
1025    // Management Support
1026
private static LoggingMXBean JavaDoc loggingMXBean = null;
1027    /**
1028     * String representation of the
1029     * {@link javax.management.ObjectName} for {@link LoggingMXBean}.
1030     */

1031    public final static String JavaDoc LOGGING_MXBEAN_NAME
1032        = "java.util.logging:type=Logging";
1033
1034    /**
1035     * Returns <tt>LoggingMXBean</tt> for managing loggers.
1036     * The <tt>LoggingMXBean</tt> can also obtained from the
1037     * {@link java.lang.management.ManagementFactory#getPlatformMBeanServer
1038     * platform <tt>MBeanServer</tt>} method.
1039     *
1040     * @return a {@link LoggingMXBean} object.
1041     *
1042     * @see java.lang.management.ManagementFactory
1043     */

1044    public static synchronized LoggingMXBean JavaDoc getLoggingMXBean() {
1045        if (loggingMXBean == null) {
1046            loggingMXBean = new Logging JavaDoc();
1047        }
1048        return loggingMXBean;
1049    }
1050
1051}
1052
Popular Tags