1 /*
   2  * Copyright (c) 2000, 2017, 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 package java.util.logging;
  27 
  28 import java.io.*;
  29 import java.util.*;
  30 import java.security.*;
  31 import java.lang.ref.ReferenceQueue;
  32 import java.lang.ref.WeakReference;
  33 import java.util.concurrent.ConcurrentHashMap;
  34 import java.nio.file.Paths;
  35 import java.util.concurrent.CopyOnWriteArrayList;
  36 import java.util.concurrent.locks.ReentrantLock;
  37 import java.util.function.BiFunction;
  38 import java.util.function.Function;
  39 import java.util.function.Predicate;
  40 import java.util.stream.Collectors;
  41 import java.util.stream.Stream;
  42 import jdk.internal.misc.JavaAWTAccess;
  43 import jdk.internal.misc.SharedSecrets;
  44 import sun.util.logging.internal.LoggingProviderImpl;
  45 import static jdk.internal.logger.DefaultLoggerFinder.isSystem;
  46 
  47 /**
  48  * There is a single global LogManager object that is used to
  49  * maintain a set of shared state about Loggers and log services.
  50  * <p>
  51  * This LogManager object:
  52  * <ul>
  53  * <li> Manages a hierarchical namespace of Logger objects.  All
  54  *      named Loggers are stored in this namespace.
  55  * <li> Manages a set of logging control properties.  These are
  56  *      simple key-value pairs that can be used by Handlers and
  57  *      other logging objects to configure themselves.
  58  * </ul>
  59  * <p>
  60  * The global LogManager object can be retrieved using LogManager.getLogManager().
  61  * The LogManager object is created during class initialization and
  62  * cannot subsequently be changed.
  63  * <p>
  64  * At startup the LogManager class is located using the
  65  * java.util.logging.manager system property.
  66  *
  67  * <h3>LogManager Configuration</h3>
  68  *
  69  * A LogManager initializes the logging configuration via
  70  * the {@link #readConfiguration()} method during LogManager initialization.
  71  * By default, LogManager default configuration is used.
  72  * The logging configuration read by LogManager must be in the
  73  * {@linkplain Properties properties file} format.
  74  * <p>
  75  * The LogManager defines two optional system properties that allow control over
  76  * the initial configuration, as specified in the {@link #readConfiguration()}
  77  * method:
  78  * <ul>
  79  * <li>"java.util.logging.config.class"
  80  * <li>"java.util.logging.config.file"
  81  * </ul>
  82  * <p>
  83  * These two system properties may be specified on the command line to the "java"
  84  * command, or as system property definitions passed to JNI_CreateJavaVM.
  85  * <p>
  86  * The {@linkplain Properties properties} for loggers and Handlers will have
  87  * names starting with the dot-separated name for the handler or logger.<br>
  88  * The global logging properties may include:
  89  * <ul>
  90  * <li>A property "handlers".  This defines a whitespace or comma separated
  91  * list of class names for handler classes to load and register as
  92  * handlers on the root Logger (the Logger named "").  Each class
  93  * name must be for a Handler class which has a default constructor.
  94  * Note that these Handlers may be created lazily, when they are
  95  * first used.
  96  *
  97  * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
  98  * comma separated list of class names for handlers classes to
  99  * load and register as handlers to the specified logger. Each class
 100  * name must be for a Handler class which has a default constructor.
 101  * Note that these Handlers may be created lazily, when they are
 102  * first used.
 103  *
 104  * <li>A property "&lt;logger&gt;.handlers.ensureCloseOnReset". This defines a
 105  * a boolean value. If "&lt;logger&gt;.handlers" is not defined or is empty,
 106  * this property is ignored. Otherwise it defaults to {@code true}. When the
 107  * value is {@code true}, the handlers associated with the logger are guaranteed
 108  * to be closed on {@linkplain #reset} and shutdown. This can be turned off
 109  * by explicitly setting "&lt;logger&gt;.handlers.ensureCloseOnReset=false" in
 110  * the configuration. Note that turning this property off causes the risk of
 111  * introducing a resource leak, as the logger may get garbage collected before
 112  * {@code reset()} is called, thus preventing its handlers from being closed
 113  * on {@code reset()}. In that case it is the responsibility of the application
 114  * to ensure that the handlers are closed before the logger is garbage
 115  * collected.
 116  *
 117  * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
 118  * value. By default every logger calls its parent in addition to
 119  * handling the logging message itself, this often result in messages
 120  * being handled by the root logger as well. When setting this property
 121  * to false a Handler needs to be configured for this logger otherwise
 122  * no logging messages are delivered.
 123  *
 124  * <li>A property "config".  This property is intended to allow
 125  * arbitrary configuration code to be run.  The property defines a
 126  * whitespace or comma separated list of class names.  A new instance will be
 127  * created for each named class.  The default constructor of each class
 128  * may execute arbitrary code to update the logging configuration, such as
 129  * setting logger levels, adding handlers, adding filters, etc.
 130  * </ul>
 131  * <p>
 132  * Note that all classes loaded during LogManager configuration are
 133  * first searched on the system class path before any user class path.
 134  * That includes the LogManager class, any config classes, and any
 135  * handler classes.
 136  * <p>
 137  * Loggers are organized into a naming hierarchy based on their
 138  * dot separated names.  Thus "a.b.c" is a child of "a.b", but
 139  * "a.b1" and a.b2" are peers.
 140  * <p>
 141  * All properties whose names end with ".level" are assumed to define
 142  * log levels for Loggers.  Thus "foo.level" defines a log level for
 143  * the logger called "foo" and (recursively) for any of its children
 144  * in the naming hierarchy.  Log Levels are applied in the order they
 145  * are defined in the properties file.  Thus level settings for child
 146  * nodes in the tree should come after settings for their parents.
 147  * The property name ".level" can be used to set the level for the
 148  * root of the tree.
 149  * <p>
 150  * All methods on the LogManager object are multi-thread safe.
 151  *
 152  * @since 1.4
 153 */
 154 
 155 public class LogManager {
 156     // The global LogManager object
 157     private static final LogManager manager;
 158 
 159     // 'props' is assigned within a lock but accessed without it.
 160     // Declaring it volatile makes sure that another thread will not
 161     // be able to see a partially constructed 'props' object.
 162     // (seeing a partially constructed 'props' object can result in
 163     // NPE being thrown in Hashtable.get(), because it leaves the door
 164     // open for props.getProperties() to be called before the construcor
 165     // of Hashtable is actually completed).
 166     private volatile Properties props = new Properties();
 167     private final static Level defaultLevel = Level.INFO;
 168 
 169     // LoggerContext for system loggers and user loggers
 170     private final LoggerContext systemContext = new SystemLoggerContext();
 171     private final LoggerContext userContext = new LoggerContext();
 172     // non final field - make it volatile to make sure that other threads
 173     // will see the new value once ensureLogManagerInitialized() has finished
 174     // executing.
 175     private volatile Logger rootLogger;
 176     // Have we done the primordial reading of the configuration file?
 177     // (Must be done after a suitable amount of java.lang.System
 178     // initialization has been done)
 179     private volatile boolean readPrimordialConfiguration;
 180     // Have we initialized global (root) handlers yet?
 181     // This gets set to STATE_UNINITIALIZED in readConfiguration
 182     private static final int
 183             STATE_INITIALIZED = 0, // initial state
 184             STATE_INITIALIZING = 1,
 185             STATE_READING_CONFIG = 2,
 186             STATE_UNINITIALIZED = 3,
 187             STATE_SHUTDOWN = 4;    // terminal state
 188     private volatile int globalHandlersState; // = STATE_INITIALIZED;
 189     // A concurrency lock for reset(), readConfiguration() and Cleaner.
 190     private final ReentrantLock configurationLock = new ReentrantLock();
 191 
 192     // This list contains the loggers for which some handlers have been
 193     // explicitly configured in the configuration file.
 194     // It prevents these loggers from being arbitrarily garbage collected.
 195     private static final class CloseOnReset {
 196         private final Logger logger;
 197         private CloseOnReset(Logger ref) {
 198             this.logger = Objects.requireNonNull(ref);
 199         }
 200         @Override
 201         public boolean equals(Object other) {
 202             return (other instanceof CloseOnReset) && ((CloseOnReset)other).logger == logger;
 203         }
 204         @Override
 205         public int hashCode() {
 206             return System.identityHashCode(logger);
 207         }
 208         public Logger get() {
 209             return logger;
 210         }
 211         public static CloseOnReset create(Logger logger) {
 212             return new CloseOnReset(logger);
 213         }
 214     }
 215     private final CopyOnWriteArrayList<CloseOnReset> closeOnResetLoggers =
 216             new CopyOnWriteArrayList<>();
 217 
 218 
 219     private final Map<Object, Runnable> listeners =
 220             Collections.synchronizedMap(new IdentityHashMap<>());
 221 
 222     static {
 223         manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
 224             @Override
 225             public LogManager run() {
 226                 LogManager mgr = null;
 227                 String cname = null;
 228                 try {
 229                     cname = System.getProperty("java.util.logging.manager");
 230                     if (cname != null) {
 231                         try {
 232                             @SuppressWarnings("deprecation")
 233                             Object tmp = ClassLoader.getSystemClassLoader()
 234                                 .loadClass(cname).newInstance();
 235                             mgr = (LogManager) tmp;
 236                         } catch (ClassNotFoundException ex) {
 237                             @SuppressWarnings("deprecation")
 238                             Object tmp = Thread.currentThread()
 239                                 .getContextClassLoader().loadClass(cname).newInstance();
 240                             mgr = (LogManager) tmp;
 241                         }
 242                     }
 243                 } catch (Exception ex) {
 244                     System.err.println("Could not load Logmanager \"" + cname + "\"");
 245                     ex.printStackTrace();
 246                 }
 247                 if (mgr == null) {
 248                     mgr = new LogManager();
 249                 }
 250                 return mgr;
 251 
 252             }
 253         });
 254     }
 255 
 256     // This private class is used as a shutdown hook.
 257     // It does a "reset" to close all open handlers.
 258     private class Cleaner extends Thread {
 259 
 260         private Cleaner() {
 261             super(null, null, "Logging-Cleaner", 0, false);
 262             /* Set context class loader to null in order to avoid
 263              * keeping a strong reference to an application classloader.
 264              */
 265             this.setContextClassLoader(null);
 266         }
 267 
 268         @Override
 269         public void run() {
 270             // This is to ensure the LogManager.<clinit> is completed
 271             // before synchronized block. Otherwise deadlocks are possible.
 272             LogManager mgr = manager;
 273 
 274             // set globalHandlersState to STATE_SHUTDOWN atomically so that
 275             // no attempts are made to (re)initialize the handlers or (re)read
 276             // the configuration again. This is terminal state.
 277             configurationLock.lock();
 278             globalHandlersState = STATE_SHUTDOWN;
 279             configurationLock.unlock();
 280 
 281             // Do a reset to close all active handlers.
 282             reset();
 283         }
 284     }
 285 
 286 
 287     /**
 288      * Protected constructor.  This is protected so that container applications
 289      * (such as J2EE containers) can subclass the object.  It is non-public as
 290      * it is intended that there only be one LogManager object, whose value is
 291      * retrieved by calling LogManager.getLogManager.
 292      */
 293     protected LogManager() {
 294         this(checkSubclassPermissions());
 295     }
 296 
 297     private LogManager(Void checked) {
 298 
 299         // Add a shutdown hook to close the global handlers.
 300         try {
 301             Runtime.getRuntime().addShutdownHook(new Cleaner());
 302         } catch (IllegalStateException e) {
 303             // If the VM is already shutting down,
 304             // We do not need to register shutdownHook.
 305         }
 306     }
 307 
 308     private static Void checkSubclassPermissions() {
 309         final SecurityManager sm = System.getSecurityManager();
 310         if (sm != null) {
 311             // These permission will be checked in the LogManager constructor,
 312             // in order to register the Cleaner() thread as a shutdown hook.
 313             // Check them here to avoid the penalty of constructing the object
 314             // etc...
 315             sm.checkPermission(new RuntimePermission("shutdownHooks"));
 316             sm.checkPermission(new RuntimePermission("setContextClassLoader"));
 317         }
 318         return null;
 319     }
 320 
 321     /**
 322      * Lazy initialization: if this instance of manager is the global
 323      * manager then this method will read the initial configuration and
 324      * add the root logger and global logger by calling addLogger().
 325      *
 326      * Note that it is subtly different from what we do in LoggerContext.
 327      * In LoggerContext we're patching up the logger context tree in order to add
 328      * the root and global logger *to the context tree*.
 329      *
 330      * For this to work, addLogger() must have already have been called
 331      * once on the LogManager instance for the default logger being
 332      * added.
 333      *
 334      * This is why ensureLogManagerInitialized() needs to be called before
 335      * any logger is added to any logger context.
 336      *
 337      */
 338     private boolean initializedCalled = false;
 339     private volatile boolean initializationDone = false;
 340     final void ensureLogManagerInitialized() {
 341         final LogManager owner = this;
 342         if (initializationDone || owner != manager) {
 343             // we don't want to do this twice, and we don't want to do
 344             // this on private manager instances.
 345             return;
 346         }
 347 
 348         // Maybe another thread has called ensureLogManagerInitialized()
 349         // before us and is still executing it. If so we will block until
 350         // the log manager has finished initialized, then acquire the monitor,
 351         // notice that initializationDone is now true and return.
 352         // Otherwise - we have come here first! We will acquire the monitor,
 353         // see that initializationDone is still false, and perform the
 354         // initialization.
 355         //
 356         configurationLock.lock();
 357         try {
 358             // If initializedCalled is true it means that we're already in
 359             // the process of initializing the LogManager in this thread.
 360             // There has been a recursive call to ensureLogManagerInitialized().
 361             final boolean isRecursiveInitialization = (initializedCalled == true);
 362 
 363             assert initializedCalled || !initializationDone
 364                     : "Initialization can't be done if initialized has not been called!";
 365 
 366             if (isRecursiveInitialization || initializationDone) {
 367                 // If isRecursiveInitialization is true it means that we're
 368                 // already in the process of initializing the LogManager in
 369                 // this thread. There has been a recursive call to
 370                 // ensureLogManagerInitialized(). We should not proceed as
 371                 // it would lead to infinite recursion.
 372                 //
 373                 // If initializationDone is true then it means the manager
 374                 // has finished initializing; just return: we're done.
 375                 return;
 376             }
 377             // Calling addLogger below will in turn call requiresDefaultLogger()
 378             // which will call ensureLogManagerInitialized().
 379             // We use initializedCalled to break the recursion.
 380             initializedCalled = true;
 381             try {
 382                 AccessController.doPrivileged(new PrivilegedAction<Object>() {
 383                     @Override
 384                     public Object run() {
 385                         assert rootLogger == null;
 386                         assert initializedCalled && !initializationDone;
 387 
 388                         // create root logger before reading primordial
 389                         // configuration - to ensure that it will be added
 390                         // before the global logger, and not after.
 391                         final Logger root = owner.rootLogger = owner.new RootLogger();
 392 
 393                         // Read configuration.
 394                         owner.readPrimordialConfiguration();
 395 
 396                         // Create and retain Logger for the root of the namespace.
 397                         owner.addLogger(root);
 398 
 399                         // For backward compatibility: add any handlers configured using
 400                         // ".handlers"
 401                         owner.createLoggerHandlers("", ".handlers")
 402                                 .stream()
 403                                 .forEach(root::addHandler);
 404 
 405                         // Initialize level if not yet initialized
 406                         if (!root.isLevelInitialized()) {
 407                             root.setLevel(defaultLevel);
 408                         }
 409 
 410                         // Adding the global Logger.
 411                         // Do not call Logger.getGlobal() here as this might trigger
 412                         // subtle inter-dependency issues.
 413                         @SuppressWarnings("deprecation")
 414                         final Logger global = Logger.global;
 415 
 416                         // Make sure the global logger will be registered in the
 417                         // global manager
 418                         owner.addLogger(global);
 419                         return null;
 420                     }
 421                 });
 422             } finally {
 423                 initializationDone = true;
 424             }
 425         } finally {
 426             configurationLock.unlock();
 427         }
 428     }
 429 
 430     /**
 431      * Returns the global LogManager object.
 432      * @return the global LogManager object
 433      */
 434     public static LogManager getLogManager() {
 435         if (manager != null) {
 436             manager.ensureLogManagerInitialized();
 437         }
 438         return manager;
 439     }
 440 
 441     private void readPrimordialConfiguration() { // must be called while holding configurationLock
 442         if (!readPrimordialConfiguration) {
 443             // If System.in/out/err are null, it's a good
 444             // indication that we're still in the
 445             // bootstrapping phase
 446             if (System.out == null) {
 447                 return;
 448             }
 449             readPrimordialConfiguration = true;
 450             try {
 451                 readConfiguration();
 452 
 453                 // Platform loggers begin to delegate to java.util.logging.Logger
 454                 jdk.internal.logger.BootstrapLogger.redirectTemporaryLoggers();
 455 
 456             } catch (Exception ex) {
 457                 assert false : "Exception raised while reading logging configuration: " + ex;
 458             }
 459         }
 460     }
 461 
 462     // LoggerContext maps from AppContext
 463     private WeakHashMap<Object, LoggerContext> contextsMap = null;
 464 
 465     // Returns the LoggerContext for the user code (i.e. application or AppContext).
 466     // Loggers are isolated from each AppContext.
 467     private LoggerContext getUserContext() {
 468         LoggerContext context = null;
 469 
 470         SecurityManager sm = System.getSecurityManager();
 471         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
 472         if (sm != null && javaAwtAccess != null) {
 473             // for each applet, it has its own LoggerContext isolated from others
 474             final Object ecx = javaAwtAccess.getAppletContext();
 475             if (ecx != null) {
 476                 synchronized (javaAwtAccess) {
 477                     // find the AppContext of the applet code
 478                     // will be null if we are in the main app context.
 479                     if (contextsMap == null) {
 480                         contextsMap = new WeakHashMap<>();
 481                     }
 482                     context = contextsMap.get(ecx);
 483                     if (context == null) {
 484                         // Create a new LoggerContext for the applet.
 485                         context = new LoggerContext();
 486                         contextsMap.put(ecx, context);
 487                     }
 488                 }
 489             }
 490         }
 491         // for standalone app, return userContext
 492         return context != null ? context : userContext;
 493     }
 494 
 495     // The system context.
 496     final LoggerContext getSystemContext() {
 497         return systemContext;
 498     }
 499 
 500     private List<LoggerContext> contexts() {
 501         List<LoggerContext> cxs = new ArrayList<>();
 502         cxs.add(getSystemContext());
 503         cxs.add(getUserContext());
 504         return cxs;
 505     }
 506 
 507     // Find or create a specified logger instance. If a logger has
 508     // already been created with the given name it is returned.
 509     // Otherwise a new logger instance is created and registered
 510     // in the LogManager global namespace.
 511     // This method will always return a non-null Logger object.
 512     // Synchronization is not required here. All synchronization for
 513     // adding a new Logger object is handled by addLogger().
 514     //
 515     // This method must delegate to the LogManager implementation to
 516     // add a new Logger or return the one that has been added previously
 517     // as a LogManager subclass may override the addLogger, getLogger,
 518     // readConfiguration, and other methods.
 519     Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
 520         final Module module = caller == null ? null : caller.getModule();
 521         return demandLogger(name, resourceBundleName, module);
 522     }
 523 
 524     Logger demandLogger(String name, String resourceBundleName, Module module) {
 525         Logger result = getLogger(name);
 526         if (result == null) {
 527             // only allocate the new logger once
 528             Logger newLogger = new Logger(name, resourceBundleName,
 529                                           module, this, false);
 530             do {
 531                 if (addLogger(newLogger)) {
 532                     // We successfully added the new Logger that we
 533                     // created above so return it without refetching.
 534                     return newLogger;
 535                 }
 536 
 537                 // We didn't add the new Logger that we created above
 538                 // because another thread added a Logger with the same
 539                 // name after our null check above and before our call
 540                 // to addLogger(). We have to refetch the Logger because
 541                 // addLogger() returns a boolean instead of the Logger
 542                 // reference itself. However, if the thread that created
 543                 // the other Logger is not holding a strong reference to
 544                 // the other Logger, then it is possible for the other
 545                 // Logger to be GC'ed after we saw it in addLogger() and
 546                 // before we can refetch it. If it has been GC'ed then
 547                 // we'll just loop around and try again.
 548                 result = getLogger(name);
 549             } while (result == null);
 550         }
 551         return result;
 552     }
 553 
 554     Logger demandSystemLogger(String name, String resourceBundleName, Class<?> caller) {
 555         final Module module = caller == null ? null : caller.getModule();
 556         return demandSystemLogger(name, resourceBundleName, module);
 557     }
 558 
 559     Logger demandSystemLogger(String name, String resourceBundleName, Module module) {
 560         // Add a system logger in the system context's namespace
 561         final Logger sysLogger = getSystemContext()
 562                 .demandLogger(name, resourceBundleName, module);
 563 
 564         // Add the system logger to the LogManager's namespace if not exist
 565         // so that there is only one single logger of the given name.
 566         // System loggers are visible to applications unless a logger of
 567         // the same name has been added.
 568         Logger logger;
 569         do {
 570             // First attempt to call addLogger instead of getLogger
 571             // This would avoid potential bug in custom LogManager.getLogger
 572             // implementation that adds a logger if does not exist
 573             if (addLogger(sysLogger)) {
 574                 // successfully added the new system logger
 575                 logger = sysLogger;
 576             } else {
 577                 logger = getLogger(name);
 578             }
 579         } while (logger == null);
 580 
 581         // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
 582         if (logger != sysLogger) {
 583             // if logger already exists we merge the two logger configurations.
 584             final Logger l = logger;
 585             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 586                 @Override
 587                 public Void run() {
 588                     l.mergeWithSystemLogger(sysLogger);
 589                     return null;
 590                 }
 591             });
 592         }
 593         return sysLogger;
 594     }
 595 
 596     // LoggerContext maintains the logger namespace per context.
 597     // The default LogManager implementation has one system context and user
 598     // context.  The system context is used to maintain the namespace for
 599     // all system loggers and is queried by the system code.  If a system logger
 600     // doesn't exist in the user context, it'll also be added to the user context.
 601     // The user context is queried by the user code and all other loggers are
 602     // added in the user context.
 603     class LoggerContext {
 604         // Table of named Loggers that maps names to Loggers.
 605         private final ConcurrentHashMap<String,LoggerWeakRef> namedLoggers =
 606                 new ConcurrentHashMap<>();
 607         // Tree of named Loggers
 608         private final LogNode root;
 609         private LoggerContext() {
 610             this.root = new LogNode(null, this);
 611         }
 612 
 613 
 614         // Tells whether default loggers are required in this context.
 615         // If true, the default loggers will be lazily added.
 616         final boolean requiresDefaultLoggers() {
 617             final boolean requiresDefaultLoggers = (getOwner() == manager);
 618             if (requiresDefaultLoggers) {
 619                 getOwner().ensureLogManagerInitialized();
 620             }
 621             return requiresDefaultLoggers;
 622         }
 623 
 624         // This context's LogManager.
 625         final LogManager getOwner() {
 626             return LogManager.this;
 627         }
 628 
 629         // This context owner's root logger, which if not null, and if
 630         // the context requires default loggers, will be added to the context
 631         // logger's tree.
 632         final Logger getRootLogger() {
 633             return getOwner().rootLogger;
 634         }
 635 
 636         // The global logger, which if not null, and if
 637         // the context requires default loggers, will be added to the context
 638         // logger's tree.
 639         final Logger getGlobalLogger() {
 640             @SuppressWarnings("deprecation") // avoids initialization cycles.
 641             final Logger global = Logger.global;
 642             return global;
 643         }
 644 
 645         Logger demandLogger(String name, String resourceBundleName, Module module) {
 646             // a LogManager subclass may have its own implementation to add and
 647             // get a Logger.  So delegate to the LogManager to do the work.
 648             final LogManager owner = getOwner();
 649             return owner.demandLogger(name, resourceBundleName, module);
 650         }
 651 
 652 
 653         // Due to subtle deadlock issues getUserContext() no longer
 654         // calls addLocalLogger(rootLogger);
 655         // Therefore - we need to add the default loggers later on.
 656         // Checks that the context is properly initialized
 657         // This is necessary before calling e.g. find(name)
 658         // or getLoggerNames()
 659         //
 660         private void ensureInitialized() {
 661             if (requiresDefaultLoggers()) {
 662                 // Ensure that the root and global loggers are set.
 663                 ensureDefaultLogger(getRootLogger());
 664                 ensureDefaultLogger(getGlobalLogger());
 665             }
 666         }
 667 
 668 
 669         Logger findLogger(String name) {
 670             // Attempt to find logger without locking.
 671             LoggerWeakRef ref = namedLoggers.get(name);
 672             Logger logger = ref == null ? null : ref.get();
 673 
 674             // if logger is not null, then we can return it right away.
 675             // if name is "" or "global" and logger is null
 676             // we need to fall through and check that this context is
 677             // initialized.
 678             // if ref is not null and logger is null we also need to
 679             // fall through.
 680             if (logger != null || (ref == null && !name.isEmpty()
 681                     && !name.equals(Logger.GLOBAL_LOGGER_NAME))) {
 682                 return logger;
 683             }
 684 
 685             // We either found a stale reference, or we were looking for
 686             // "" or "global" and didn't find them.
 687             // Make sure context is initialized (has the default loggers),
 688             // and look up again, cleaning the stale reference if it hasn't
 689             // been cleaned up in between. All this needs to be done inside
 690             // a synchronized block.
 691             synchronized(this) {
 692                 // ensure that this context is properly initialized before
 693                 // looking for loggers.
 694                 ensureInitialized();
 695                 ref = namedLoggers.get(name);
 696                 if (ref == null) {
 697                     return null;
 698                 }
 699                 logger = ref.get();
 700                 if (logger == null) {
 701                     // The namedLoggers map holds stale weak reference
 702                     // to a logger which has been GC-ed.
 703                     ref.dispose();
 704                 }
 705                 return logger;
 706             }
 707         }
 708 
 709         // This method is called before adding a logger to the
 710         // context.
 711         // 'logger' is the context that will be added.
 712         // This method will ensure that the defaults loggers are added
 713         // before adding 'logger'.
 714         //
 715         private void ensureAllDefaultLoggers(Logger logger) {
 716             if (requiresDefaultLoggers()) {
 717                 final String name = logger.getName();
 718                 if (!name.isEmpty()) {
 719                     ensureDefaultLogger(getRootLogger());
 720                     if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
 721                         ensureDefaultLogger(getGlobalLogger());
 722                     }
 723                 }
 724             }
 725         }
 726 
 727         private void ensureDefaultLogger(Logger logger) {
 728             // Used for lazy addition of root logger and global logger
 729             // to a LoggerContext.
 730 
 731             // This check is simple sanity: we do not want that this
 732             // method be called for anything else than Logger.global
 733             // or owner.rootLogger.
 734             if (!requiresDefaultLoggers() || logger == null
 735                     || logger != getGlobalLogger() && logger != LogManager.this.rootLogger ) {
 736 
 737                 // the case where we have a non null logger which is neither
 738                 // Logger.global nor manager.rootLogger indicates a serious
 739                 // issue - as ensureDefaultLogger should never be called
 740                 // with any other loggers than one of these two (or null - if
 741                 // e.g manager.rootLogger is not yet initialized)...
 742                 assert logger == null;
 743 
 744                 return;
 745             }
 746 
 747             // Adds the logger if it's not already there.
 748             if (!namedLoggers.containsKey(logger.getName())) {
 749                 // It is important to prevent addLocalLogger to
 750                 // call ensureAllDefaultLoggers when we're in the process
 751                 // off adding one of those default loggers - as this would
 752                 // immediately cause a stack overflow.
 753                 // Therefore we must pass addDefaultLoggersIfNeeded=false,
 754                 // even if requiresDefaultLoggers is true.
 755                 addLocalLogger(logger, false);
 756             }
 757         }
 758 
 759         boolean addLocalLogger(Logger logger) {
 760             // no need to add default loggers if it's not required
 761             return addLocalLogger(logger, requiresDefaultLoggers());
 762         }
 763 
 764         // Add a logger to this context.  This method will only set its level
 765         // and process parent loggers.  It doesn't set its handlers.
 766         synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
 767             // addDefaultLoggersIfNeeded serves to break recursion when adding
 768             // default loggers. If we're adding one of the default loggers
 769             // (we're being called from ensureDefaultLogger()) then
 770             // addDefaultLoggersIfNeeded will be false: we don't want to
 771             // call ensureAllDefaultLoggers again.
 772             //
 773             // Note: addDefaultLoggersIfNeeded can also be false when
 774             //       requiresDefaultLoggers is false - since calling
 775             //       ensureAllDefaultLoggers would have no effect in this case.
 776             if (addDefaultLoggersIfNeeded) {
 777                 ensureAllDefaultLoggers(logger);
 778             }
 779 
 780             final String name = logger.getName();
 781             if (name == null) {
 782                 throw new NullPointerException();
 783             }
 784             LoggerWeakRef ref = namedLoggers.get(name);
 785             if (ref != null) {
 786                 if (ref.get() == null) {
 787                     // It's possible that the Logger was GC'ed after a
 788                     // drainLoggerRefQueueBounded() call above so allow
 789                     // a new one to be registered.
 790                     ref.dispose();
 791                 } else {
 792                     // We already have a registered logger with the given name.
 793                     return false;
 794                 }
 795             }
 796 
 797             // We're adding a new logger.
 798             // Note that we are creating a weak reference here.
 799             final LogManager owner = getOwner();
 800             logger.setLogManager(owner);
 801             ref = owner.new LoggerWeakRef(logger);
 802 
 803             // Apply any initial level defined for the new logger, unless
 804             // the logger's level is already initialized
 805             Level level = owner.getLevelProperty(name + ".level", null);
 806             if (level != null && !logger.isLevelInitialized()) {
 807                 doSetLevel(logger, level);
 808             }
 809 
 810             // instantiation of the handler is done in the LogManager.addLogger
 811             // implementation as a handler class may be only visible to LogManager
 812             // subclass for the custom log manager case
 813             processParentHandlers(logger, name, VisitedLoggers.NEVER);
 814 
 815             // Find the new node and its parent.
 816             LogNode node = getNode(name);
 817             node.loggerRef = ref;
 818             Logger parent = null;
 819             LogNode nodep = node.parent;
 820             while (nodep != null) {
 821                 LoggerWeakRef nodeRef = nodep.loggerRef;
 822                 if (nodeRef != null) {
 823                     parent = nodeRef.get();
 824                     if (parent != null) {
 825                         break;
 826                     }
 827                 }
 828                 nodep = nodep.parent;
 829             }
 830 
 831             if (parent != null) {
 832                 doSetParent(logger, parent);
 833             }
 834             // Walk over the children and tell them we are their new parent.
 835             node.walkAndSetParent(logger);
 836             // new LogNode is ready so tell the LoggerWeakRef about it
 837             ref.setNode(node);
 838 
 839             // Do not publish 'ref' in namedLoggers before the logger tree
 840             // is fully updated - because the named logger will be visible as
 841             // soon as it is published in namedLoggers (findLogger takes
 842             // benefit of the ConcurrentHashMap implementation of namedLoggers
 843             // to avoid synchronizing on retrieval when that is possible).
 844             namedLoggers.put(name, ref);
 845             return true;
 846         }
 847 
 848         void removeLoggerRef(String name, LoggerWeakRef ref) {
 849             namedLoggers.remove(name, ref);
 850         }
 851 
 852         synchronized Enumeration<String> getLoggerNames() {
 853             // ensure that this context is properly initialized before
 854             // returning logger names.
 855             ensureInitialized();
 856             return Collections.enumeration(namedLoggers.keySet());
 857         }
 858 
 859         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 860         // parents have levels or handlers defined, make sure they are instantiated.
 861         private void processParentHandlers(final Logger logger, final String name,
 862                Predicate<Logger> visited) {
 863             final LogManager owner = getOwner();
 864             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 865                 @Override
 866                 public Void run() {
 867                     if (logger != owner.rootLogger) {
 868                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
 869                         if (!useParent) {
 870                             logger.setUseParentHandlers(false);
 871                         }
 872                     }
 873                     return null;
 874                 }
 875             });
 876 
 877             int ix = 1;
 878             for (;;) {
 879                 int ix2 = name.indexOf('.', ix);
 880                 if (ix2 < 0) {
 881                     break;
 882                 }
 883                 String pname = name.substring(0, ix2);
 884                 if (owner.getProperty(pname + ".level") != null ||
 885                     owner.getProperty(pname + ".handlers") != null) {
 886                     // This pname has a level/handlers definition.
 887                     // Make sure it exists.
 888                     if (visited.test(demandLogger(pname, null, null))) {
 889                         break;
 890                     }
 891                 }
 892                 ix = ix2+1;
 893             }
 894         }
 895 
 896         // Gets a node in our tree of logger nodes.
 897         // If necessary, create it.
 898         LogNode getNode(String name) {
 899             if (name == null || name.equals("")) {
 900                 return root;
 901             }
 902             LogNode node = root;
 903             while (name.length() > 0) {
 904                 int ix = name.indexOf('.');
 905                 String head;
 906                 if (ix > 0) {
 907                     head = name.substring(0, ix);
 908                     name = name.substring(ix + 1);
 909                 } else {
 910                     head = name;
 911                     name = "";
 912                 }
 913                 if (node.children == null) {
 914                     node.children = new HashMap<>();
 915                 }
 916                 LogNode child = node.children.get(head);
 917                 if (child == null) {
 918                     child = new LogNode(node, this);
 919                     node.children.put(head, child);
 920                 }
 921                 node = child;
 922             }
 923             return node;
 924         }
 925     }
 926 
 927     final class SystemLoggerContext extends LoggerContext {
 928         // Add a system logger in the system context's namespace as well as
 929         // in the LogManager's namespace if not exist so that there is only
 930         // one single logger of the given name.  System loggers are visible
 931         // to applications unless a logger of the same name has been added.
 932         @Override
 933         Logger demandLogger(String name, String resourceBundleName,
 934                             Module module) {
 935             Logger result = findLogger(name);
 936             if (result == null) {
 937                 // only allocate the new system logger once
 938                 Logger newLogger = new Logger(name, resourceBundleName,
 939                                               module, getOwner(), true);
 940                 do {
 941                     if (addLocalLogger(newLogger)) {
 942                         // We successfully added the new Logger that we
 943                         // created above so return it without refetching.
 944                         result = newLogger;
 945                     } else {
 946                         // We didn't add the new Logger that we created above
 947                         // because another thread added a Logger with the same
 948                         // name after our null check above and before our call
 949                         // to addLogger(). We have to refetch the Logger because
 950                         // addLogger() returns a boolean instead of the Logger
 951                         // reference itself. However, if the thread that created
 952                         // the other Logger is not holding a strong reference to
 953                         // the other Logger, then it is possible for the other
 954                         // Logger to be GC'ed after we saw it in addLogger() and
 955                         // before we can refetch it. If it has been GC'ed then
 956                         // we'll just loop around and try again.
 957                         result = findLogger(name);
 958                     }
 959                 } while (result == null);
 960             }
 961             return result;
 962         }
 963     }
 964 
 965     // Add new per logger handlers.
 966     // We need to raise privilege here. All our decisions will
 967     // be made based on the logging configuration, which can
 968     // only be modified by trusted code.
 969     private void loadLoggerHandlers(final Logger logger, final String name,
 970                                     final String handlersPropertyName)
 971     {
 972         AccessController.doPrivileged(new PrivilegedAction<Void>() {
 973             @Override
 974             public Void run() {
 975                 setLoggerHandlers(logger, name, handlersPropertyName,
 976                     createLoggerHandlers(name, handlersPropertyName));
 977                 return null;
 978             }
 979         });
 980     }
 981 
 982     private void setLoggerHandlers(final Logger logger, final String name,
 983                                    final String handlersPropertyName,
 984                                    List<Handler> handlers)
 985     {
 986         final boolean ensureCloseOnReset = ! handlers.isEmpty()
 987                     && getBooleanProperty(handlersPropertyName + ".ensureCloseOnReset",true);
 988         int count = 0;
 989         for (Handler hdl : handlers) {
 990             logger.addHandler(hdl);
 991             if (++count == 1 && ensureCloseOnReset) {
 992                 // add this logger to the closeOnResetLoggers list.
 993                 closeOnResetLoggers.addIfAbsent(CloseOnReset.create(logger));
 994             }
 995         }
 996     }
 997 
 998     private List<Handler> createLoggerHandlers(final String name, final String handlersPropertyName)
 999     {
1000         String names[] = parseClassNames(handlersPropertyName);
1001         List<Handler> handlers = new ArrayList<>(names.length);
1002         for (String type : names) {
1003             try {
1004                 @SuppressWarnings("deprecation")
1005                 Object o = ClassLoader.getSystemClassLoader().loadClass(type).newInstance();
1006                 Handler hdl = (Handler) o;
1007                 // Check if there is a property defining the
1008                 // this handler's level.
1009                 String levs = getProperty(type + ".level");
1010                 if (levs != null) {
1011                     Level l = Level.findLevel(levs);
1012                     if (l != null) {
1013                         hdl.setLevel(l);
1014                     } else {
1015                         // Probably a bad level. Drop through.
1016                         System.err.println("Can't set level for " + type);
1017                     }
1018                 }
1019                 // Add this Handler to the logger
1020                 handlers.add(hdl);
1021             } catch (Exception ex) {
1022                 System.err.println("Can't load log handler \"" + type + "\"");
1023                 System.err.println("" + ex);
1024                 ex.printStackTrace();
1025             }
1026         }
1027 
1028         return handlers;
1029     }
1030 
1031 
1032     // loggerRefQueue holds LoggerWeakRef objects for Logger objects
1033     // that have been GC'ed.
1034     private final ReferenceQueue<Logger> loggerRefQueue
1035         = new ReferenceQueue<>();
1036 
1037     // Package-level inner class.
1038     // Helper class for managing WeakReferences to Logger objects.
1039     //
1040     // LogManager.namedLoggers
1041     //     - has weak references to all named Loggers
1042     //     - namedLoggers keeps the LoggerWeakRef objects for the named
1043     //       Loggers around until we can deal with the book keeping for
1044     //       the named Logger that is being GC'ed.
1045     // LogManager.LogNode.loggerRef
1046     //     - has a weak reference to a named Logger
1047     //     - the LogNode will also keep the LoggerWeakRef objects for
1048     //       the named Loggers around; currently LogNodes never go away.
1049     // Logger.kids
1050     //     - has a weak reference to each direct child Logger; this
1051     //       includes anonymous and named Loggers
1052     //     - anonymous Loggers are always children of the rootLogger
1053     //       which is a strong reference; rootLogger.kids keeps the
1054     //       LoggerWeakRef objects for the anonymous Loggers around
1055     //       until we can deal with the book keeping.
1056     //
1057     final class LoggerWeakRef extends WeakReference<Logger> {
1058         private String                name;       // for namedLoggers cleanup
1059         private LogNode               node;       // for loggerRef cleanup
1060         private WeakReference<Logger> parentRef;  // for kids cleanup
1061         private boolean disposed = false;         // avoid calling dispose twice
1062 
1063         LoggerWeakRef(Logger logger) {
1064             super(logger, loggerRefQueue);
1065 
1066             name = logger.getName();  // save for namedLoggers cleanup
1067         }
1068 
1069         // dispose of this LoggerWeakRef object
1070         void dispose() {
1071             // Avoid calling dispose twice. When a Logger is gc'ed, its
1072             // LoggerWeakRef will be enqueued.
1073             // However, a new logger of the same name may be added (or looked
1074             // up) before the queue is drained. When that happens, dispose()
1075             // will be called by addLocalLogger() or findLogger().
1076             // Later when the queue is drained, dispose() will be called again
1077             // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed
1078             // avoids processing the data twice (even though the code should
1079             // now be reentrant).
1080             synchronized(this) {
1081                 // Note to maintainers:
1082                 // Be careful not to call any method that tries to acquire
1083                 // another lock from within this block - as this would surely
1084                 // lead to deadlocks, given that dispose() can be called by
1085                 // multiple threads, and from within different synchronized
1086                 // methods/blocks.
1087                 if (disposed) return;
1088                 disposed = true;
1089             }
1090 
1091             final LogNode n = node;
1092             if (n != null) {
1093                 // n.loggerRef can only be safely modified from within
1094                 // a lock on LoggerContext. removeLoggerRef is already
1095                 // synchronized on LoggerContext so calling
1096                 // n.context.removeLoggerRef from within this lock is safe.
1097                 synchronized (n.context) {
1098                     // if we have a LogNode, then we were a named Logger
1099                     // so clear namedLoggers weak ref to us
1100                     n.context.removeLoggerRef(name, this);
1101                     name = null;  // clear our ref to the Logger's name
1102 
1103                     // LogNode may have been reused - so only clear
1104                     // LogNode.loggerRef if LogNode.loggerRef == this
1105                     if (n.loggerRef == this) {
1106                         n.loggerRef = null;  // clear LogNode's weak ref to us
1107                     }
1108                     node = null;            // clear our ref to LogNode
1109                 }
1110             }
1111 
1112             if (parentRef != null) {
1113                 // this LoggerWeakRef has or had a parent Logger
1114                 Logger parent = parentRef.get();
1115                 if (parent != null) {
1116                     // the parent Logger is still there so clear the
1117                     // parent Logger's weak ref to us
1118                     parent.removeChildLogger(this);
1119                 }
1120                 parentRef = null;  // clear our weak ref to the parent Logger
1121             }
1122         }
1123 
1124         // set the node field to the specified value
1125         void setNode(LogNode node) {
1126             this.node = node;
1127         }
1128 
1129         // set the parentRef field to the specified value
1130         void setParentRef(WeakReference<Logger> parentRef) {
1131             this.parentRef = parentRef;
1132         }
1133     }
1134 
1135     // Package-level method.
1136     // Drain some Logger objects that have been GC'ed.
1137     //
1138     // drainLoggerRefQueueBounded() is called by addLogger() below
1139     // and by Logger.getAnonymousLogger(String) so we'll drain up to
1140     // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
1141     //
1142     // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
1143     // us about a 50/50 mix in increased weak ref counts versus
1144     // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
1145     // Here are stats for cleaning up sets of 400 anonymous Loggers:
1146     //   - test duration 1 minute
1147     //   - sample size of 125 sets of 400
1148     //   - average: 1.99 ms
1149     //   - minimum: 0.57 ms
1150     //   - maximum: 25.3 ms
1151     //
1152     // The same config gives us a better decreased weak ref count
1153     // than increased weak ref count in the LoggerWeakRefLeak test.
1154     // Here are stats for cleaning up sets of 400 named Loggers:
1155     //   - test duration 2 minutes
1156     //   - sample size of 506 sets of 400
1157     //   - average: 0.57 ms
1158     //   - minimum: 0.02 ms
1159     //   - maximum: 10.9 ms
1160     //
1161     private final static int MAX_ITERATIONS = 400;
1162     final void drainLoggerRefQueueBounded() {
1163         for (int i = 0; i < MAX_ITERATIONS; i++) {
1164             if (loggerRefQueue == null) {
1165                 // haven't finished loading LogManager yet
1166                 break;
1167             }
1168 
1169             LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
1170             if (ref == null) {
1171                 break;
1172             }
1173             // a Logger object has been GC'ed so clean it up
1174             ref.dispose();
1175         }
1176     }
1177 
1178     /**
1179      * Add a named logger.  This does nothing and returns false if a logger
1180      * with the same name is already registered.
1181      * <p>
1182      * The Logger factory methods call this method to register each
1183      * newly created Logger.
1184      * <p>
1185      * The application should retain its own reference to the Logger
1186      * object to avoid it being garbage collected.  The LogManager
1187      * may only retain a weak reference.
1188      *
1189      * @param   logger the new logger.
1190      * @return  true if the argument logger was registered successfully,
1191      *          false if a logger of that name already exists.
1192      * @exception NullPointerException if the logger name is null.
1193      */
1194     public boolean addLogger(Logger logger) {
1195         final String name = logger.getName();
1196         if (name == null) {
1197             throw new NullPointerException();
1198         }
1199         drainLoggerRefQueueBounded();
1200         LoggerContext cx = getUserContext();
1201         if (cx.addLocalLogger(logger)) {
1202             // Do we have a per logger handler too?
1203             // Note: this will add a 200ms penalty
1204             loadLoggerHandlers(logger, name, name + ".handlers");
1205             return true;
1206         } else {
1207             return false;
1208         }
1209     }
1210 
1211     // Private method to set a level on a logger.
1212     // If necessary, we raise privilege before doing the call.
1213     private static void doSetLevel(final Logger logger, final Level level) {
1214         SecurityManager sm = System.getSecurityManager();
1215         if (sm == null) {
1216             // There is no security manager, so things are easy.
1217             logger.setLevel(level);
1218             return;
1219         }
1220         // There is a security manager.  Raise privilege before
1221         // calling setLevel.
1222         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1223             @Override
1224             public Object run() {
1225                 logger.setLevel(level);
1226                 return null;
1227             }});
1228     }
1229 
1230     // Private method to set a parent on a logger.
1231     // If necessary, we raise privilege before doing the setParent call.
1232     private static void doSetParent(final Logger logger, final Logger parent) {
1233         SecurityManager sm = System.getSecurityManager();
1234         if (sm == null) {
1235             // There is no security manager, so things are easy.
1236             logger.setParent(parent);
1237             return;
1238         }
1239         // There is a security manager.  Raise privilege before
1240         // calling setParent.
1241         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1242             @Override
1243             public Object run() {
1244                 logger.setParent(parent);
1245                 return null;
1246             }});
1247     }
1248 
1249     /**
1250      * Method to find a named logger.
1251      * <p>
1252      * Note that since untrusted code may create loggers with
1253      * arbitrary names this method should not be relied on to
1254      * find Loggers for security sensitive logging.
1255      * It is also important to note that the Logger associated with the
1256      * String {@code name} may be garbage collected at any time if there
1257      * is no strong reference to the Logger. The caller of this method
1258      * must check the return value for null in order to properly handle
1259      * the case where the Logger has been garbage collected.
1260      *
1261      * @param name name of the logger
1262      * @return  matching logger or null if none is found
1263      */
1264     public Logger getLogger(String name) {
1265         return getUserContext().findLogger(name);
1266     }
1267 
1268     /**
1269      * Get an enumeration of known logger names.
1270      * <p>
1271      * Note:  Loggers may be added dynamically as new classes are loaded.
1272      * This method only reports on the loggers that are currently registered.
1273      * It is also important to note that this method only returns the name
1274      * of a Logger, not a strong reference to the Logger itself.
1275      * The returned String does nothing to prevent the Logger from being
1276      * garbage collected. In particular, if the returned name is passed
1277      * to {@code LogManager.getLogger()}, then the caller must check the
1278      * return value from {@code LogManager.getLogger()} for null to properly
1279      * handle the case where the Logger has been garbage collected in the
1280      * time since its name was returned by this method.
1281      *
1282      * @return  enumeration of logger name strings
1283      */
1284     public Enumeration<String> getLoggerNames() {
1285         return getUserContext().getLoggerNames();
1286     }
1287 
1288     /**
1289      * Reads and initializes the logging configuration.
1290      * <p>
1291      * If the "java.util.logging.config.class" system property is set, then the
1292      * property value is treated as a class name.  The given class will be
1293      * loaded, an object will be instantiated, and that object's constructor
1294      * is responsible for reading in the initial configuration.  (That object
1295      * may use other system properties to control its configuration.)  The
1296      * alternate configuration class can use {@code readConfiguration(InputStream)}
1297      * to define properties in the LogManager.
1298      * <p>
1299      * If "java.util.logging.config.class" system property is <b>not</b> set,
1300      * then this method will read the initial configuration from a properties
1301      * file and calls the {@link #readConfiguration(InputStream)} method to initialize
1302      * the configuration. The "java.util.logging.config.file" system property can be used
1303      * to specify the properties file that will be read as the initial configuration;
1304      * if not set, then the LogManager default configuration is used.
1305      * The default configuration is typically loaded from the
1306      * properties file "{@code conf/logging.properties}" in the Java installation
1307      * directory.
1308      *
1309      * <p>
1310      * Any {@linkplain #addConfigurationListener registered configuration
1311      * listener} will be invoked after the properties are read.
1312      *
1313      * @apiNote This {@code readConfiguration} method should only be used for
1314      * initializing the configuration during LogManager initialization or
1315      * used with the "java.util.logging.config.class" property.
1316      * When this method is called after loggers have been created, and
1317      * the "java.util.logging.config.class" system property is not set, all
1318      * existing loggers will be {@linkplain #reset() reset}. Then any
1319      * existing loggers that have a level property specified in the new
1320      * configuration stream will be {@linkplain
1321      * Logger#setLevel(java.util.logging.Level) set} to the specified log level.
1322      * <p>
1323      * To properly update the logging configuration, use the
1324      * {@link #updateConfiguration(java.util.function.Function)} or
1325      * {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)}
1326      * methods instead.
1327      *
1328      * @throws   SecurityException  if a security manager exists and if
1329      *              the caller does not have LoggingPermission("control").
1330      * @throws   IOException if there are IO problems reading the configuration.
1331      */
1332     public void readConfiguration() throws IOException, SecurityException {
1333         checkPermission();
1334 
1335         // if a configuration class is specified, load it and use it.
1336         String cname = System.getProperty("java.util.logging.config.class");
1337         if (cname != null) {
1338             try {
1339                 // Instantiate the named class.  It is its constructor's
1340                 // responsibility to initialize the logging configuration, by
1341                 // calling readConfiguration(InputStream) with a suitable stream.
1342                 try {
1343                     Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
1344                     @SuppressWarnings("deprecation")
1345                     Object witness = clz.newInstance();
1346                     return;
1347                 } catch (ClassNotFoundException ex) {
1348                     Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
1349                     @SuppressWarnings("deprecation")
1350                     Object witness = clz.newInstance();
1351                     return;
1352                 }
1353             } catch (Exception ex) {
1354                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1355                 System.err.println("" + ex);
1356                 // keep going and useful config file.
1357             }
1358         }
1359 
1360         String fname = getConfigurationFileName();
1361         try (final InputStream in = new FileInputStream(fname)) {
1362             final BufferedInputStream bin = new BufferedInputStream(in);
1363             readConfiguration(bin);
1364         }
1365     }
1366 
1367     String getConfigurationFileName() throws IOException {
1368         String fname = System.getProperty("java.util.logging.config.file");
1369         if (fname == null) {
1370             fname = System.getProperty("java.home");
1371             if (fname == null) {
1372                 throw new Error("Can't find java.home ??");
1373             }
1374             fname = Paths.get(fname, "conf", "logging.properties")
1375                     .toAbsolutePath().normalize().toString();
1376         }
1377         return fname;
1378     }
1379 
1380     /**
1381      * Reset the logging configuration.
1382      * <p>
1383      * For all named loggers, the reset operation removes and closes
1384      * all Handlers and (except for the root logger) sets the level
1385      * to {@code null}. The root logger's level is set to {@code Level.INFO}.
1386      *
1387      * @apiNote Calling this method also clears the LogManager {@linkplain
1388      * #getProperty(java.lang.String) properties}. The {@link
1389      * #updateConfiguration(java.util.function.Function)
1390      * updateConfiguration(Function)} or
1391      * {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)
1392      * updateConfiguration(InputStream, Function)} method can be used to
1393      * properly update to a new configuration.
1394      *
1395      * @throws  SecurityException  if a security manager exists and if
1396      *             the caller does not have LoggingPermission("control").
1397      */
1398 
1399     public void reset() throws SecurityException {
1400         checkPermission();
1401 
1402         List<CloseOnReset> persistent;
1403 
1404         // We don't want reset() and readConfiguration()
1405         // to run in parallel
1406         configurationLock.lock();
1407         try {
1408             // install new empty properties
1409             props = new Properties();
1410             // make sure we keep the loggers persistent until reset is done.
1411             // Those are the loggers for which we previously created a
1412             // handler from the configuration, and we need to prevent them
1413             // from being gc'ed until those handlers are closed.
1414             persistent = new ArrayList<>(closeOnResetLoggers);
1415             closeOnResetLoggers.clear();
1416 
1417             // if reset has been called from shutdown-hook (Cleaner),
1418             // or if reset has been called from readConfiguration() which
1419             // already holds the lock and will change the state itself,
1420             // then do not change state here...
1421             if (globalHandlersState != STATE_SHUTDOWN &&
1422                 globalHandlersState != STATE_READING_CONFIG) {
1423                 // ...else user called reset()...
1424                 // Since we are doing a reset we no longer want to initialize
1425                 // the global handlers, if they haven't been initialized yet.
1426                 globalHandlersState = STATE_INITIALIZED;
1427             }
1428 
1429             for (LoggerContext cx : contexts()) {
1430                 resetLoggerContext(cx);
1431             }
1432 
1433             persistent.clear();
1434         } finally {
1435             configurationLock.unlock();
1436         }
1437     }
1438 
1439     private void resetLoggerContext(LoggerContext cx) {
1440         Enumeration<String> enum_ = cx.getLoggerNames();
1441         while (enum_.hasMoreElements()) {
1442             String name = enum_.nextElement();
1443             Logger logger = cx.findLogger(name);
1444             if (logger != null) {
1445                 resetLogger(logger);
1446             }
1447         }
1448     }
1449 
1450     private void closeHandlers(Logger logger) {
1451         Handler[] targets = logger.getHandlers();
1452         for (Handler h : targets) {
1453             logger.removeHandler(h);
1454             try {
1455                 h.close();
1456             } catch (Exception ex) {
1457                 // Problems closing a handler?  Keep going...
1458             } catch (Error e) {
1459                 // ignore Errors while shutting down
1460                 if (globalHandlersState != STATE_SHUTDOWN) {
1461                     throw e;
1462                 }
1463             }
1464         }
1465     }
1466 
1467     // Private method to reset an individual target logger.
1468     private void resetLogger(Logger logger) {
1469         // Close all the Logger handlers.
1470         closeHandlers(logger);
1471 
1472         // Reset Logger level
1473         String name = logger.getName();
1474         if (name != null && name.equals("")) {
1475             // This is the root logger.
1476             logger.setLevel(defaultLevel);
1477         } else {
1478             logger.setLevel(null);
1479         }
1480     }
1481 
1482     // get a list of whitespace separated classnames from a property.
1483     private String[] parseClassNames(String propertyName) {
1484         String hands = getProperty(propertyName);
1485         if (hands == null) {
1486             return new String[0];
1487         }
1488         hands = hands.trim();
1489         int ix = 0;
1490         final List<String> result = new ArrayList<>();
1491         while (ix < hands.length()) {
1492             int end = ix;
1493             while (end < hands.length()) {
1494                 if (Character.isWhitespace(hands.charAt(end))) {
1495                     break;
1496                 }
1497                 if (hands.charAt(end) == ',') {
1498                     break;
1499                 }
1500                 end++;
1501             }
1502             String word = hands.substring(ix, end);
1503             ix = end+1;
1504             word = word.trim();
1505             if (word.length() == 0) {
1506                 continue;
1507             }
1508             result.add(word);
1509         }
1510         return result.toArray(new String[result.size()]);
1511     }
1512 
1513     /**
1514      * Reads and initializes the logging configuration from the given input stream.
1515      *
1516      * <p>
1517      * Any {@linkplain #addConfigurationListener registered configuration
1518      * listener} will be invoked after the properties are read.
1519      *
1520      * @apiNote This {@code readConfiguration} method should only be used for
1521      * initializing the configuration during LogManager initialization or
1522      * used with the "java.util.logging.config.class" property.
1523      * When this method is called after loggers have been created, all
1524      * existing loggers will be {@linkplain #reset() reset}. Then any
1525      * existing loggers that have a level property specified in the
1526      * given input stream will be {@linkplain
1527      * Logger#setLevel(java.util.logging.Level) set} to the specified log level.
1528      * <p>
1529      * To properly update the logging configuration, use the
1530      * {@link #updateConfiguration(java.util.function.Function)} or
1531      * {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)}
1532      * method instead.
1533      *
1534      * @param ins  stream to read properties from
1535      * @throws  SecurityException  if a security manager exists and if
1536      *             the caller does not have LoggingPermission("control").
1537      * @throws  IOException if there are problems reading from the stream,
1538      *             or the given stream is not in the
1539      *             {@linkplain java.util.Properties properties file} format.
1540      */
1541     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1542         checkPermission();
1543 
1544         // We don't want reset() and readConfiguration() to run
1545         // in parallel.
1546         configurationLock.lock();
1547         try {
1548             if (globalHandlersState == STATE_SHUTDOWN) {
1549                 // already in terminal state: don't even bother
1550                 // to read the configuration
1551                 return;
1552             }
1553 
1554             // change state to STATE_READING_CONFIG to signal reset() to not change it
1555             globalHandlersState = STATE_READING_CONFIG;
1556             try {
1557                 // reset configuration which leaves globalHandlersState at STATE_READING_CONFIG
1558                 // so that while reading configuration, any ongoing logging requests block and
1559                 // wait for the outcome (see the end of this try statement)
1560                 reset();
1561 
1562                 try {
1563                     // Load the properties
1564                     props.load(ins);
1565                 } catch (IllegalArgumentException x) {
1566                     // props.load may throw an IllegalArgumentException if the stream
1567                     // contains malformed Unicode escape sequences.
1568                     // We wrap that in an IOException as readConfiguration is
1569                     // specified to throw IOException if there are problems reading
1570                     // from the stream.
1571                     // Note: new IOException(x.getMessage(), x) allow us to get a more
1572                     // concise error message than new IOException(x);
1573                     throw new IOException(x.getMessage(), x);
1574                 }
1575 
1576                 // Instantiate new configuration objects.
1577                 String names[] = parseClassNames("config");
1578 
1579                 for (String word : names) {
1580                     try {
1581                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
1582                         @SuppressWarnings("deprecation")
1583                         Object witness = clz.newInstance();
1584                     } catch (Exception ex) {
1585                         System.err.println("Can't load config class \"" + word + "\"");
1586                         System.err.println("" + ex);
1587                         // ex.printStackTrace();
1588                     }
1589                 }
1590 
1591                 // Set levels on any pre-existing loggers, based on the new properties.
1592                 setLevelsOnExistingLoggers();
1593 
1594                 // Note that we need to reinitialize global handles when
1595                 // they are first referenced.
1596                 globalHandlersState = STATE_UNINITIALIZED;
1597             } catch (Throwable t) {
1598                 // If there were any trouble, then set state to STATE_INITIALIZED
1599                 // so that no global handlers reinitialization is performed on not fully
1600                 // initialized configuration.
1601                 globalHandlersState = STATE_INITIALIZED;
1602                 // re-throw
1603                 throw t;
1604             }
1605         } finally {
1606             configurationLock.unlock();
1607         }
1608 
1609         // should be called out of lock to avoid dead-lock situations
1610         // when user code is involved
1611         invokeConfigurationListeners();
1612     }
1613 
1614     // This enum enumerate the configuration properties that will be
1615     // updated on existing loggers when the configuration is updated
1616     // with LogManager.updateConfiguration().
1617     //
1618     // Note that this works properly only for the global LogManager - as
1619     // Handler and its subclasses get their configuration from
1620     // LogManager.getLogManager().
1621     //
1622     static enum ConfigProperty {
1623         LEVEL(".level"), HANDLERS(".handlers"), USEPARENT(".useParentHandlers");
1624         final String suffix;
1625         final int length;
1626         private ConfigProperty(String suffix) {
1627             this.suffix = Objects.requireNonNull(suffix);
1628             length = suffix.length();
1629         }
1630 
1631         public boolean handleKey(String key) {
1632             if (this == HANDLERS && suffix.substring(1).equals(key)) return true;
1633             if (this == HANDLERS && suffix.equals(key)) return false;
1634             return key.endsWith(suffix);
1635         }
1636         String key(String loggerName) {
1637             if (this == HANDLERS && (loggerName == null || loggerName.isEmpty())) {
1638                 return suffix.substring(1);
1639             }
1640             return loggerName + suffix;
1641         }
1642         String loggerName(String key) {
1643             assert key.equals(suffix.substring(1)) && this == HANDLERS || key.endsWith(suffix);
1644             if (this == HANDLERS && suffix.substring(1).equals(key)) return "";
1645             return key.substring(0, key.length() - length);
1646         }
1647 
1648         /**
1649          * If the property is one that should be updated on existing loggers by
1650          * updateConfiguration, returns the name of the logger for which the
1651          * property is configured. Otherwise, returns null.
1652          * @param property a property key in 'props'
1653          * @return the name of the logger on which the property is to be set,
1654          *         if the property is one that should be updated on existing
1655          *         loggers, {@code null} otherwise.
1656          */
1657         static String getLoggerName(String property) {
1658             for (ConfigProperty p : ConfigProperty.ALL) {
1659                 if (p.handleKey(property)) {
1660                     return p.loggerName(property);
1661                 }
1662             }
1663             return null; // Not a property that should be updated.
1664         }
1665 
1666         /**
1667          * Find the ConfigProperty corresponding to the given
1668          * property key (may find none).
1669          * @param property a property key in 'props'
1670          * @return An optional containing a ConfigProperty object,
1671          *         if the property is one that should be updated on existing
1672          *         loggers, empty otherwise.
1673          */
1674         static Optional<ConfigProperty> find(String property) {
1675             return ConfigProperty.ALL.stream()
1676                     .filter(p -> p.handleKey(property))
1677                     .findFirst();
1678          }
1679 
1680         /**
1681          * Returns true if the given property is one that should be updated
1682          * on existing loggers.
1683          * Used to filter property name streams.
1684          * @param property a property key from the configuration.
1685          * @return true if this property is of interest for updateConfiguration.
1686          */
1687         static boolean matches(String property) {
1688             return find(property).isPresent();
1689         }
1690 
1691         /**
1692          * Returns true if the new property value is different from the old,
1693          * and therefore needs to be updated on existing loggers.
1694          * @param k a property key in the configuration
1695          * @param previous the old configuration
1696          * @param next the new configuration
1697          * @return true if the property is changing value between the two
1698          *         configurations.
1699          */
1700         static boolean needsUpdating(String k, Properties previous, Properties next) {
1701             final String p = trim(previous.getProperty(k, null));
1702             final String n = trim(next.getProperty(k, null));
1703             return ! Objects.equals(p,n);
1704         }
1705 
1706         /**
1707          * Applies the mapping function for the given key to the next
1708          * configuration.
1709          * If the mapping function is null then this method does nothing.
1710          * Otherwise, it calls the mapping function to compute the value
1711          * that should be associated with {@code key} in the resulting
1712          * configuration, and applies it to {@code next}.
1713          * If the mapping function returns {@code null} the key is removed
1714          * from {@code next}.
1715          *
1716          * @param k a property key in the configuration
1717          * @param previous the old configuration
1718          * @param next the new configuration (modified by this function)
1719          * @param mappingFunction the mapping function.
1720          */
1721         static void merge(String k, Properties previous, Properties next,
1722                           BiFunction<String, String, String> mappingFunction) {
1723             String p = trim(previous.getProperty(k, null));
1724             String n = trim(next.getProperty(k, null));
1725             String mapped = trim(mappingFunction.apply(p,n));
1726             if (!Objects.equals(n, mapped)) {
1727                 if (mapped == null) {
1728                     next.remove(k);
1729                 } else {
1730                     next.setProperty(k, mapped);
1731                 }
1732             }
1733         }
1734 
1735         private static final EnumSet<ConfigProperty> ALL =
1736                 EnumSet.allOf(ConfigProperty.class);
1737     }
1738 
1739     // trim the value if not null.
1740     private static String trim(String value) {
1741         return value == null ? null : value.trim();
1742     }
1743 
1744     /**
1745      * An object that keep track of loggers we have already visited.
1746      * Used when updating configuration, to avoid processing the same logger
1747      * twice.
1748      */
1749     static final class VisitedLoggers implements Predicate<Logger> {
1750         final IdentityHashMap<Logger,Boolean> visited;
1751         private VisitedLoggers(IdentityHashMap<Logger,Boolean> visited) {
1752             this.visited = visited;
1753         }
1754         VisitedLoggers() {
1755             this(new IdentityHashMap<>());
1756         }
1757         @Override
1758         public boolean test(Logger logger) {
1759             return visited != null && visited.put(logger, Boolean.TRUE) != null;
1760         }
1761         public void clear() {
1762             if (visited != null) visited.clear();
1763         }
1764 
1765         // An object that considers that no logger has ever been visited.
1766         // This is used when processParentHandlers is called from
1767         // LoggerContext.addLocalLogger
1768         static final VisitedLoggers NEVER = new VisitedLoggers(null);
1769     }
1770 
1771 
1772     /**
1773      * Type of the modification for a given property. One of SAME, ADDED, CHANGED,
1774      * or REMOVED.
1775      */
1776     static enum ModType {
1777         SAME,    // property had no value in the old and new conf, or had the
1778                  // same value in both.
1779         ADDED,   // property had no value in the old conf, but has one in the new.
1780         CHANGED, // property has a different value in the old conf and the new conf.
1781         REMOVED; // property has no value in the new conf, but had one in the old.
1782         static ModType of(String previous, String next) {
1783             if (previous == null && next != null) {
1784                 return ADDED;
1785             }
1786             if (next == null && previous != null) {
1787                 return REMOVED;
1788             }
1789             if (!Objects.equals(trim(previous), trim(next))) {
1790                 return CHANGED;
1791             }
1792             return SAME;
1793         }
1794     }
1795 
1796     /**
1797      * Updates the logging configuration.
1798      * <p>
1799      * If the "java.util.logging.config.file" system property is set,
1800      * then the property value specifies the properties file to be read
1801      * as the new configuration. Otherwise, the LogManager default
1802      * configuration is used.
1803      * <br>The default configuration is typically loaded from the
1804      * properties file "{@code conf/logging.properties}" in the
1805      * Java installation directory.
1806      * <p>
1807      * This method reads the new configuration and calls the {@link
1808      * #updateConfiguration(java.io.InputStream, java.util.function.Function)
1809      * updateConfiguration(ins, mapper)} method to
1810      * update the configuration.
1811      *
1812      * @apiNote
1813      * This method updates the logging configuration from reading
1814      * a properties file and ignores the "java.util.logging.config.class"
1815      * system property.  The "java.util.logging.config.class" property is
1816      * only used by the {@link #readConfiguration()}  method to load a custom
1817      * configuration class as an initial configuration.
1818      *
1819      * @param mapper a functional interface that takes a configuration
1820      *   key <i>k</i> and returns a function <i>f(o,n)</i> whose returned
1821      *   value will be applied to the resulting configuration. The
1822      *   function <i>f</i> may return {@code null} to indicate that the property
1823      *   <i>k</i> will not be added to the resulting configuration.
1824      *   <br>
1825      *   If {@code mapper} is {@code null} then {@code (k) -> ((o, n) -> n)} is
1826      *   assumed.
1827      *   <br>
1828      *   For each <i>k</i>, the mapped function <i>f</i> will
1829      *   be invoked with the value associated with <i>k</i> in the old
1830      *   configuration (i.e <i>o</i>) and the value associated with
1831      *   <i>k</i> in the new configuration (i.e. <i>n</i>).
1832      *   <br>A {@code null} value for <i>o</i> or <i>n</i> indicates that no
1833      *   value was present for <i>k</i> in the corresponding configuration.
1834      *
1835      * @throws  SecurityException  if a security manager exists and if
1836      *          the caller does not have LoggingPermission("control"), or
1837      *          does not have the permissions required to set up the
1838      *          configuration (e.g. open file specified for FileHandlers
1839      *          etc...)
1840      *
1841      * @throws  NullPointerException  if {@code mapper} returns a {@code null}
1842      *         function when invoked.
1843      *
1844      * @throws  IOException if there are problems reading from the
1845      *          logging configuration file.
1846      *
1847      * @see #updateConfiguration(java.io.InputStream, java.util.function.Function)
1848      * @since 9
1849      */
1850     public void updateConfiguration(Function<String, BiFunction<String,String,String>> mapper)
1851             throws IOException {
1852         checkPermission();
1853         ensureLogManagerInitialized();
1854         drainLoggerRefQueueBounded();
1855 
1856         String fname = getConfigurationFileName();
1857         try (final InputStream in = new FileInputStream(fname)) {
1858             final BufferedInputStream bin = new BufferedInputStream(in);
1859             updateConfiguration(bin, mapper);
1860         }
1861     }
1862 
1863     /**
1864      * Updates the logging configuration.
1865      * <p>
1866      * For each configuration key in the {@linkplain
1867      * #getProperty(java.lang.String) existing configuration} and
1868      * the given input stream configuration, the given {@code mapper} function
1869      * is invoked to map from the configuration key to a function,
1870      * <i>f(o,n)</i>, that takes the old value and new value and returns
1871      * the resulting value to be applied in the resulting configuration,
1872      * as specified in the table below.
1873      * <p>Let <i>k</i> be a configuration key in the old or new configuration,
1874      * <i>o</i> be the old value (i.e. the value associated
1875      * with <i>k</i> in the old configuration), <i>n</i> be the
1876      * new value (i.e. the value associated with <i>k</i> in the new
1877      * configuration), and <i>f</i> be the function returned
1878      * by {@code mapper.apply(}<i>k</i>{@code )}: then <i>v = f(o,n)</i> is the
1879      * resulting value. If <i>v</i> is not {@code null}, then a property
1880      * <i>k</i> with value <i>v</i> will be added to the resulting configuration.
1881      * Otherwise, it will be omitted.
1882      * <br>A {@code null} value may be passed to function
1883      * <i>f</i> to indicate that the corresponding configuration has no
1884      * configuration key <i>k</i>.
1885      * The function <i>f</i> may return {@code null} to indicate that
1886      * there will be no value associated with <i>k</i> in the resulting
1887      * configuration.
1888      * <p>
1889      * If {@code mapper} is {@code null}, then <i>v</i> will be set to
1890      * <i>n</i>.
1891      * <p>
1892      * LogManager {@linkplain #getProperty(java.lang.String) properties} are
1893      * updated with the resulting value in the resulting configuration.
1894      * <p>
1895      * The registered {@linkplain #addConfigurationListener configuration
1896      * listeners} will be invoked after the configuration is successfully updated.
1897      * <br><br>
1898      * <table class="striped">
1899      * <caption style="display:none">Updating configuration properties</caption>
1900      * <thead>
1901      * <tr>
1902      * <th scope="col">Property</th>
1903      * <th scope="col">Resulting Behavior</th>
1904      * </tr>
1905      * </thead>
1906      * <tbody>
1907      * <tr>
1908      * <th scope="row" valign="top">{@code <logger>.level}</th>
1909      * <td>
1910      * <ul>
1911      *   <li>If the resulting configuration defines a level for a logger and
1912      *       if the resulting level is different than the level specified in the
1913      *       the old configuration, or not specified in
1914      *       the old configuration, then if the logger exists or if children for
1915      *       that logger exist, the level for that logger will be updated,
1916      *       and the change propagated to any existing logger children.
1917      *       This may cause the logger to be created, if necessary.
1918      *   </li>
1919      *   <li>If the old configuration defined a level for a logger, and the
1920      *       resulting configuration doesn't, then this change will not be
1921      *       propagated to existing loggers, if any.
1922      *       To completely replace a configuration - the caller should therefore
1923      *       call {@link #reset() reset} to empty the current configuration,
1924      *       before calling {@code updateConfiguration}.
1925      *   </li>
1926      * </ul>
1927      * </td>
1928      * <tr>
1929      * <th scope="row" valign="top">{@code <logger>.useParentHandlers}</th>
1930      * <td>
1931      * <ul>
1932      *   <li>If either the resulting or the old value for the useParentHandlers
1933      *       property is not null, then if the logger exists or if children for
1934      *       that logger exist, that logger will be updated to the resulting
1935      *       value.
1936      *       The value of the useParentHandlers property is the value specified
1937      *       in the configuration; if not specified, the default is true.
1938      *   </li>
1939      * </ul>
1940      * </td>
1941      * </tr>
1942      * <tr>
1943      * <th scope="row" valign="top">{@code <logger>.handlers}</th>
1944      * <td>
1945      * <ul>
1946      *   <li>If the resulting configuration defines a list of handlers for a
1947      *       logger, and if the resulting list is different than the list
1948      *       specified in the old configuration for that logger (that could be
1949      *       empty), then if the logger exists or its children exist, the
1950      *       handlers associated with that logger are closed and removed and
1951      *       the new handlers will be created per the resulting configuration
1952      *       and added to that logger, creating that logger if necessary.
1953      *   </li>
1954      *   <li>If the old configuration defined some handlers for a logger, and
1955      *       the resulting configuration doesn't, if that logger exists,
1956      *       its handlers will be removed and closed.
1957      *   </li>
1958      *   <li>Changing the list of handlers on an existing logger will cause all
1959      *       its previous handlers to be removed and closed, regardless of whether
1960      *       they had been created from the configuration or programmatically.
1961      *       The old handlers will be replaced by new handlers, if any.
1962      *   </li>
1963      * </ul>
1964      * </td>
1965      * </tr>
1966      * <tr>
1967      * <th scope="row" valign="top">{@code <handler-name>.*}</th>
1968      * <td>
1969      * <ul>
1970      *   <li>Properties configured/changed on handler classes will only affect
1971      *       newly created handlers. If a node is configured with the same list
1972      *       of handlers in the old and the resulting configuration, then these
1973      *       handlers will remain unchanged.
1974      *   </li>
1975      * </ul>
1976      * </td>
1977      * </tr>
1978      * <tr>
1979      * <th scope="row" valign="top">{@code config} and any other property</th>
1980      * <td>
1981      * <ul>
1982      *   <li>The resulting value for these property will be stored in the
1983      *   LogManager properties, but {@code updateConfiguration} will not parse
1984      *   or process their values.
1985      *   </li>
1986      * </ul>
1987      * </td>
1988      * </tr>
1989      * </tbody>
1990      * </table>
1991      * <p>
1992      * <em>Example mapper functions:</em>
1993      * <br><br>
1994      * <ul>
1995      * <li>Replace all logging properties with the new configuration:
1996      * <br><br>{@code     (k) -> ((o, n) -> n)}:
1997      * <br><br>this is equivalent to passing a null {@code mapper} parameter.
1998      * </li>
1999      * <li>Merge the new configuration and old configuration and use the
2000      * new value if <i>k</i> exists in the new configuration:
2001      * <br><br>{@code     (k) -> ((o, n) -> n == null ? o : n)}:
2002      * <br><br>as if merging two collections as follows:
2003      * {@code result.putAll(oldc); result.putAll(newc)}.<br></li>
2004      * <li>Merge the new configuration and old configuration and use the old
2005      * value if <i>k</i> exists in the old configuration:
2006      * <br><br>{@code     (k) -> ((o, n) -> o == null ? n : o)}:
2007      * <br><br>as if merging two collections as follows:
2008      * {@code result.putAll(newc); result.putAll(oldc)}.<br></li>
2009      * <li>Replace all properties with the new configuration except the handler
2010      * property to configure Logger's handler that is not root logger:
2011      * <br>
2012      * <pre>{@code (k) -> k.endsWith(".handlers")}
2013      *      {@code     ? ((o, n) -> (o == null ? n : o))}
2014      *      {@code     : ((o, n) -> n)}</pre>
2015      * </li>
2016      * </ul>
2017      * <p>
2018      * To completely reinitialize a configuration, an application can first call
2019      * {@link #reset() reset} to fully remove the old configuration, followed by
2020      * {@code updateConfiguration} to initialize the new configuration.
2021      *
2022      * @param ins    a stream to read properties from
2023      * @param mapper a functional interface that takes a configuration
2024      *   key <i>k</i> and returns a function <i>f(o,n)</i> whose returned
2025      *   value will be applied to the resulting configuration. The
2026      *   function <i>f</i> may return {@code null} to indicate that the property
2027      *   <i>k</i> will not be added to the resulting configuration.
2028      *   <br>
2029      *   If {@code mapper} is {@code null} then {@code (k) -> ((o, n) -> n)} is
2030      *   assumed.
2031      *   <br>
2032      *   For each <i>k</i>, the mapped function <i>f</i> will
2033      *   be invoked with the value associated with <i>k</i> in the old
2034      *   configuration (i.e <i>o</i>) and the value associated with
2035      *   <i>k</i> in the new configuration (i.e. <i>n</i>).
2036      *   <br>A {@code null} value for <i>o</i> or <i>n</i> indicates that no
2037      *   value was present for <i>k</i> in the corresponding configuration.
2038      *
2039      * @throws  SecurityException if a security manager exists and if
2040      *          the caller does not have LoggingPermission("control"), or
2041      *          does not have the permissions required to set up the
2042      *          configuration (e.g. open files specified for FileHandlers)
2043      *
2044      * @throws  NullPointerException if {@code ins} is null or if
2045      *          {@code mapper} returns a null function when invoked.
2046      *
2047      * @throws  IOException if there are problems reading from the stream,
2048      *          or the given stream is not in the
2049      *          {@linkplain java.util.Properties properties file} format.
2050      * @since 9
2051      */
2052     public void updateConfiguration(InputStream ins,
2053             Function<String, BiFunction<String,String,String>> mapper)
2054             throws IOException {
2055         checkPermission();
2056         ensureLogManagerInitialized();
2057         drainLoggerRefQueueBounded();
2058 
2059         final Properties previous;
2060         final Set<String> updatePropertyNames;
2061         List<LoggerContext> cxs = Collections.emptyList();
2062         final VisitedLoggers visited = new VisitedLoggers();
2063         final Properties next = new Properties();
2064 
2065         try {
2066             // Load the properties
2067             next.load(ins);
2068         } catch (IllegalArgumentException x) {
2069             // props.load may throw an IllegalArgumentException if the stream
2070             // contains malformed Unicode escape sequences.
2071             // We wrap that in an IOException as updateConfiguration is
2072             // specified to throw IOException if there are problems reading
2073             // from the stream.
2074             // Note: new IOException(x.getMessage(), x) allow us to get a more
2075             // concise error message than new IOException(x);
2076             throw new IOException(x.getMessage(), x);
2077         }
2078 
2079         if (globalHandlersState == STATE_SHUTDOWN) return;
2080 
2081         // exclusive lock: readConfiguration/reset/updateConfiguration can't
2082         //           run concurrently.
2083         // configurationLock.writeLock().lock();
2084         configurationLock.lock();
2085         try {
2086             if (globalHandlersState == STATE_SHUTDOWN) return;
2087             previous = props;
2088 
2089             // Builds a TreeSet of all (old and new) property names.
2090             updatePropertyNames =
2091                     Stream.concat(previous.stringPropertyNames().stream(),
2092                                   next.stringPropertyNames().stream())
2093                         .collect(Collectors.toCollection(TreeSet::new));
2094 
2095             if (mapper != null) {
2096                 // mapper will potentially modify the content of
2097                 // 'next', so we need to call it before affecting props=next.
2098                 // give a chance to the mapper to control all
2099                 // properties - not just those we will reset.
2100                 updatePropertyNames.stream()
2101                         .forEachOrdered(k -> ConfigProperty
2102                                 .merge(k, previous, next,
2103                                        Objects.requireNonNull(mapper.apply(k))));
2104             }
2105 
2106             props = next;
2107 
2108             // allKeys will contain all keys:
2109             //    - which correspond to a configuration property we are interested in
2110             //      (first filter)
2111             //    - whose value needs to be updated (because it's new, removed, or
2112             //      different) in the resulting configuration (second filter)
2113             final Stream<String> allKeys = updatePropertyNames.stream()
2114                     .filter(ConfigProperty::matches)
2115                     .filter(k -> ConfigProperty.needsUpdating(k, previous, next));
2116 
2117             // Group configuration properties by logger name
2118             // We use a TreeMap so that parent loggers will be visited before
2119             // child loggers.
2120             final Map<String, TreeSet<String>> loggerConfigs =
2121                     allKeys.collect(Collectors.groupingBy(ConfigProperty::getLoggerName,
2122                                     TreeMap::new,
2123                                     Collectors.toCollection(TreeSet::new)));
2124 
2125             if (!loggerConfigs.isEmpty()) {
2126                 cxs = contexts();
2127             }
2128             final List<Logger> loggers = cxs.isEmpty()
2129                     ? Collections.emptyList() : new ArrayList<>(cxs.size());
2130             for (Map.Entry<String, TreeSet<String>> e : loggerConfigs.entrySet()) {
2131                 // This can be a logger name, or something else...
2132                 // The only thing we know is that we found a property
2133                 //    we are interested in.
2134                 // For instance, if we found x.y.z.level, then x.y.z could be
2135                 // a logger, but it could also be a handler class...
2136                 // Anyway...
2137                 final String name = e.getKey();
2138                 final Set<String> properties = e.getValue();
2139                 loggers.clear();
2140                 for (LoggerContext cx : cxs) {
2141                     Logger l = cx.findLogger(name);
2142                     if (l != null && !visited.test(l)) {
2143                         loggers.add(l);
2144                     }
2145                 }
2146                 if (loggers.isEmpty()) continue;
2147                 for (String pk : properties) {
2148                     ConfigProperty cp = ConfigProperty.find(pk).get();
2149                     String p = previous.getProperty(pk, null);
2150                     String n = next.getProperty(pk, null);
2151 
2152                     // Determines the type of modification.
2153                     ModType mod = ModType.of(p, n);
2154 
2155                     // mod == SAME means that the two values are equals, there
2156                     // is nothing to do. Usually, this should not happen as such
2157                     // properties should have been filtered above.
2158                     // It could happen however if the properties had
2159                     // trailing/leading whitespaces.
2160                     if (mod == ModType.SAME) continue;
2161 
2162                     switch (cp) {
2163                         case LEVEL:
2164                             if (mod == ModType.REMOVED) continue;
2165                             Level level = Level.findLevel(trim(n));
2166                             if (level != null) {
2167                                 if (name.isEmpty()) {
2168                                     rootLogger.setLevel(level);
2169                                 }
2170                                 for (Logger l : loggers) {
2171                                     if (!name.isEmpty() || l != rootLogger) {
2172                                         l.setLevel(level);
2173                                     }
2174                                 }
2175                             }
2176                             break;
2177                         case USEPARENT:
2178                             if (!name.isEmpty()) {
2179                                 boolean useParent = getBooleanProperty(pk, true);
2180                                 if (n != null || p != null) {
2181                                     // reset the flag only if the previous value
2182                                     // or the new value are not null.
2183                                     for (Logger l : loggers) {
2184                                         l.setUseParentHandlers(useParent);
2185                                     }
2186                                 }
2187                             }
2188                             break;
2189                         case HANDLERS:
2190                             List<Handler> hdls = null;
2191                             if (name.isEmpty()) {
2192                                 // special handling for the root logger.
2193                                 globalHandlersState = STATE_READING_CONFIG;
2194                                 try {
2195                                     closeHandlers(rootLogger);
2196                                     globalHandlersState = STATE_UNINITIALIZED;
2197                                 } catch (Throwable t) {
2198                                     globalHandlersState = STATE_INITIALIZED;
2199                                     throw t;
2200                                 }
2201                             }
2202                             for (Logger l : loggers) {
2203                                 if (l == rootLogger) continue;
2204                                 closeHandlers(l);
2205                                 if (mod == ModType.REMOVED) {
2206                                     closeOnResetLoggers.removeIf(c -> c.logger == l);
2207                                     continue;
2208                                 }
2209                                 if (hdls == null) {
2210                                     hdls = name.isEmpty()
2211                                             ? Arrays.asList(rootLogger.getHandlers())
2212                                             : createLoggerHandlers(name, pk);
2213                                 }
2214                                 setLoggerHandlers(l, name, pk, hdls);
2215                             }
2216                             break;
2217                         default: break;
2218                     }
2219                 }
2220             }
2221         } finally {
2222             configurationLock.unlock();
2223             visited.clear();
2224         }
2225 
2226         // Now ensure that if an existing logger has acquired a new parent
2227         // in the configuration, this new parent will be created - if needed,
2228         // and added to the context of the existing child.
2229         //
2230         drainLoggerRefQueueBounded();
2231         for (LoggerContext cx : cxs) {
2232             for (Enumeration<String> names = cx.getLoggerNames() ; names.hasMoreElements();) {
2233                 String name = names.nextElement();
2234                 if (name.isEmpty()) continue;  // don't need to process parents on root.
2235                 Logger l = cx.findLogger(name);
2236                 if (l != null && !visited.test(l)) {
2237                     // should pass visited here to cut the processing when
2238                     // reaching a logger already visited.
2239                     cx.processParentHandlers(l, name, visited);
2240                 }
2241             }
2242         }
2243 
2244         // We changed the configuration: invoke configuration listeners
2245         invokeConfigurationListeners();
2246     }
2247 
2248     /**
2249      * Get the value of a logging property.
2250      * The method returns null if the property is not found.
2251      * @param name      property name
2252      * @return          property value
2253      */
2254     public String getProperty(String name) {
2255         return props.getProperty(name);
2256     }
2257 
2258     // Package private method to get a String property.
2259     // If the property is not defined we return the given
2260     // default value.
2261     String getStringProperty(String name, String defaultValue) {
2262         String val = getProperty(name);
2263         if (val == null) {
2264             return defaultValue;
2265         }
2266         return val.trim();
2267     }
2268 
2269     // Package private method to get an integer property.
2270     // If the property is not defined or cannot be parsed
2271     // we return the given default value.
2272     int getIntProperty(String name, int defaultValue) {
2273         String val = getProperty(name);
2274         if (val == null) {
2275             return defaultValue;
2276         }
2277         try {
2278             return Integer.parseInt(val.trim());
2279         } catch (Exception ex) {
2280             return defaultValue;
2281         }
2282     }
2283 
2284     // Package private method to get a long property.
2285     // If the property is not defined or cannot be parsed
2286     // we return the given default value.
2287     long getLongProperty(String name, long defaultValue) {
2288         String val = getProperty(name);
2289         if (val == null) {
2290             return defaultValue;
2291         }
2292         try {
2293             return Long.parseLong(val.trim());
2294         } catch (Exception ex) {
2295             return defaultValue;
2296         }
2297     }
2298 
2299     // Package private method to get a boolean property.
2300     // If the property is not defined or cannot be parsed
2301     // we return the given default value.
2302     boolean getBooleanProperty(String name, boolean defaultValue) {
2303         String val = getProperty(name);
2304         if (val == null) {
2305             return defaultValue;
2306         }
2307         val = val.toLowerCase();
2308         if (val.equals("true") || val.equals("1")) {
2309             return true;
2310         } else if (val.equals("false") || val.equals("0")) {
2311             return false;
2312         }
2313         return defaultValue;
2314     }
2315 
2316     // Package private method to get a Level property.
2317     // If the property is not defined or cannot be parsed
2318     // we return the given default value.
2319     Level getLevelProperty(String name, Level defaultValue) {
2320         String val = getProperty(name);
2321         if (val == null) {
2322             return defaultValue;
2323         }
2324         Level l = Level.findLevel(val.trim());
2325         return l != null ? l : defaultValue;
2326     }
2327 
2328     // Package private method to get a filter property.
2329     // We return an instance of the class named by the "name"
2330     // property. If the property is not defined or has problems
2331     // we return the defaultValue.
2332     Filter getFilterProperty(String name, Filter defaultValue) {
2333         String val = getProperty(name);
2334         try {
2335             if (val != null) {
2336                 @SuppressWarnings("deprecation")
2337                 Object o = ClassLoader.getSystemClassLoader().loadClass(val).newInstance();
2338                 return (Filter) o;
2339             }
2340         } catch (Exception ex) {
2341             // We got one of a variety of exceptions in creating the
2342             // class or creating an instance.
2343             // Drop through.
2344         }
2345         // We got an exception.  Return the defaultValue.
2346         return defaultValue;
2347     }
2348 
2349 
2350     // Package private method to get a formatter property.
2351     // We return an instance of the class named by the "name"
2352     // property. If the property is not defined or has problems
2353     // we return the defaultValue.
2354     Formatter getFormatterProperty(String name, Formatter defaultValue) {
2355         String val = getProperty(name);
2356         try {
2357             if (val != null) {
2358                 @SuppressWarnings("deprecation")
2359                 Object o = ClassLoader.getSystemClassLoader().loadClass(val).newInstance();
2360                 return (Formatter) o;
2361             }
2362         } catch (Exception ex) {
2363             // We got one of a variety of exceptions in creating the
2364             // class or creating an instance.
2365             // Drop through.
2366         }
2367         // We got an exception.  Return the defaultValue.
2368         return defaultValue;
2369     }
2370 
2371     // Private method to load the global handlers.
2372     // We do the real work lazily, when the global handlers
2373     // are first used.
2374     private void initializeGlobalHandlers() {
2375         int state = globalHandlersState;
2376         if (state == STATE_INITIALIZED ||
2377             state == STATE_SHUTDOWN) {
2378             // Nothing to do: return.
2379             return;
2380         }
2381 
2382         // If we have not initialized global handlers yet (or need to
2383         // reinitialize them), lets do it now (this case is indicated by
2384         // globalHandlersState == STATE_UNINITIALIZED).
2385         // If we are in the process of initializing global handlers we
2386         // also need to lock & wait (this case is indicated by
2387         // globalHandlersState == STATE_INITIALIZING).
2388         // If we are in the process of reading configuration we also need to
2389         // wait to see what the outcome will be (this case
2390         // is indicated by globalHandlersState == STATE_READING_CONFIG)
2391         // So in either case we need to wait for the lock.
2392         configurationLock.lock();
2393         try {
2394             if (globalHandlersState != STATE_UNINITIALIZED) {
2395                 return; // recursive call or nothing to do
2396             }
2397             // set globalHandlersState to STATE_INITIALIZING first to avoid
2398             // getting an infinite recursion when loadLoggerHandlers(...)
2399             // is going to call addHandler(...)
2400             globalHandlersState = STATE_INITIALIZING;
2401             try {
2402                 loadLoggerHandlers(rootLogger, null, "handlers");
2403             } finally {
2404                 globalHandlersState = STATE_INITIALIZED;
2405             }
2406         } finally {
2407             configurationLock.unlock();
2408         }
2409     }
2410 
2411     static final Permission controlPermission =
2412             new LoggingPermission("control", null);
2413 
2414     void checkPermission() {
2415         SecurityManager sm = System.getSecurityManager();
2416         if (sm != null)
2417             sm.checkPermission(controlPermission);
2418     }
2419 
2420     /**
2421      * Check that the current context is trusted to modify the logging
2422      * configuration.  This requires LoggingPermission("control").
2423      * <p>
2424      * If the check fails we throw a SecurityException, otherwise
2425      * we return normally.
2426      *
2427      * @exception  SecurityException  if a security manager exists and if
2428      *             the caller does not have LoggingPermission("control").
2429      */
2430     public void checkAccess() throws SecurityException {
2431         checkPermission();
2432     }
2433 
2434     // Nested class to represent a node in our tree of named loggers.
2435     private static class LogNode {
2436         HashMap<String,LogNode> children;
2437         LoggerWeakRef loggerRef;
2438         LogNode parent;
2439         final LoggerContext context;
2440 
2441         LogNode(LogNode parent, LoggerContext context) {
2442             this.parent = parent;
2443             this.context = context;
2444         }
2445 
2446         // Recursive method to walk the tree below a node and set
2447         // a new parent logger.
2448         void walkAndSetParent(Logger parent) {
2449             if (children == null) {
2450                 return;
2451             }
2452             for (LogNode node : children.values()) {
2453                 LoggerWeakRef ref = node.loggerRef;
2454                 Logger logger = (ref == null) ? null : ref.get();
2455                 if (logger == null) {
2456                     node.walkAndSetParent(parent);
2457                 } else {
2458                     doSetParent(logger, parent);
2459                 }
2460             }
2461         }
2462     }
2463 
2464     // We use a subclass of Logger for the root logger, so
2465     // that we only instantiate the global handlers when they
2466     // are first needed.
2467     private final class RootLogger extends Logger {
2468         private RootLogger() {
2469             // We do not call the protected Logger two args constructor here,
2470             // to avoid calling LogManager.getLogManager() from within the
2471             // RootLogger constructor.
2472             super("", null, null, LogManager.this, true);
2473         }
2474 
2475         @Override
2476         public void log(LogRecord record) {
2477             // Make sure that the global handlers have been instantiated.
2478             initializeGlobalHandlers();
2479             super.log(record);
2480         }
2481 
2482         @Override
2483         public void addHandler(Handler h) {
2484             initializeGlobalHandlers();
2485             super.addHandler(h);
2486         }
2487 
2488         @Override
2489         public void removeHandler(Handler h) {
2490             initializeGlobalHandlers();
2491             super.removeHandler(h);
2492         }
2493 
2494         @Override
2495         Handler[] accessCheckedHandlers() {
2496             initializeGlobalHandlers();
2497             return super.accessCheckedHandlers();
2498         }
2499     }
2500 
2501 
2502     // Private method to be called when the configuration has
2503     // changed to apply any level settings to any pre-existing loggers.
2504     private void setLevelsOnExistingLoggers() {
2505         Enumeration<?> enum_ = props.propertyNames();
2506         while (enum_.hasMoreElements()) {
2507             String key = (String)enum_.nextElement();
2508             if (!key.endsWith(".level")) {
2509                 // Not a level definition.
2510                 continue;
2511             }
2512             int ix = key.length() - 6;
2513             String name = key.substring(0, ix);
2514             Level level = getLevelProperty(key, null);
2515             if (level == null) {
2516                 System.err.println("Bad level value for property: " + key);
2517                 continue;
2518             }
2519             for (LoggerContext cx : contexts()) {
2520                 Logger l = cx.findLogger(name);
2521                 if (l == null) {
2522                     continue;
2523                 }
2524                 l.setLevel(level);
2525             }
2526         }
2527     }
2528 
2529     /**
2530      * String representation of the
2531      * {@link javax.management.ObjectName} for the management interface
2532      * for the logging facility.
2533      *
2534      * @see java.lang.management.PlatformLoggingMXBean
2535      *
2536      * @since 1.5
2537      */
2538     public final static String LOGGING_MXBEAN_NAME
2539         = "java.util.logging:type=Logging";
2540 
2541     /**
2542      * Returns {@code LoggingMXBean} for managing loggers.
2543      *
2544      * @return a {@link LoggingMXBean} object.
2545      *
2546      * @deprecated {@code java.util.logging.LoggingMXBean} is deprecated and
2547      *      replaced with {@code java.lang.management.PlatformLoggingMXBean}. Use
2548      *      {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
2549      *      ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class)
2550      *      instead.
2551      *
2552      * @see java.lang.management.PlatformLoggingMXBean
2553      * @since 1.5
2554      */
2555     @Deprecated(since="9")
2556     public static synchronized LoggingMXBean getLoggingMXBean() {
2557         return Logging.getInstance();
2558     }
2559 
2560     /**
2561      * Adds a configuration listener to be invoked each time the logging
2562      * configuration is read.
2563      * If the listener is already registered the method does nothing.
2564      * <p>
2565      * The listener is invoked with privileges that are restricted by the
2566      * calling context of this method.
2567      * The order in which the listeners are invoked is unspecified.
2568      * <p>
2569      * It is recommended that listeners do not throw errors or exceptions.
2570      *
2571      * If a listener terminates with an uncaught error or exception then
2572      * the first exception will be propagated to the caller of
2573      * {@link #readConfiguration()} (or {@link #readConfiguration(java.io.InputStream)})
2574      * after all listeners have been invoked.
2575      *
2576      * @implNote If more than one listener terminates with an uncaught error or
2577      * exception, an implementation may record the additional errors or
2578      * exceptions as {@linkplain Throwable#addSuppressed(java.lang.Throwable)
2579      * suppressed exceptions}.
2580      *
2581      * @param listener A configuration listener that will be invoked after the
2582      *        configuration changed.
2583      * @return This LogManager.
2584      * @throws SecurityException if a security manager exists and if the
2585      * caller does not have LoggingPermission("control").
2586      * @throws NullPointerException if the listener is null.
2587      *
2588      * @since 9
2589      */
2590     public LogManager addConfigurationListener(Runnable listener) {
2591         final Runnable r = Objects.requireNonNull(listener);
2592         checkPermission();
2593         final SecurityManager sm = System.getSecurityManager();
2594         final AccessControlContext acc =
2595                 sm == null ? null : AccessController.getContext();
2596         final PrivilegedAction<Void> pa =
2597                 acc == null ? null : () -> { r.run() ; return null; };
2598         final Runnable pr =
2599                 acc == null ? r : () -> AccessController.doPrivileged(pa, acc);
2600         // Will do nothing if already registered.
2601         listeners.putIfAbsent(r, pr);
2602         return this;
2603     }
2604 
2605     /**
2606      * Removes a previously registered configuration listener.
2607      *
2608      * Returns silently if the listener is not found.
2609      *
2610      * @param listener the configuration listener to remove.
2611      * @throws NullPointerException if the listener is null.
2612      * @throws SecurityException if a security manager exists and if the
2613      * caller does not have LoggingPermission("control").
2614      *
2615      * @since 9
2616      */
2617     public void removeConfigurationListener(Runnable listener) {
2618         final Runnable key = Objects.requireNonNull(listener);
2619         checkPermission();
2620         listeners.remove(key);
2621     }
2622 
2623     private void invokeConfigurationListeners() {
2624         Throwable t = null;
2625 
2626         // We're using an IdentityHashMap because we want to compare
2627         // keys using identity (==).
2628         // We don't want to loop within a block synchronized on 'listeners'
2629         // to avoid invoking listeners from yet another synchronized block.
2630         // So we're taking a snapshot of the values list to avoid the risk of
2631         // ConcurrentModificationException while looping.
2632         //
2633         for (Runnable c : listeners.values().toArray(new Runnable[0])) {
2634             try {
2635                 c.run();
2636             } catch (ThreadDeath death) {
2637                 throw death;
2638             } catch (Error | RuntimeException x) {
2639                 if (t == null) t = x;
2640                 else t.addSuppressed(x);
2641             }
2642         }
2643         // Listeners are not supposed to throw exceptions, but if that
2644         // happens, we will rethrow the first error or exception that is raised
2645         // after all listeners have been invoked.
2646         if (t instanceof Error) throw (Error)t;
2647         if (t instanceof RuntimeException) throw (RuntimeException)t;
2648     }
2649 
2650     /**
2651      * This class allows the {@link LoggingProviderImpl} to demand loggers on
2652      * behalf of system and application classes.
2653      */
2654     private static final class LoggingProviderAccess
2655         implements LoggingProviderImpl.LogManagerAccess,
2656                    PrivilegedAction<Void> {
2657 
2658         private LoggingProviderAccess() {
2659         }
2660 
2661         /**
2662          * Demands a logger on behalf of the given {@code module}.
2663          * <p>
2664          * If a named logger suitable for the given module is found
2665          * returns it.
2666          * Otherwise, creates a new logger suitable for the given module.
2667          *
2668          * @param name   The logger name.
2669          * @param module The module on which behalf the logger is created/retrieved.
2670          * @return A logger for the given {@code module}.
2671          *
2672          * @throws NullPointerException if {@code name} is {@code null}
2673          *         or {@code module} is {@code null}.
2674          * @throws IllegalArgumentException if {@code manager} is not the default
2675          *         LogManager.
2676          * @throws SecurityException if a security manager is present and the
2677          *         calling code doesn't have the
2678          *        {@link LoggingPermission LoggingPermission("demandLogger", null)}.
2679          */
2680         @Override
2681         public Logger demandLoggerFor(LogManager manager, String name, Module module) {
2682             if (manager != getLogManager()) {
2683                 // having LogManager as parameter just ensures that the
2684                 // caller will have initialized the LogManager before reaching
2685                 // here.
2686                 throw new IllegalArgumentException("manager");
2687             }
2688             Objects.requireNonNull(name);
2689             Objects.requireNonNull(module);
2690             SecurityManager sm = System.getSecurityManager();
2691             if (sm != null) {
2692                 sm.checkPermission(controlPermission);
2693             }
2694             if (isSystem(module)) {
2695                 return manager.demandSystemLogger(name,
2696                     Logger.SYSTEM_LOGGER_RB_NAME, module);
2697             } else {
2698                 return manager.demandLogger(name, null, module);
2699             }
2700         }
2701 
2702         @Override
2703         public Void run() {
2704             LoggingProviderImpl.setLogManagerAccess(INSTANCE);
2705             return null;
2706         }
2707 
2708         static final LoggingProviderAccess INSTANCE = new LoggingProviderAccess();
2709     }
2710 
2711     static {
2712         AccessController.doPrivileged(LoggingProviderAccess.INSTANCE, null,
2713                                       controlPermission);
2714     }
2715 
2716 }