1 /*
   2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package java.util.logging;
  28 
  29 import java.io.*;
  30 import java.util.*;
  31 import java.security.*;
  32 import java.lang.ref.ReferenceQueue;
  33 import java.lang.ref.WeakReference;
  34 import sun.misc.JavaAWTAccess;
  35 import sun.misc.SharedSecrets;
  36 
  37 /**
  38  * There is a single global LogManager object that is used to
  39  * maintain a set of shared state about Loggers and log services.
  40  * <p>
  41  * This LogManager object:
  42  * <ul>
  43  * <li> Manages a hierarchical namespace of Logger objects.  All
  44  *      named Loggers are stored in this namespace.
  45  * <li> Manages a set of logging control properties.  These are
  46  *      simple key-value pairs that can be used by Handlers and
  47  *      other logging objects to configure themselves.
  48  * </ul>
  49  * <p>
  50  * The global LogManager object can be retrieved using LogManager.getLogManager().
  51  * The LogManager object is created during class initialization and
  52  * cannot subsequently be changed.
  53  * <p>
  54  * At startup the LogManager class is located using the
  55  * java.util.logging.manager system property.
  56  * <p>
  57  * The LogManager defines two optional system properties that allow control over
  58  * the initial configuration:
  59  * <ul>
  60  * <li>"java.util.logging.config.class"
  61  * <li>"java.util.logging.config.file"
  62  * </ul>
  63  * These two properties may be specified on the command line to the "java"
  64  * command, or as system property definitions passed to JNI_CreateJavaVM.
  65  * <p>
  66  * If the "java.util.logging.config.class" property is set, then the
  67  * property value is treated as a class name.  The given class will be
  68  * loaded, an object will be instantiated, and that object's constructor
  69  * is responsible for reading in the initial configuration.  (That object
  70  * may use other system properties to control its configuration.)  The
  71  * alternate configuration class can use <tt>readConfiguration(InputStream)</tt>
  72  * to define properties in the LogManager.
  73  * <p>
  74  * If "java.util.logging.config.class" property is <b>not</b> set,
  75  * then the "java.util.logging.config.file" system property can be used
  76  * to specify a properties file (in java.util.Properties format). The
  77  * initial logging configuration will be read from this file.
  78  * <p>
  79  * If neither of these properties is defined then the LogManager uses its
  80  * default configuration. The default configuration is typically loaded from the
  81  * properties file "{@code lib/logging.properties}" in the Java installation
  82  * directory.
  83  * <p>
  84  * The properties for loggers and Handlers will have names starting
  85  * with the dot-separated name for the handler or logger.
  86  * <p>
  87  * The global logging properties may include:
  88  * <ul>
  89  * <li>A property "handlers".  This defines a whitespace or comma separated
  90  * list of class names for handler classes to load and register as
  91  * handlers on the root Logger (the Logger named "").  Each class
  92  * name must be for a Handler class which has a default constructor.
  93  * Note that these Handlers may be created lazily, when they are
  94  * first used.
  95  *
  96  * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
  97  * comma separated list of class names for handlers classes to
  98  * load and register as handlers to the specified logger. Each class
  99  * name must be for a Handler class which has a default constructor.
 100  * Note that these Handlers may be created lazily, when they are
 101  * first used.
 102  *
 103  * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
 104  * value. By default every logger calls its parent in addition to
 105  * handling the logging message itself, this often result in messages
 106  * being handled by the root logger as well. When setting this property
 107  * to false a Handler needs to be configured for this logger otherwise
 108  * no logging messages are delivered.
 109  *
 110  * <li>A property "config".  This property is intended to allow
 111  * arbitrary configuration code to be run.  The property defines a
 112  * whitespace or comma separated list of class names.  A new instance will be
 113  * created for each named class.  The default constructor of each class
 114  * may execute arbitrary code to update the logging configuration, such as
 115  * setting logger levels, adding handlers, adding filters, etc.
 116  * </ul>
 117  * <p>
 118  * Note that all classes loaded during LogManager configuration are
 119  * first searched on the system class path before any user class path.
 120  * That includes the LogManager class, any config classes, and any
 121  * handler classes.
 122  * <p>
 123  * Loggers are organized into a naming hierarchy based on their
 124  * dot separated names.  Thus "a.b.c" is a child of "a.b", but
 125  * "a.b1" and a.b2" are peers.
 126  * <p>
 127  * All properties whose names end with ".level" are assumed to define
 128  * log levels for Loggers.  Thus "foo.level" defines a log level for
 129  * the logger called "foo" and (recursively) for any of its children
 130  * in the naming hierarchy.  Log Levels are applied in the order they
 131  * are defined in the properties file.  Thus level settings for child
 132  * nodes in the tree should come after settings for their parents.
 133  * The property name ".level" can be used to set the level for the
 134  * root of the tree.
 135  * <p>
 136  * All methods on the LogManager object are multi-thread safe.
 137  *
 138  * @since 1.4
 139 */
 140 
 141 public class LogManager {
 142     // The global LogManager object
 143     private static final LogManager manager;
 144 
 145     // 'props' is assigned within a lock but accessed without it.
 146     // Declaring it volatile makes sure that another thread will not
 147     // be able to see a partially constructed 'props' object.
 148     // (seeing a partially constructed 'props' object can result in
 149     // NPE being thrown in Hashtable.get(), because it leaves the door
 150     // open for props.getProperties() to be called before the construcor
 151     // of Hashtable is actually completed).
 152     private volatile Properties props = new Properties();
 153     private final static Level defaultLevel = Level.INFO;
 154 
 155     // LoggerContext for system loggers and user loggers
 156     private final LoggerContext systemContext = new SystemLoggerContext();
 157     private final LoggerContext userContext = new LoggerContext();
 158     // non final field - make it volatile to make sure that other threads
 159     // will see the new value once ensureLogManagerInitialized() has finished
 160     // executing.
 161     private volatile Logger rootLogger;
 162     // Have we done the primordial reading of the configuration file?
 163     // (Must be done after a suitable amount of java.lang.System
 164     // initialization has been done)
 165     private volatile boolean readPrimordialConfiguration;
 166     // Have we initialized global (root) handlers yet?
 167     // This gets set to false in readConfiguration
 168     private boolean initializedGlobalHandlers = true;
 169     // True if JVM death is imminent and the exit hook has been called.
 170     private boolean deathImminent;
 171 
 172     private final Map<Object, Runnable> listeners =
 173             Collections.synchronizedMap(new IdentityHashMap<>());
 174 
 175     static {
 176         manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
 177             @Override
 178             public LogManager run() {
 179                 LogManager mgr = null;
 180                 String cname = null;
 181                 try {
 182                     cname = System.getProperty("java.util.logging.manager");
 183                     if (cname != null) {
 184                         try {
 185                             Class<?> clz = ClassLoader.getSystemClassLoader()
 186                                     .loadClass(cname);
 187                             mgr = (LogManager) clz.newInstance();
 188                         } catch (ClassNotFoundException ex) {
 189                             Class<?> clz = Thread.currentThread()
 190                                     .getContextClassLoader().loadClass(cname);
 191                             mgr = (LogManager) clz.newInstance();
 192                         }
 193                     }
 194                 } catch (Exception ex) {
 195                     System.err.println("Could not load Logmanager \"" + cname + "\"");
 196                     ex.printStackTrace();
 197                 }
 198                 if (mgr == null) {
 199                     mgr = new LogManager();
 200                 }
 201                 return mgr;
 202 
 203             }
 204         });
 205     }
 206 
 207 
 208     // This private class is used as a shutdown hook.
 209     // It does a "reset" to close all open handlers.
 210     private class Cleaner extends Thread {
 211 
 212         private Cleaner() {
 213             /* Set context class loader to null in order to avoid
 214              * keeping a strong reference to an application classloader.
 215              */
 216             this.setContextClassLoader(null);
 217         }
 218 
 219         @Override
 220         public void run() {
 221             // This is to ensure the LogManager.<clinit> is completed
 222             // before synchronized block. Otherwise deadlocks are possible.
 223             LogManager mgr = manager;
 224 
 225             // If the global handlers haven't been initialized yet, we
 226             // don't want to initialize them just so we can close them!
 227             synchronized (LogManager.this) {
 228                 // Note that death is imminent.
 229                 deathImminent = true;
 230                 initializedGlobalHandlers = true;
 231             }
 232 
 233             // Do a reset to close all active handlers.
 234             reset();
 235         }
 236     }
 237 
 238 
 239     /**
 240      * Protected constructor.  This is protected so that container applications
 241      * (such as J2EE containers) can subclass the object.  It is non-public as
 242      * it is intended that there only be one LogManager object, whose value is
 243      * retrieved by calling LogManager.getLogManager.
 244      */
 245     protected LogManager() {
 246         this(checkSubclassPermissions());
 247     }
 248 
 249     private LogManager(Void checked) {
 250 
 251         // Add a shutdown hook to close the global handlers.
 252         try {
 253             Runtime.getRuntime().addShutdownHook(new Cleaner());
 254         } catch (IllegalStateException e) {
 255             // If the VM is already shutting down,
 256             // We do not need to register shutdownHook.
 257         }
 258     }
 259 
 260     private static Void checkSubclassPermissions() {
 261         final SecurityManager sm = System.getSecurityManager();
 262         if (sm != null) {
 263             // These permission will be checked in the LogManager constructor,
 264             // in order to register the Cleaner() thread as a shutdown hook.
 265             // Check them here to avoid the penalty of constructing the object
 266             // etc...
 267             sm.checkPermission(new RuntimePermission("shutdownHooks"));
 268             sm.checkPermission(new RuntimePermission("setContextClassLoader"));
 269         }
 270         return null;
 271     }
 272 
 273     /**
 274      * Lazy initialization: if this instance of manager is the global
 275      * manager then this method will read the initial configuration and
 276      * add the root logger and global logger by calling addLogger().
 277      *
 278      * Note that it is subtly different from what we do in LoggerContext.
 279      * In LoggerContext we're patching up the logger context tree in order to add
 280      * the root and global logger *to the context tree*.
 281      *
 282      * For this to work, addLogger() must have already have been called
 283      * once on the LogManager instance for the default logger being
 284      * added.
 285      *
 286      * This is why ensureLogManagerInitialized() needs to be called before
 287      * any logger is added to any logger context.
 288      *
 289      */
 290     private boolean initializedCalled = false;
 291     private volatile boolean initializationDone = false;
 292     final void ensureLogManagerInitialized() {
 293         final LogManager owner = this;
 294         if (initializationDone || owner != manager) {
 295             // we don't want to do this twice, and we don't want to do
 296             // this on private manager instances.
 297             return;
 298         }
 299 
 300         // Maybe another thread has called ensureLogManagerInitialized()
 301         // before us and is still executing it. If so we will block until
 302         // the log manager has finished initialized, then acquire the monitor,
 303         // notice that initializationDone is now true and return.
 304         // Otherwise - we have come here first! We will acquire the monitor,
 305         // see that initializationDone is still false, and perform the
 306         // initialization.
 307         //
 308         synchronized(this) {
 309             // If initializedCalled is true it means that we're already in
 310             // the process of initializing the LogManager in this thread.
 311             // There has been a recursive call to ensureLogManagerInitialized().
 312             final boolean isRecursiveInitialization = (initializedCalled == true);
 313 
 314             assert initializedCalled || !initializationDone
 315                     : "Initialization can't be done if initialized has not been called!";
 316 
 317             if (isRecursiveInitialization || initializationDone) {
 318                 // If isRecursiveInitialization is true it means that we're
 319                 // already in the process of initializing the LogManager in
 320                 // this thread. There has been a recursive call to
 321                 // ensureLogManagerInitialized(). We should not proceed as
 322                 // it would lead to infinite recursion.
 323                 //
 324                 // If initializationDone is true then it means the manager
 325                 // has finished initializing; just return: we're done.
 326                 return;
 327             }
 328             // Calling addLogger below will in turn call requiresDefaultLogger()
 329             // which will call ensureLogManagerInitialized().
 330             // We use initializedCalled to break the recursion.
 331             initializedCalled = true;
 332             try {
 333                 AccessController.doPrivileged(new PrivilegedAction<Object>() {
 334                     @Override
 335                     public Object run() {
 336                         assert rootLogger == null;
 337                         assert initializedCalled && !initializationDone;
 338 
 339                         // Read configuration.
 340                         owner.readPrimordialConfiguration();
 341 
 342                         // Create and retain Logger for the root of the namespace.
 343                         owner.rootLogger = owner.new RootLogger();
 344                         owner.addLogger(owner.rootLogger);
 345                         if (!owner.rootLogger.isLevelInitialized()) {
 346                             owner.rootLogger.setLevel(defaultLevel);
 347                         }
 348 
 349                         // Adding the global Logger.
 350                         // Do not call Logger.getGlobal() here as this might trigger
 351                         // subtle inter-dependency issues.
 352                         @SuppressWarnings("deprecation")
 353                         final Logger global = Logger.global;
 354 
 355                         // Make sure the global logger will be registered in the
 356                         // global manager
 357                         owner.addLogger(global);
 358                         return null;
 359                     }
 360                 });
 361             } finally {
 362                 initializationDone = true;
 363             }
 364         }
 365     }
 366 
 367     /**
 368      * Returns the global LogManager object.
 369      * @return the global LogManager object
 370      */
 371     public static LogManager getLogManager() {
 372         if (manager != null) {
 373             manager.ensureLogManagerInitialized();
 374         }
 375         return manager;
 376     }
 377 
 378     private void readPrimordialConfiguration() {
 379         if (!readPrimordialConfiguration) {
 380             synchronized (this) {
 381                 if (!readPrimordialConfiguration) {
 382                     // If System.in/out/err are null, it's a good
 383                     // indication that we're still in the
 384                     // bootstrapping phase
 385                     if (System.out == null) {
 386                         return;
 387                     }
 388                     readPrimordialConfiguration = true;
 389 
 390                     try {
 391                         AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
 392                                 @Override
 393                                 public Void run() throws Exception {
 394                                     readConfiguration();
 395 
 396                                     // Platform loggers begin to delegate to java.util.logging.Logger
 397                                     sun.util.logging.PlatformLogger.redirectPlatformLoggers();
 398                                     return null;
 399                                 }
 400                             });
 401                     } catch (Exception ex) {
 402                         assert false : "Exception raised while reading logging configuration: " + ex;
 403                     }
 404                 }
 405             }
 406         }
 407     }
 408 
 409     // LoggerContext maps from AppContext
 410     private WeakHashMap<Object, LoggerContext> contextsMap = null;
 411 
 412     // Returns the LoggerContext for the user code (i.e. application or AppContext).
 413     // Loggers are isolated from each AppContext.
 414     private LoggerContext getUserContext() {
 415         LoggerContext context = null;
 416 
 417         SecurityManager sm = System.getSecurityManager();
 418         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
 419         if (sm != null && javaAwtAccess != null) {
 420             // for each applet, it has its own LoggerContext isolated from others
 421             synchronized (javaAwtAccess) {
 422                 // find the AppContext of the applet code
 423                 // will be null if we are in the main app context.
 424                 final Object ecx = javaAwtAccess.getAppletContext();
 425                 if (ecx != null) {
 426                     if (contextsMap == null) {
 427                         contextsMap = new WeakHashMap<>();
 428                     }
 429                     context = contextsMap.get(ecx);
 430                     if (context == null) {
 431                         // Create a new LoggerContext for the applet.
 432                         context = new LoggerContext();
 433                         contextsMap.put(ecx, context);
 434                     }
 435                 }
 436             }
 437         }
 438         // for standalone app, return userContext
 439         return context != null ? context : userContext;
 440     }
 441 
 442     // The system context.
 443     final LoggerContext getSystemContext() {
 444         return systemContext;
 445     }
 446 
 447     private List<LoggerContext> contexts() {
 448         List<LoggerContext> cxs = new ArrayList<>();
 449         cxs.add(getSystemContext());
 450         cxs.add(getUserContext());
 451         return cxs;
 452     }
 453 
 454     // Find or create a specified logger instance. If a logger has
 455     // already been created with the given name it is returned.
 456     // Otherwise a new logger instance is created and registered
 457     // in the LogManager global namespace.
 458     // This method will always return a non-null Logger object.
 459     // Synchronization is not required here. All synchronization for
 460     // adding a new Logger object is handled by addLogger().
 461     //
 462     // This method must delegate to the LogManager implementation to
 463     // add a new Logger or return the one that has been added previously
 464     // as a LogManager subclass may override the addLogger, getLogger,
 465     // readConfiguration, and other methods.
 466     Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
 467         Logger result = getLogger(name);
 468         if (result == null) {
 469             // only allocate the new logger once
 470             Logger newLogger = new Logger(name, resourceBundleName, caller, this, false);
 471             do {
 472                 if (addLogger(newLogger)) {
 473                     // We successfully added the new Logger that we
 474                     // created above so return it without refetching.
 475                     return newLogger;
 476                 }
 477 
 478                 // We didn't add the new Logger that we created above
 479                 // because another thread added a Logger with the same
 480                 // name after our null check above and before our call
 481                 // to addLogger(). We have to refetch the Logger because
 482                 // addLogger() returns a boolean instead of the Logger
 483                 // reference itself. However, if the thread that created
 484                 // the other Logger is not holding a strong reference to
 485                 // the other Logger, then it is possible for the other
 486                 // Logger to be GC'ed after we saw it in addLogger() and
 487                 // before we can refetch it. If it has been GC'ed then
 488                 // we'll just loop around and try again.
 489                 result = getLogger(name);
 490             } while (result == null);
 491         }
 492         return result;
 493     }
 494 
 495     Logger demandSystemLogger(String name, String resourceBundleName) {
 496         // Add a system logger in the system context's namespace
 497         final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
 498 
 499         // Add the system logger to the LogManager's namespace if not exist
 500         // so that there is only one single logger of the given name.
 501         // System loggers are visible to applications unless a logger of
 502         // the same name has been added.
 503         Logger logger;
 504         do {
 505             // First attempt to call addLogger instead of getLogger
 506             // This would avoid potential bug in custom LogManager.getLogger
 507             // implementation that adds a logger if does not exist
 508             if (addLogger(sysLogger)) {
 509                 // successfully added the new system logger
 510                 logger = sysLogger;
 511             } else {
 512                 logger = getLogger(name);
 513             }
 514         } while (logger == null);
 515 
 516         // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
 517         if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) {
 518             // if logger already exists but handlers not set
 519             final Logger l = logger;
 520             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 521                 @Override
 522                 public Void run() {
 523                     for (Handler hdl : l.accessCheckedHandlers()) {
 524                         sysLogger.addHandler(hdl);
 525                     }
 526                     return null;
 527                 }
 528             });
 529         }
 530         return sysLogger;
 531     }
 532 
 533     // LoggerContext maintains the logger namespace per context.
 534     // The default LogManager implementation has one system context and user
 535     // context.  The system context is used to maintain the namespace for
 536     // all system loggers and is queried by the system code.  If a system logger
 537     // doesn't exist in the user context, it'll also be added to the user context.
 538     // The user context is queried by the user code and all other loggers are
 539     // added in the user context.
 540     class LoggerContext {
 541         // Table of named Loggers that maps names to Loggers.
 542         private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
 543         // Tree of named Loggers
 544         private final LogNode root;
 545         private LoggerContext() {
 546             this.root = new LogNode(null, this);
 547         }
 548 
 549 
 550         // Tells whether default loggers are required in this context.
 551         // If true, the default loggers will be lazily added.
 552         final boolean requiresDefaultLoggers() {
 553             final boolean requiresDefaultLoggers = (getOwner() == manager);
 554             if (requiresDefaultLoggers) {
 555                 getOwner().ensureLogManagerInitialized();
 556             }
 557             return requiresDefaultLoggers;
 558         }
 559 
 560         // This context's LogManager.
 561         final LogManager getOwner() {
 562             return LogManager.this;
 563         }
 564 
 565         // This context owner's root logger, which if not null, and if
 566         // the context requires default loggers, will be added to the context
 567         // logger's tree.
 568         final Logger getRootLogger() {
 569             return getOwner().rootLogger;
 570         }
 571 
 572         // The global logger, which if not null, and if
 573         // the context requires default loggers, will be added to the context
 574         // logger's tree.
 575         final Logger getGlobalLogger() {
 576             @SuppressWarnings("deprecation") // avoids initialization cycles.
 577             final Logger global = Logger.global;
 578             return global;
 579         }
 580 
 581         Logger demandLogger(String name, String resourceBundleName) {
 582             // a LogManager subclass may have its own implementation to add and
 583             // get a Logger.  So delegate to the LogManager to do the work.
 584             final LogManager owner = getOwner();
 585             return owner.demandLogger(name, resourceBundleName, null);
 586         }
 587 
 588 
 589         // Due to subtle deadlock issues getUserContext() no longer
 590         // calls addLocalLogger(rootLogger);
 591         // Therefore - we need to add the default loggers later on.
 592         // Checks that the context is properly initialized
 593         // This is necessary before calling e.g. find(name)
 594         // or getLoggerNames()
 595         //
 596         private void ensureInitialized() {
 597             if (requiresDefaultLoggers()) {
 598                 // Ensure that the root and global loggers are set.
 599                 ensureDefaultLogger(getRootLogger());
 600                 ensureDefaultLogger(getGlobalLogger());
 601             }
 602         }
 603 
 604 
 605         synchronized Logger findLogger(String name) {
 606             // ensure that this context is properly initialized before
 607             // looking for loggers.
 608             ensureInitialized();
 609             LoggerWeakRef ref = namedLoggers.get(name);
 610             if (ref == null) {
 611                 return null;
 612             }
 613             Logger logger = ref.get();
 614             if (logger == null) {
 615                 // Hashtable holds stale weak reference
 616                 // to a logger which has been GC-ed.
 617                 ref.dispose();
 618             }
 619             return logger;
 620         }
 621 
 622         // This method is called before adding a logger to the
 623         // context.
 624         // 'logger' is the context that will be added.
 625         // This method will ensure that the defaults loggers are added
 626         // before adding 'logger'.
 627         //
 628         private void ensureAllDefaultLoggers(Logger logger) {
 629             if (requiresDefaultLoggers()) {
 630                 final String name = logger.getName();
 631                 if (!name.isEmpty()) {
 632                     ensureDefaultLogger(getRootLogger());
 633                     if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
 634                         ensureDefaultLogger(getGlobalLogger());
 635                     }
 636                 }
 637             }
 638         }
 639 
 640         private void ensureDefaultLogger(Logger logger) {
 641             // Used for lazy addition of root logger and global logger
 642             // to a LoggerContext.
 643 
 644             // This check is simple sanity: we do not want that this
 645             // method be called for anything else than Logger.global
 646             // or owner.rootLogger.
 647             if (!requiresDefaultLoggers() || logger == null
 648                     || logger != getGlobalLogger() && logger != LogManager.this.rootLogger ) {
 649 
 650                 // the case where we have a non null logger which is neither
 651                 // Logger.global nor manager.rootLogger indicates a serious
 652                 // issue - as ensureDefaultLogger should never be called
 653                 // with any other loggers than one of these two (or null - if
 654                 // e.g manager.rootLogger is not yet initialized)...
 655                 assert logger == null;
 656 
 657                 return;
 658             }
 659 
 660             // Adds the logger if it's not already there.
 661             if (!namedLoggers.containsKey(logger.getName())) {
 662                 // It is important to prevent addLocalLogger to
 663                 // call ensureAllDefaultLoggers when we're in the process
 664                 // off adding one of those default loggers - as this would
 665                 // immediately cause a stack overflow.
 666                 // Therefore we must pass addDefaultLoggersIfNeeded=false,
 667                 // even if requiresDefaultLoggers is true.
 668                 addLocalLogger(logger, false);
 669             }
 670         }
 671 
 672         boolean addLocalLogger(Logger logger) {
 673             // no need to add default loggers if it's not required
 674             return addLocalLogger(logger, requiresDefaultLoggers());
 675         }
 676 
 677         // Add a logger to this context.  This method will only set its level
 678         // and process parent loggers.  It doesn't set its handlers.
 679         synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
 680             // addDefaultLoggersIfNeeded serves to break recursion when adding
 681             // default loggers. If we're adding one of the default loggers
 682             // (we're being called from ensureDefaultLogger()) then
 683             // addDefaultLoggersIfNeeded will be false: we don't want to
 684             // call ensureAllDefaultLoggers again.
 685             //
 686             // Note: addDefaultLoggersIfNeeded can also be false when
 687             //       requiresDefaultLoggers is false - since calling
 688             //       ensureAllDefaultLoggers would have no effect in this case.
 689             if (addDefaultLoggersIfNeeded) {
 690                 ensureAllDefaultLoggers(logger);
 691             }
 692 
 693             final String name = logger.getName();
 694             if (name == null) {
 695                 throw new NullPointerException();
 696             }
 697             LoggerWeakRef ref = namedLoggers.get(name);
 698             if (ref != null) {
 699                 if (ref.get() == null) {
 700                     // It's possible that the Logger was GC'ed after a
 701                     // drainLoggerRefQueueBounded() call above so allow
 702                     // a new one to be registered.
 703                     ref.dispose();
 704                 } else {
 705                     // We already have a registered logger with the given name.
 706                     return false;
 707                 }
 708             }
 709 
 710             // We're adding a new logger.
 711             // Note that we are creating a weak reference here.
 712             final LogManager owner = getOwner();
 713             logger.setLogManager(owner);
 714             ref = owner.new LoggerWeakRef(logger);
 715             namedLoggers.put(name, ref);
 716 
 717             // Apply any initial level defined for the new logger, unless
 718             // the logger's level is already initialized
 719             Level level = owner.getLevelProperty(name + ".level", null);
 720             if (level != null && !logger.isLevelInitialized()) {
 721                 doSetLevel(logger, level);
 722             }
 723 
 724             // instantiation of the handler is done in the LogManager.addLogger
 725             // implementation as a handler class may be only visible to LogManager
 726             // subclass for the custom log manager case
 727             processParentHandlers(logger, name);
 728 
 729             // Find the new node and its parent.
 730             LogNode node = getNode(name);
 731             node.loggerRef = ref;
 732             Logger parent = null;
 733             LogNode nodep = node.parent;
 734             while (nodep != null) {
 735                 LoggerWeakRef nodeRef = nodep.loggerRef;
 736                 if (nodeRef != null) {
 737                     parent = nodeRef.get();
 738                     if (parent != null) {
 739                         break;
 740                     }
 741                 }
 742                 nodep = nodep.parent;
 743             }
 744 
 745             if (parent != null) {
 746                 doSetParent(logger, parent);
 747             }
 748             // Walk over the children and tell them we are their new parent.
 749             node.walkAndSetParent(logger);
 750             // new LogNode is ready so tell the LoggerWeakRef about it
 751             ref.setNode(node);
 752             return true;
 753         }
 754 
 755         synchronized void removeLoggerRef(String name, LoggerWeakRef ref) {
 756             namedLoggers.remove(name, ref);
 757         }
 758 
 759         synchronized Enumeration<String> getLoggerNames() {
 760             // ensure that this context is properly initialized before
 761             // returning logger names.
 762             ensureInitialized();
 763             return namedLoggers.keys();
 764         }
 765 
 766         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 767         // parents have levels or handlers defined, make sure they are instantiated.
 768         private void processParentHandlers(final Logger logger, final String name) {
 769             final LogManager owner = getOwner();
 770             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 771                 @Override
 772                 public Void run() {
 773                     if (logger != owner.rootLogger) {
 774                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
 775                         if (!useParent) {
 776                             logger.setUseParentHandlers(false);
 777                         }
 778                     }
 779                     return null;
 780                 }
 781             });
 782 
 783             int ix = 1;
 784             for (;;) {
 785                 int ix2 = name.indexOf('.', ix);
 786                 if (ix2 < 0) {
 787                     break;
 788                 }
 789                 String pname = name.substring(0, ix2);
 790                 if (owner.getProperty(pname + ".level") != null ||
 791                     owner.getProperty(pname + ".handlers") != null) {
 792                     // This pname has a level/handlers definition.
 793                     // Make sure it exists.
 794                     demandLogger(pname, null);
 795                 }
 796                 ix = ix2+1;
 797             }
 798         }
 799 
 800         // Gets a node in our tree of logger nodes.
 801         // If necessary, create it.
 802         LogNode getNode(String name) {
 803             if (name == null || name.equals("")) {
 804                 return root;
 805             }
 806             LogNode node = root;
 807             while (name.length() > 0) {
 808                 int ix = name.indexOf('.');
 809                 String head;
 810                 if (ix > 0) {
 811                     head = name.substring(0, ix);
 812                     name = name.substring(ix + 1);
 813                 } else {
 814                     head = name;
 815                     name = "";
 816                 }
 817                 if (node.children == null) {
 818                     node.children = new HashMap<>();
 819                 }
 820                 LogNode child = node.children.get(head);
 821                 if (child == null) {
 822                     child = new LogNode(node, this);
 823                     node.children.put(head, child);
 824                 }
 825                 node = child;
 826             }
 827             return node;
 828         }
 829     }
 830 
 831     final class SystemLoggerContext extends LoggerContext {
 832         // Add a system logger in the system context's namespace as well as
 833         // in the LogManager's namespace if not exist so that there is only
 834         // one single logger of the given name.  System loggers are visible
 835         // to applications unless a logger of the same name has been added.
 836         @Override
 837         Logger demandLogger(String name, String resourceBundleName) {
 838             Logger result = findLogger(name);
 839             if (result == null) {
 840                 // only allocate the new system logger once
 841                 Logger newLogger = new Logger(name, resourceBundleName, null, getOwner(), true);
 842                 do {
 843                     if (addLocalLogger(newLogger)) {
 844                         // We successfully added the new Logger that we
 845                         // created above so return it without refetching.
 846                         result = newLogger;
 847                     } else {
 848                         // We didn't add the new Logger that we created above
 849                         // because another thread added a Logger with the same
 850                         // name after our null check above and before our call
 851                         // to addLogger(). We have to refetch the Logger because
 852                         // addLogger() returns a boolean instead of the Logger
 853                         // reference itself. However, if the thread that created
 854                         // the other Logger is not holding a strong reference to
 855                         // the other Logger, then it is possible for the other
 856                         // Logger to be GC'ed after we saw it in addLogger() and
 857                         // before we can refetch it. If it has been GC'ed then
 858                         // we'll just loop around and try again.
 859                         result = findLogger(name);
 860                     }
 861                 } while (result == null);
 862             }
 863             return result;
 864         }
 865     }
 866 
 867     // Add new per logger handlers.
 868     // We need to raise privilege here. All our decisions will
 869     // be made based on the logging configuration, which can
 870     // only be modified by trusted code.
 871     private void loadLoggerHandlers(final Logger logger, final String name,
 872                                     final String handlersPropertyName)
 873     {
 874         AccessController.doPrivileged(new PrivilegedAction<Object>() {
 875             @Override
 876             public Object run() {
 877                 String names[] = parseClassNames(handlersPropertyName);
 878                 for (String word : names) {
 879                     try {
 880                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
 881                         Handler hdl = (Handler) clz.newInstance();
 882                         // Check if there is a property defining the
 883                         // this handler's level.
 884                         String levs = getProperty(word + ".level");
 885                         if (levs != null) {
 886                             Level l = Level.findLevel(levs);
 887                             if (l != null) {
 888                                 hdl.setLevel(l);
 889                             } else {
 890                                 // Probably a bad level. Drop through.
 891                                 System.err.println("Can't set level for " + word);
 892                             }
 893                         }
 894                         // Add this Handler to the logger
 895                         logger.addHandler(hdl);
 896                     } catch (Exception ex) {
 897                         System.err.println("Can't load log handler \"" + word + "\"");
 898                         System.err.println("" + ex);
 899                         ex.printStackTrace();
 900                     }
 901                 }
 902                 return null;
 903             }
 904         });
 905     }
 906 
 907 
 908     // loggerRefQueue holds LoggerWeakRef objects for Logger objects
 909     // that have been GC'ed.
 910     private final ReferenceQueue<Logger> loggerRefQueue
 911         = new ReferenceQueue<>();
 912 
 913     // Package-level inner class.
 914     // Helper class for managing WeakReferences to Logger objects.
 915     //
 916     // LogManager.namedLoggers
 917     //     - has weak references to all named Loggers
 918     //     - namedLoggers keeps the LoggerWeakRef objects for the named
 919     //       Loggers around until we can deal with the book keeping for
 920     //       the named Logger that is being GC'ed.
 921     // LogManager.LogNode.loggerRef
 922     //     - has a weak reference to a named Logger
 923     //     - the LogNode will also keep the LoggerWeakRef objects for
 924     //       the named Loggers around; currently LogNodes never go away.
 925     // Logger.kids
 926     //     - has a weak reference to each direct child Logger; this
 927     //       includes anonymous and named Loggers
 928     //     - anonymous Loggers are always children of the rootLogger
 929     //       which is a strong reference; rootLogger.kids keeps the
 930     //       LoggerWeakRef objects for the anonymous Loggers around
 931     //       until we can deal with the book keeping.
 932     //
 933     final class LoggerWeakRef extends WeakReference<Logger> {
 934         private String                name;       // for namedLoggers cleanup
 935         private LogNode               node;       // for loggerRef cleanup
 936         private WeakReference<Logger> parentRef;  // for kids cleanup
 937         private boolean disposed = false;         // avoid calling dispose twice
 938 
 939         LoggerWeakRef(Logger logger) {
 940             super(logger, loggerRefQueue);
 941 
 942             name = logger.getName();  // save for namedLoggers cleanup
 943         }
 944 
 945         // dispose of this LoggerWeakRef object
 946         void dispose() {
 947             // Avoid calling dispose twice. When a Logger is gc'ed, its
 948             // LoggerWeakRef will be enqueued.
 949             // However, a new logger of the same name may be added (or looked
 950             // up) before the queue is drained. When that happens, dispose()
 951             // will be called by addLocalLogger() or findLogger().
 952             // Later when the queue is drained, dispose() will be called again
 953             // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed
 954             // avoids processing the data twice (even though the code should
 955             // now be reentrant).
 956             synchronized(this) {
 957                 // Note to maintainers:
 958                 // Be careful not to call any method that tries to acquire
 959                 // another lock from within this block - as this would surely
 960                 // lead to deadlocks, given that dispose() can be called by
 961                 // multiple threads, and from within different synchronized
 962                 // methods/blocks.
 963                 if (disposed) return;
 964                 disposed = true;
 965             }
 966 
 967             final LogNode n = node;
 968             if (n != null) {
 969                 // n.loggerRef can only be safely modified from within
 970                 // a lock on LoggerContext. removeLoggerRef is already
 971                 // synchronized on LoggerContext so calling
 972                 // n.context.removeLoggerRef from within this lock is safe.
 973                 synchronized (n.context) {
 974                     // if we have a LogNode, then we were a named Logger
 975                     // so clear namedLoggers weak ref to us
 976                     n.context.removeLoggerRef(name, this);
 977                     name = null;  // clear our ref to the Logger's name
 978 
 979                     // LogNode may have been reused - so only clear
 980                     // LogNode.loggerRef if LogNode.loggerRef == this
 981                     if (n.loggerRef == this) {
 982                         n.loggerRef = null;  // clear LogNode's weak ref to us
 983                     }
 984                     node = null;            // clear our ref to LogNode
 985                 }
 986             }
 987 
 988             if (parentRef != null) {
 989                 // this LoggerWeakRef has or had a parent Logger
 990                 Logger parent = parentRef.get();
 991                 if (parent != null) {
 992                     // the parent Logger is still there so clear the
 993                     // parent Logger's weak ref to us
 994                     parent.removeChildLogger(this);
 995                 }
 996                 parentRef = null;  // clear our weak ref to the parent Logger
 997             }
 998         }
 999 
1000         // set the node field to the specified value
1001         void setNode(LogNode node) {
1002             this.node = node;
1003         }
1004 
1005         // set the parentRef field to the specified value
1006         void setParentRef(WeakReference<Logger> parentRef) {
1007             this.parentRef = parentRef;
1008         }
1009     }
1010 
1011     // Package-level method.
1012     // Drain some Logger objects that have been GC'ed.
1013     //
1014     // drainLoggerRefQueueBounded() is called by addLogger() below
1015     // and by Logger.getAnonymousLogger(String) so we'll drain up to
1016     // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
1017     //
1018     // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
1019     // us about a 50/50 mix in increased weak ref counts versus
1020     // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
1021     // Here are stats for cleaning up sets of 400 anonymous Loggers:
1022     //   - test duration 1 minute
1023     //   - sample size of 125 sets of 400
1024     //   - average: 1.99 ms
1025     //   - minimum: 0.57 ms
1026     //   - maximum: 25.3 ms
1027     //
1028     // The same config gives us a better decreased weak ref count
1029     // than increased weak ref count in the LoggerWeakRefLeak test.
1030     // Here are stats for cleaning up sets of 400 named Loggers:
1031     //   - test duration 2 minutes
1032     //   - sample size of 506 sets of 400
1033     //   - average: 0.57 ms
1034     //   - minimum: 0.02 ms
1035     //   - maximum: 10.9 ms
1036     //
1037     private final static int MAX_ITERATIONS = 400;
1038     final void drainLoggerRefQueueBounded() {
1039         for (int i = 0; i < MAX_ITERATIONS; i++) {
1040             if (loggerRefQueue == null) {
1041                 // haven't finished loading LogManager yet
1042                 break;
1043             }
1044 
1045             LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
1046             if (ref == null) {
1047                 break;
1048             }
1049             // a Logger object has been GC'ed so clean it up
1050             ref.dispose();
1051         }
1052     }
1053 
1054     /**
1055      * Add a named logger.  This does nothing and returns false if a logger
1056      * with the same name is already registered.
1057      * <p>
1058      * The Logger factory methods call this method to register each
1059      * newly created Logger.
1060      * <p>
1061      * The application should retain its own reference to the Logger
1062      * object to avoid it being garbage collected.  The LogManager
1063      * may only retain a weak reference.
1064      *
1065      * @param   logger the new logger.
1066      * @return  true if the argument logger was registered successfully,
1067      *          false if a logger of that name already exists.
1068      * @exception NullPointerException if the logger name is null.
1069      */
1070     public boolean addLogger(Logger logger) {
1071         final String name = logger.getName();
1072         if (name == null) {
1073             throw new NullPointerException();
1074         }
1075         drainLoggerRefQueueBounded();
1076         LoggerContext cx = getUserContext();
1077         if (cx.addLocalLogger(logger)) {
1078             // Do we have a per logger handler too?
1079             // Note: this will add a 200ms penalty
1080             loadLoggerHandlers(logger, name, name + ".handlers");
1081             return true;
1082         } else {
1083             return false;
1084         }
1085     }
1086 
1087     // Private method to set a level on a logger.
1088     // If necessary, we raise privilege before doing the call.
1089     private static void doSetLevel(final Logger logger, final Level level) {
1090         SecurityManager sm = System.getSecurityManager();
1091         if (sm == null) {
1092             // There is no security manager, so things are easy.
1093             logger.setLevel(level);
1094             return;
1095         }
1096         // There is a security manager.  Raise privilege before
1097         // calling setLevel.
1098         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1099             @Override
1100             public Object run() {
1101                 logger.setLevel(level);
1102                 return null;
1103             }});
1104     }
1105 
1106     // Private method to set a parent on a logger.
1107     // If necessary, we raise privilege before doing the setParent call.
1108     private static void doSetParent(final Logger logger, final Logger parent) {
1109         SecurityManager sm = System.getSecurityManager();
1110         if (sm == null) {
1111             // There is no security manager, so things are easy.
1112             logger.setParent(parent);
1113             return;
1114         }
1115         // There is a security manager.  Raise privilege before
1116         // calling setParent.
1117         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1118             @Override
1119             public Object run() {
1120                 logger.setParent(parent);
1121                 return null;
1122             }});
1123     }
1124 
1125     /**
1126      * Method to find a named logger.
1127      * <p>
1128      * Note that since untrusted code may create loggers with
1129      * arbitrary names this method should not be relied on to
1130      * find Loggers for security sensitive logging.
1131      * It is also important to note that the Logger associated with the
1132      * String {@code name} may be garbage collected at any time if there
1133      * is no strong reference to the Logger. The caller of this method
1134      * must check the return value for null in order to properly handle
1135      * the case where the Logger has been garbage collected.
1136      *
1137      * @param name name of the logger
1138      * @return  matching logger or null if none is found
1139      */
1140     public Logger getLogger(String name) {
1141         return getUserContext().findLogger(name);
1142     }
1143 
1144     /**
1145      * Get an enumeration of known logger names.
1146      * <p>
1147      * Note:  Loggers may be added dynamically as new classes are loaded.
1148      * This method only reports on the loggers that are currently registered.
1149      * It is also important to note that this method only returns the name
1150      * of a Logger, not a strong reference to the Logger itself.
1151      * The returned String does nothing to prevent the Logger from being
1152      * garbage collected. In particular, if the returned name is passed
1153      * to {@code LogManager.getLogger()}, then the caller must check the
1154      * return value from {@code LogManager.getLogger()} for null to properly
1155      * handle the case where the Logger has been garbage collected in the
1156      * time since its name was returned by this method.
1157      *
1158      * @return  enumeration of logger name strings
1159      */
1160     public Enumeration<String> getLoggerNames() {
1161         return getUserContext().getLoggerNames();
1162     }
1163 
1164     /**
1165      * Reinitialize the logging properties and reread the logging configuration.
1166      * <p>
1167      * The same rules are used for locating the configuration properties
1168      * as are used at startup.  So normally the logging properties will
1169      * be re-read from the same file that was used at startup.
1170      * <P>
1171      * Any log level definitions in the new configuration file will be
1172      * applied using Logger.setLevel(), if the target Logger exists.
1173      * <p>
1174      * Any {@linkplain #addConfigurationListener registered configuration
1175      * listener} will be invoked after the properties are read.
1176      *
1177      * @exception  SecurityException  if a security manager exists and if
1178      *             the caller does not have LoggingPermission("control").
1179      * @exception  IOException if there are IO problems reading the configuration.
1180      */
1181     public void readConfiguration() throws IOException, SecurityException {
1182         checkPermission();
1183 
1184         // if a configuration class is specified, load it and use it.
1185         String cname = System.getProperty("java.util.logging.config.class");
1186         if (cname != null) {
1187             try {
1188                 // Instantiate the named class.  It is its constructor's
1189                 // responsibility to initialize the logging configuration, by
1190                 // calling readConfiguration(InputStream) with a suitable stream.
1191                 try {
1192                     Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
1193                     clz.newInstance();
1194                     return;
1195                 } catch (ClassNotFoundException ex) {
1196                     Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
1197                     clz.newInstance();
1198                     return;
1199                 }
1200             } catch (Exception ex) {
1201                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1202                 System.err.println("" + ex);
1203                 // keep going and useful config file.
1204             }
1205         }
1206 
1207         String fname = System.getProperty("java.util.logging.config.file");
1208         if (fname == null) {
1209             fname = System.getProperty("java.home");
1210             if (fname == null) {
1211                 throw new Error("Can't find java.home ??");
1212             }
1213             File f = new File(fname, "lib");
1214             f = new File(f, "logging.properties");
1215             fname = f.getCanonicalPath();
1216         }
1217         try (final InputStream in = new FileInputStream(fname)) {
1218             final BufferedInputStream bin = new BufferedInputStream(in);
1219             readConfiguration(bin);
1220         }
1221     }
1222 
1223     /**
1224      * Reset the logging configuration.
1225      * <p>
1226      * For all named loggers, the reset operation removes and closes
1227      * all Handlers and (except for the root logger) sets the level
1228      * to null.  The root logger's level is set to Level.INFO.
1229      *
1230      * @exception  SecurityException  if a security manager exists and if
1231      *             the caller does not have LoggingPermission("control").
1232      */
1233 
1234     public void reset() throws SecurityException {
1235         checkPermission();
1236         synchronized (this) {
1237             props = new Properties();
1238             // Since we are doing a reset we no longer want to initialize
1239             // the global handlers, if they haven't been initialized yet.
1240             initializedGlobalHandlers = true;
1241         }
1242         for (LoggerContext cx : contexts()) {
1243             Enumeration<String> enum_ = cx.getLoggerNames();
1244             while (enum_.hasMoreElements()) {
1245                 String name = enum_.nextElement();
1246                 Logger logger = cx.findLogger(name);
1247                 if (logger != null) {
1248                     resetLogger(logger);
1249                 }
1250             }
1251         }
1252     }
1253 
1254     // Private method to reset an individual target logger.
1255     private void resetLogger(Logger logger) {
1256         // Close all the Logger's handlers.
1257         Handler[] targets = logger.getHandlers();
1258         for (Handler h : targets) {
1259             logger.removeHandler(h);
1260             try {
1261                 h.close();
1262             } catch (Exception ex) {
1263                 // Problems closing a handler?  Keep going...
1264             }
1265         }
1266         String name = logger.getName();
1267         if (name != null && name.equals("")) {
1268             // This is the root logger.
1269             logger.setLevel(defaultLevel);
1270         } else {
1271             logger.setLevel(null);
1272         }
1273     }
1274 
1275     // get a list of whitespace separated classnames from a property.
1276     private String[] parseClassNames(String propertyName) {
1277         String hands = getProperty(propertyName);
1278         if (hands == null) {
1279             return new String[0];
1280         }
1281         hands = hands.trim();
1282         int ix = 0;
1283         final List<String> result = new ArrayList<>();
1284         while (ix < hands.length()) {
1285             int end = ix;
1286             while (end < hands.length()) {
1287                 if (Character.isWhitespace(hands.charAt(end))) {
1288                     break;
1289                 }
1290                 if (hands.charAt(end) == ',') {
1291                     break;
1292                 }
1293                 end++;
1294             }
1295             String word = hands.substring(ix, end);
1296             ix = end+1;
1297             word = word.trim();
1298             if (word.length() == 0) {
1299                 continue;
1300             }
1301             result.add(word);
1302         }
1303         return result.toArray(new String[result.size()]);
1304     }
1305 
1306     /**
1307      * Reinitialize the logging properties and reread the logging configuration
1308      * from the given stream, which should be in java.util.Properties format.
1309      * Any {@linkplain #addConfigurationListener registered configuration
1310      * listener} will be invoked after the properties are read.
1311      * <p>
1312      * Any log level definitions in the new configuration file will be
1313      * applied using Logger.setLevel(), if the target Logger exists.
1314      *
1315      * @param ins       stream to read properties from
1316      * @exception  SecurityException  if a security manager exists and if
1317      *             the caller does not have LoggingPermission("control").
1318      * @exception  IOException if there are problems reading from the stream.
1319      */
1320     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1321         checkPermission();
1322         reset();
1323 
1324         // Load the properties
1325         props.load(ins);
1326         // Instantiate new configuration objects.
1327         String names[] = parseClassNames("config");
1328 
1329         for (String word : names) {
1330             try {
1331                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
1332                 clz.newInstance();
1333             } catch (Exception ex) {
1334                 System.err.println("Can't load config class \"" + word + "\"");
1335                 System.err.println("" + ex);
1336                 // ex.printStackTrace();
1337             }
1338         }
1339 
1340         // Set levels on any pre-existing loggers, based on the new properties.
1341         setLevelsOnExistingLoggers();
1342 
1343         try {
1344             invokeConfigurationListeners();
1345         } finally {
1346             // Note that we need to reinitialize global handles when
1347             // they are first referenced.
1348             synchronized (this) {
1349                 initializedGlobalHandlers = false;
1350             }
1351         }
1352     }
1353 
1354     /**
1355      * Get the value of a logging property.
1356      * The method returns null if the property is not found.
1357      * @param name      property name
1358      * @return          property value
1359      */
1360     public String getProperty(String name) {
1361         return props.getProperty(name);
1362     }
1363 
1364     // Package private method to get a String property.
1365     // If the property is not defined we return the given
1366     // default value.
1367     String getStringProperty(String name, String defaultValue) {
1368         String val = getProperty(name);
1369         if (val == null) {
1370             return defaultValue;
1371         }
1372         return val.trim();
1373     }
1374 
1375     // Package private method to get an integer property.
1376     // If the property is not defined or cannot be parsed
1377     // we return the given default value.
1378     int getIntProperty(String name, int defaultValue) {
1379         String val = getProperty(name);
1380         if (val == null) {
1381             return defaultValue;
1382         }
1383         try {
1384             return Integer.parseInt(val.trim());
1385         } catch (Exception ex) {
1386             return defaultValue;
1387         }
1388     }
1389 
1390     // Package private method to get a long property.
1391     // If the property is not defined or cannot be parsed
1392     // we return the given default value.
1393     long getLongProperty(String name, long defaultValue) {
1394         String val = getProperty(name);
1395         if (val == null) {
1396             return defaultValue;
1397         }
1398         try {
1399             return Long.parseLong(val.trim());
1400         } catch (Exception ex) {
1401             return defaultValue;
1402         }
1403     }
1404 
1405     // Package private method to get a boolean property.
1406     // If the property is not defined or cannot be parsed
1407     // we return the given default value.
1408     boolean getBooleanProperty(String name, boolean defaultValue) {
1409         String val = getProperty(name);
1410         if (val == null) {
1411             return defaultValue;
1412         }
1413         val = val.toLowerCase();
1414         if (val.equals("true") || val.equals("1")) {
1415             return true;
1416         } else if (val.equals("false") || val.equals("0")) {
1417             return false;
1418         }
1419         return defaultValue;
1420     }
1421 
1422     // Package private method to get a Level property.
1423     // If the property is not defined or cannot be parsed
1424     // we return the given default value.
1425     Level getLevelProperty(String name, Level defaultValue) {
1426         String val = getProperty(name);
1427         if (val == null) {
1428             return defaultValue;
1429         }
1430         Level l = Level.findLevel(val.trim());
1431         return l != null ? l : defaultValue;
1432     }
1433 
1434     // Package private method to get a filter property.
1435     // We return an instance of the class named by the "name"
1436     // property. If the property is not defined or has problems
1437     // we return the defaultValue.
1438     Filter getFilterProperty(String name, Filter defaultValue) {
1439         String val = getProperty(name);
1440         try {
1441             if (val != null) {
1442                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
1443                 return (Filter) clz.newInstance();
1444             }
1445         } catch (Exception ex) {
1446             // We got one of a variety of exceptions in creating the
1447             // class or creating an instance.
1448             // Drop through.
1449         }
1450         // We got an exception.  Return the defaultValue.
1451         return defaultValue;
1452     }
1453 
1454 
1455     // Package private method to get a formatter property.
1456     // We return an instance of the class named by the "name"
1457     // property. If the property is not defined or has problems
1458     // we return the defaultValue.
1459     Formatter getFormatterProperty(String name, Formatter defaultValue) {
1460         String val = getProperty(name);
1461         try {
1462             if (val != null) {
1463                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
1464                 return (Formatter) clz.newInstance();
1465             }
1466         } catch (Exception ex) {
1467             // We got one of a variety of exceptions in creating the
1468             // class or creating an instance.
1469             // Drop through.
1470         }
1471         // We got an exception.  Return the defaultValue.
1472         return defaultValue;
1473     }
1474 
1475     // Private method to load the global handlers.
1476     // We do the real work lazily, when the global handlers
1477     // are first used.
1478     private synchronized void initializeGlobalHandlers() {
1479         if (initializedGlobalHandlers) {
1480             return;
1481         }
1482 
1483         initializedGlobalHandlers = true;
1484 
1485         if (deathImminent) {
1486             // Aaargh...
1487             // The VM is shutting down and our exit hook has been called.
1488             // Avoid allocating global handlers.
1489             return;
1490         }
1491         loadLoggerHandlers(rootLogger, null, "handlers");
1492     }
1493 
1494     static final Permission controlPermission = new LoggingPermission("control", null);
1495 
1496     void checkPermission() {
1497         SecurityManager sm = System.getSecurityManager();
1498         if (sm != null)
1499             sm.checkPermission(controlPermission);
1500     }
1501 
1502     /**
1503      * Check that the current context is trusted to modify the logging
1504      * configuration.  This requires LoggingPermission("control").
1505      * <p>
1506      * If the check fails we throw a SecurityException, otherwise
1507      * we return normally.
1508      *
1509      * @exception  SecurityException  if a security manager exists and if
1510      *             the caller does not have LoggingPermission("control").
1511      */
1512     public void checkAccess() throws SecurityException {
1513         checkPermission();
1514     }
1515 
1516     // Nested class to represent a node in our tree of named loggers.
1517     private static class LogNode {
1518         HashMap<String,LogNode> children;
1519         LoggerWeakRef loggerRef;
1520         LogNode parent;
1521         final LoggerContext context;
1522 
1523         LogNode(LogNode parent, LoggerContext context) {
1524             this.parent = parent;
1525             this.context = context;
1526         }
1527 
1528         // Recursive method to walk the tree below a node and set
1529         // a new parent logger.
1530         void walkAndSetParent(Logger parent) {
1531             if (children == null) {
1532                 return;
1533             }
1534             for (LogNode node : children.values()) {
1535                 LoggerWeakRef ref = node.loggerRef;
1536                 Logger logger = (ref == null) ? null : ref.get();
1537                 if (logger == null) {
1538                     node.walkAndSetParent(parent);
1539                 } else {
1540                     doSetParent(logger, parent);
1541                 }
1542             }
1543         }
1544     }
1545 
1546     // We use a subclass of Logger for the root logger, so
1547     // that we only instantiate the global handlers when they
1548     // are first needed.
1549     private final class RootLogger extends Logger {
1550         private RootLogger() {
1551             // We do not call the protected Logger two args constructor here,
1552             // to avoid calling LogManager.getLogManager() from within the
1553             // RootLogger constructor.
1554             super("", null, null, LogManager.this, true);
1555         }
1556 
1557         @Override
1558         public void log(LogRecord record) {
1559             // Make sure that the global handlers have been instantiated.
1560             initializeGlobalHandlers();
1561             super.log(record);
1562         }
1563 
1564         @Override
1565         public void addHandler(Handler h) {
1566             initializeGlobalHandlers();
1567             super.addHandler(h);
1568         }
1569 
1570         @Override
1571         public void removeHandler(Handler h) {
1572             initializeGlobalHandlers();
1573             super.removeHandler(h);
1574         }
1575 
1576         @Override
1577         Handler[] accessCheckedHandlers() {
1578             initializeGlobalHandlers();
1579             return super.accessCheckedHandlers();
1580         }
1581     }
1582 
1583 
1584     // Private method to be called when the configuration has
1585     // changed to apply any level settings to any pre-existing loggers.
1586     synchronized private void setLevelsOnExistingLoggers() {
1587         Enumeration<?> enum_ = props.propertyNames();
1588         while (enum_.hasMoreElements()) {
1589             String key = (String)enum_.nextElement();
1590             if (!key.endsWith(".level")) {
1591                 // Not a level definition.
1592                 continue;
1593             }
1594             int ix = key.length() - 6;
1595             String name = key.substring(0, ix);
1596             Level level = getLevelProperty(key, null);
1597             if (level == null) {
1598                 System.err.println("Bad level value for property: " + key);
1599                 continue;
1600             }
1601             for (LoggerContext cx : contexts()) {
1602                 Logger l = cx.findLogger(name);
1603                 if (l == null) {
1604                     continue;
1605                 }
1606                 l.setLevel(level);
1607             }
1608         }
1609     }
1610 
1611     // Management Support
1612     private static LoggingMXBean loggingMXBean = null;
1613     /**
1614      * String representation of the
1615      * {@link javax.management.ObjectName} for the management interface
1616      * for the logging facility.
1617      *
1618      * @see java.lang.management.PlatformLoggingMXBean
1619      * @see java.util.logging.LoggingMXBean
1620      *
1621      * @since 1.5
1622      */
1623     public final static String LOGGING_MXBEAN_NAME
1624         = "java.util.logging:type=Logging";
1625 
1626     /**
1627      * Returns <tt>LoggingMXBean</tt> for managing loggers.
1628      * An alternative way to manage loggers is through the
1629      * {@link java.lang.management.PlatformLoggingMXBean} interface
1630      * that can be obtained by calling:
1631      * <pre>
1632      *     PlatformLoggingMXBean logging = {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
1633      *         ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class);
1634      * </pre>
1635      *
1636      * @return a {@link LoggingMXBean} object.
1637      *
1638      * @see java.lang.management.PlatformLoggingMXBean
1639      * @since 1.5
1640      */
1641     public static synchronized LoggingMXBean getLoggingMXBean() {
1642         if (loggingMXBean == null) {
1643             loggingMXBean =  new Logging();
1644         }
1645         return loggingMXBean;
1646     }
1647 
1648     /**
1649      * Adds a configuration listener to be invoked each time the logging
1650      * configuration is read.
1651      * If the listener is already registered the method does nothing.
1652      * <p>
1653      * The listener is invoked with privileges that are restricted by the
1654      * calling context of this method.
1655      * The order in which the listeners are invoked is unspecified.
1656      * <p>
1657      * It is recommended that listeners do not throw errors or exceptions.
1658      *
1659      * If a listener terminates with an uncaught error or exception then
1660      * the first exception will be propagated to the caller of
1661      * {@link #readConfiguration()} (or {@link #readConfiguration(java.io.InputStream)})
1662      * after all listeners have been invoked.
1663      *
1664      * @implNote If more than one listener terminates with an uncaught error or
1665      * exception, an implementation may record the additional errors or
1666      * exceptions as {@linkplain Throwable#addSuppressed(java.lang.Throwable)
1667      * suppressed exceptions}.
1668      *
1669      * @param listener A configuration listener that will be invoked after the
1670      *        configuration changed.
1671      * @return This LogManager.
1672      * @throws SecurityException if a security manager exists and if the
1673      * caller does not have LoggingPermission("control").
1674      * @throws NullPointerException if the listener is null.
1675      *
1676      * @since 1.9
1677      */
1678     public LogManager addConfigurationListener(Runnable listener) {
1679         final Runnable r = Objects.requireNonNull(listener);
1680         checkPermission();
1681         final SecurityManager sm = System.getSecurityManager();
1682         final AccessControlContext acc =
1683                 sm == null ? null : AccessController.getContext();
1684         final PrivilegedAction<Void> pa =
1685                 acc == null ? null : () -> { r.run() ; return null; };
1686         final Runnable pr =
1687                 acc == null ? r : () -> AccessController.doPrivileged(pa, acc);
1688         // Will do nothing if already registered.
1689         listeners.putIfAbsent(r, pr);
1690         return this;
1691     }
1692 
1693     /**
1694      * Removes a previously registered configuration listener.
1695      *
1696      * Returns silently if the listener is not found.
1697      *
1698      * @param listener the configuration listener to remove.
1699      * @throws NullPointerException if the listener is null.
1700      * @throws SecurityException if a security manager exists and if the
1701      * caller does not have LoggingPermission("control").
1702      *
1703      * @since 1.9
1704      */
1705     public void removeConfigurationListener(Runnable listener) {
1706         final Runnable key = Objects.requireNonNull(listener);
1707         checkPermission();
1708         listeners.remove(key);
1709     }
1710 
1711     private void invokeConfigurationListeners() {
1712         Throwable t = null;
1713 
1714         // We're using an IdentityHashMap because we want to compare
1715         // keys using identity (==).
1716         // We don't want to loop within a block synchronized on 'listeners'
1717         // to avoid invoking listeners from yet another synchronized block.
1718         // So we're taking a snapshot of the values list to avoid the risk of
1719         // ConcurrentModificationException while looping.
1720         //
1721         for (Runnable c : listeners.values().toArray(new Runnable[0])) {
1722             try {
1723                 c.run();
1724             } catch (ThreadDeath death) {
1725                 throw death;
1726             } catch (Error | RuntimeException x) {
1727                 if (t == null) t = x;
1728                 else t.addSuppressed(x);
1729             }
1730         }
1731         // Listeners are not supposed to throw exceptions, but if that
1732         // happens, we will rethrow the first error or exception that is raised
1733         // after all listeners have been invoked.
1734         if (t instanceof Error) throw (Error)t;
1735         if (t instanceof RuntimeException) throw (RuntimeException)t;
1736     }
1737 
1738 }