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