1 /*
2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */

25
26 package java.util.logging;
27
28 import java.io.*;
29 import java.util.*;
30 import java.security.*;
31 import java.lang.ref.ReferenceQueue;
32 import java.lang.ref.WeakReference;
33 import java.util.concurrent.ConcurrentHashMap;
34 import java.nio.file.Paths;
35 import java.util.concurrent.CopyOnWriteArrayList;
36 import java.util.concurrent.locks.ReentrantLock;
37 import java.util.function.BiFunction;
38 import java.util.function.Function;
39 import java.util.function.Predicate;
40 import java.util.stream.Collectors;
41 import java.util.stream.Stream;
42 import jdk.internal.misc.JavaAWTAccess;
43 import jdk.internal.misc.SharedSecrets;
44 import sun.util.logging.internal.LoggingProviderImpl;
45 import static jdk.internal.logger.DefaultLoggerFinder.isSystem;
46
47 /**
48  * There is a single global LogManager object that is used to
49  * maintain a set of shared state about Loggers and log services.
50  * <p>
51  * This LogManager object:
52  * <ul>
53  * <li> Manages a hierarchical namespace of Logger objects.  All
54  *      named Loggers are stored in this namespace.
55  * <li> Manages a set of logging control properties.  These are
56  *      simple key-value pairs that can be used by Handlers and
57  *      other logging objects to configure themselves.
58  * </ul>
59  * <p>
60  * The global LogManager object can be retrieved using LogManager.getLogManager().
61  * The LogManager object is created during class initialization and
62  * cannot subsequently be changed.
63  * <p>
64  * At startup the LogManager class is located using the
65  * java.util.logging.manager system property.
66  *
67  * <h3>LogManager Configuration</h3>
68  *
69  * A LogManager initializes the logging configuration via
70  * the {@link #readConfiguration()} method during LogManager initialization.
71  * By default, LogManager default configuration is used.
72  * The logging configuration read by LogManager must be in the
73  * {@linkplain Properties properties file} format.
74  * <p>
75  * The LogManager defines two optional system properties that allow control over
76  * the initial configuration, as specified in the {@link #readConfiguration()}
77  * method:
78  * <ul>
79  * <li>"java.util.logging.config.class"
80  * <li>"java.util.logging.config.file"
81  * </ul>
82  * <p>
83  * These two system properties may be specified on the command line to the "java"
84  * command, or as system property definitions passed to JNI_CreateJavaVM.
85  * <p>
86  * The {@linkplain Properties properties} for loggers and Handlers will have
87  * names starting with the dot-separated name for the handler or logger.<br>
88  * The global logging properties may include:
89  * <ul>
90  * <li>A property "handlers".  This defines a whitespace or comma separated
91  * list of class names for handler classes to load and register as
92  * handlers on the root Logger (the Logger named "").  Each class
93  * name must be for a Handler class which has a default constructor.
94  * Note that these Handlers may be created lazily, when they are
95  * first used.
96  *
97  * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
98  * comma separated list of class names for handlers classes to
99  * load and register as handlers to the specified logger. Each class
100  * name must be for a Handler class which has a default constructor.
101  * Note that these Handlers may be created lazily, when they are
102  * first used.
103  *
104  * <li>A property "&lt;logger&gt;.handlers.ensureCloseOnReset". This defines a
105  * a boolean value. If "&lt;logger&gt;.handlers" is not defined or is empty,
106  * this property is ignored. Otherwise it defaults to {@code true}. When the
107  * value is {@code true}, the handlers associated with the logger are guaranteed
108  * to be closed on {@linkplain #reset} and shutdown. This can be turned off
109  * by explicitly setting "&lt;logger&gt;.handlers.ensureCloseOnReset=false" in
110  * the configuration. Note that turning this property off causes the risk of
111  * introducing a resource leak, as the logger may get garbage collected before
112  * {@code reset()} is called, thus preventing its handlers from being closed
113  * on {@code reset()}. In that case it is the responsibility of the application
114  * to ensure that the handlers are closed before the logger is garbage
115  * collected.
116  *
117  * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
118  * value. By default every logger calls its parent in addition to
119  * handling the logging message itself, this often result in messages
120  * being handled by the root logger as well. When setting this property
121  * to false a Handler needs to be configured for this logger otherwise
122  * no logging messages are delivered.
123  *
124  * <li>A property "config".  This property is intended to allow
125  * arbitrary configuration code to be run.  The property defines a
126  * whitespace or comma separated list of class names.  A new instance will be
127  * created for each named class.  The default constructor of each class
128  * may execute arbitrary code to update the logging configuration, such as
129  * setting logger levels, adding handlers, adding filters, etc.
130  * </ul>
131  * <p>
132  * Note that all classes loaded during LogManager configuration are
133  * first searched on the system class path before any user class path.
134  * That includes the LogManager class, any config classes, and any
135  * handler classes.
136  * <p>
137  * Loggers are organized into a naming hierarchy based on their
138  * dot separated names.  Thus "a.b.c" is a child of "a.b", but
139  * "a.b1" and a.b2" are peers.
140  * <p>
141  * All properties whose names end with ".level" are assumed to define
142  * log levels for Loggers.  Thus "foo.level" defines a log level for
143  * the logger called "foo" and (recursively) for any of its children
144  * in the naming hierarchy.  Log Levels are applied in the order they
145  * are defined in the properties file.  Thus level settings for child
146  * nodes in the tree should come after settings for their parents.
147  * The property name ".level" can be used to set the level for the
148  * root of the tree.
149  * <p>
150  * All methods on the LogManager object are multi-thread safe.
151  *
152  * @since 1.4
153 */

154
155 public class LogManager {
156     // The global LogManager object
157     private static final LogManager manager;
158
159     // 'props' is assigned within a lock but accessed without it.
160     // Declaring it volatile makes sure that another thread will not
161     // be able to see a partially constructed 'props' object.
162     // (seeing a partially constructed 'props' object can result in
163     // NPE being thrown in Hashtable.get(), because it leaves the door
164     // open for props.getProperties() to be called before the construcor
165     // of Hashtable is actually completed).
166     private volatile Properties props = new Properties();
167     private final static Level defaultLevel = Level.INFO;
168
169     // LoggerContext for system loggers and user loggers
170     private final LoggerContext systemContext = new SystemLoggerContext();
171     private final LoggerContext userContext = new LoggerContext();
172     // non final field - make it volatile to make sure that other threads
173     // will see the new value once ensureLogManagerInitialized() has finished
174     // executing.
175     private volatile Logger rootLogger;
176     // Have we done the primordial reading of the configuration file?
177     // (Must be done after a suitable amount of java.lang.System
178     // initialization has been done)
179     private volatile boolean readPrimordialConfiguration;
180     // Have we initialized global (root) handlers yet?
181     // This gets set to STATE_UNINITIALIZED in readConfiguration
182     private static final int
183             STATE_INITIALIZED = 0, // initial state
184             STATE_INITIALIZING = 1,
185             STATE_READING_CONFIG = 2,
186             STATE_UNINITIALIZED = 3,
187             STATE_SHUTDOWN = 4;    // terminal state
188     private volatile int globalHandlersState; // = STATE_INITIALIZED;
189     // A concurrency lock for reset(), readConfiguration() and Cleaner.
190     private final ReentrantLock configurationLock = new ReentrantLock();
191
192     // This list contains the loggers for which some handlers have been
193     // explicitly configured in the configuration file.
194     // It prevents these loggers from being arbitrarily garbage collected.
195     private static final class CloseOnReset {
196         private final Logger logger;
197         private CloseOnReset(Logger ref) {
198             this.logger = Objects.requireNonNull(ref);
199         }
200         @Override
201         public boolean equals(Object other) {
202             return (other instanceof CloseOnReset) && ((CloseOnReset)other).logger == logger;
203         }
204         @Override
205         public int hashCode() {
206             return System.identityHashCode(logger);
207         }
208         public Logger get() {
209             return logger;
210         }
211         public static CloseOnReset create(Logger logger) {
212             return new CloseOnReset(logger);
213         }
214     }
215     private final CopyOnWriteArrayList<CloseOnReset> closeOnResetLoggers =
216             new CopyOnWriteArrayList<>();
217
218
219     private final Map<Object, Runnable> listeners =
220             Collections.synchronizedMap(new IdentityHashMap<>());
221
222     static {
223         manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
224             @Override
225             public LogManager run() {
226                 LogManager mgr = null;
227                 String cname = null;
228                 try {
229                     cname = System.getProperty("java.util.logging.manager");
230                     if (cname != null) {
231                         try {
232                             @SuppressWarnings("deprecation")
233                             Object tmp = ClassLoader.getSystemClassLoader()
234                                 .loadClass(cname).newInstance();
235                             mgr = (LogManager) tmp;
236                         } catch (ClassNotFoundException ex) {
237                             @SuppressWarnings("deprecation")
238                             Object tmp = Thread.currentThread()
239                                 .getContextClassLoader().loadClass(cname).newInstance();
240                             mgr = (LogManager) tmp;
241                         }
242                     }
243                 } catch (Exception ex) {
244                     System.err.println("Could not load Logmanager \"" + cname + "\"");
245                     ex.printStackTrace();
246                 }
247                 if (mgr == null) {
248                     mgr = new LogManager();
249                 }
250                 return mgr;
251
252             }
253         });
254     }
255
256     // This private class is used as a shutdown hook.
257     // It does a "reset" to close all open handlers.
258     private class Cleaner extends Thread {
259
260         private Cleaner() {
261             super(nullnull"Logging-Cleaner", 0, false);
262             /* Set context class loader to null in order to avoid
263              * keeping a strong reference to an application classloader.
264              */

265             this.setContextClassLoader(null);
266         }
267
268         @Override
269         public void run() {
270             // This is to ensure the LogManager.<clinit> is completed
271             // before synchronized block. Otherwise deadlocks are possible.
272             LogManager mgr = manager;
273
274             // set globalHandlersState to STATE_SHUTDOWN atomically so that
275             // no attempts are made to (re)initialize the handlers or (re)read
276             // the configuration again. This is terminal state.
277             configurationLock.lock();
278             globalHandlersState = STATE_SHUTDOWN;
279             configurationLock.unlock();
280
281             // Do a reset to close all active handlers.
282             reset();
283         }
284     }
285
286
287     /**
288      * Protected constructor.  This is protected so that container applications
289      * (such as J2EE containers) can subclass the object.  It is non-public as
290      * it is intended that there only be one LogManager object, whose value is
291      * retrieved by calling LogManager.getLogManager.
292      */

293     protected LogManager() {
294         this(checkSubclassPermissions());
295     }
296
297     private LogManager(Void checked) {
298
299         // Add a shutdown hook to close the global handlers.
300         try {
301             Runtime.getRuntime().addShutdownHook(new Cleaner());
302         } catch (IllegalStateException e) {
303             // If the VM is already shutting down,
304             // We do not need to register shutdownHook.
305         }
306     }
307
308     private static Void checkSubclassPermissions() {
309         final SecurityManager sm = System.getSecurityManager();
310         if (sm != null) {
311             // These permission will be checked in the LogManager constructor,
312             // in order to register the Cleaner() thread as a shutdown hook.
313             // Check them here to avoid the penalty of constructing the object
314             // etc...
315             sm.checkPermission(new RuntimePermission("shutdownHooks"));
316             sm.checkPermission(new RuntimePermission("setContextClassLoader"));
317         }
318         return null;
319     }
320
321     /**
322      * Lazy initialization: if this instance of manager is the global
323      * manager then this method will read the initial configuration and
324      * add the root logger and global logger by calling addLogger().
325      *
326      * Note that it is subtly different from what we do in LoggerContext.
327      * In LoggerContext we're patching up the logger context tree in order to add
328      * the root and global logger *to the context tree*.
329      *
330      * For this to work, addLogger() must have already have been called
331      * once on the LogManager instance for the default logger being
332      * added.
333      *
334      * This is why ensureLogManagerInitialized() needs to be called before
335      * any logger is added to any logger context.
336      *
337      */

338     private boolean initializedCalled = false;
339     private volatile boolean initializationDone = false;
340     final void ensureLogManagerInitialized() {
341         final LogManager owner = this;
342         if (initializationDone || owner != manager) {
343             // we don't want to do this twice, and we don't want to do
344             // this on private manager instances.
345             return;
346         }
347
348         // Maybe another thread has called ensureLogManagerInitialized()
349         // before us and is still executing it. If so we will block until
350         // the log manager has finished initialized, then acquire the monitor,
351         // notice that initializationDone is now true and return.
352         // Otherwise - we have come here first! We will acquire the monitor,
353         // see that initializationDone is still false, and perform the
354         // initialization.
355         //
356         configurationLock.lock();
357         try {
358             // If initializedCalled is true it means that we're already in
359             // the process of initializing the LogManager in this thread.
360             // There has been a recursive call to ensureLogManagerInitialized().
361             final boolean isRecursiveInitialization = (initializedCalled == true);
362
363             assert initializedCalled || !initializationDone
364                     : "Initialization can't be done if initialized has not been called!";
365
366             if (isRecursiveInitialization || initializationDone) {
367                 // If isRecursiveInitialization is true it means that we're
368                 // already in the process of initializing the LogManager in
369                 // this thread. There has been a recursive call to
370                 // ensureLogManagerInitialized(). We should not proceed as
371                 // it would lead to infinite recursion.
372                 //
373                 // If initializationDone is true then it means the manager
374                 // has finished initializing; just return: we're done.
375                 return;
376             }
377             // Calling addLogger below will in turn call requiresDefaultLogger()
378             // which will call ensureLogManagerInitialized().
379             // We use initializedCalled to break the recursion.
380             initializedCalled = true;
381             try {
382                 AccessController.doPrivileged(new PrivilegedAction<Object>() {
383                     @Override
384                     public Object run() {
385                         assert rootLogger == null;
386                         assert initializedCalled && !initializationDone;
387
388                         // create root logger before reading primordial
389                         // configuration - to ensure that it will be added
390                         // before the global logger, and not after.
391                         final Logger root = owner.rootLogger = owner.new RootLogger();
392
393                         // Read configuration.
394                         owner.readPrimordialConfiguration();
395
396                         // Create and retain Logger for the root of the namespace.
397                         owner.addLogger(root);
398
399                         // Initialize level if not yet initialized
400                         if (!root.isLevelInitialized()) {
401                             root.setLevel(defaultLevel);
402                         }
403
404                         // Adding the global Logger.
405                         // Do not call Logger.getGlobal() here as this might trigger
406                         // subtle inter-dependency issues.
407                         @SuppressWarnings("deprecation")
408                         final Logger global = Logger.global;
409
410                         // Make sure the global logger will be registered in the
411                         // global manager
412                         owner.addLogger(global);
413                         return null;
414                     }
415                 });
416             } finally {
417                 initializationDone = true;
418             }
419         } finally {
420             configurationLock.unlock();
421         }
422     }
423
424     /**
425      * Returns the global LogManager object.
426      * @return the global LogManager object
427      */

428     public static LogManager getLogManager() {
429         if (manager != null) {
430             manager.ensureLogManagerInitialized();
431         }
432         return manager;
433     }
434
435     private void readPrimordialConfiguration() { // must be called while holding configurationLock
436         if (!readPrimordialConfiguration) {
437             // If System.in/out/err are null, it's a good
438             // indication that we're still in the
439             // bootstrapping phase
440             if (System.out == null) {
441                 return;
442             }
443             readPrimordialConfiguration = true;
444             try {
445                 readConfiguration();
446
447                 // Platform loggers begin to delegate to java.util.logging.Logger
448                 jdk.internal.logger.BootstrapLogger.redirectTemporaryLoggers();
449
450             } catch (Exception ex) {
451                 assert false : "Exception raised while reading logging configuration: " + ex;
452             }
453         }
454     }
455
456     // LoggerContext maps from AppContext
457     private WeakHashMap<Object, LoggerContext> contextsMap = null;
458
459     // Returns the LoggerContext for the user code (i.e. application or AppContext).
460     // Loggers are isolated from each AppContext.
461     private LoggerContext getUserContext() {
462         LoggerContext context = null;
463
464         SecurityManager sm = System.getSecurityManager();
465         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
466         if (sm != null && javaAwtAccess != null) {
467             // for each applet, it has its own LoggerContext isolated from others
468             final Object ecx = javaAwtAccess.getAppletContext();
469             if (ecx != null) {
470                 synchronized (javaAwtAccess) {
471                     // find the AppContext of the applet code
472                     // will be null if we are in the main app context.
473                     if (contextsMap == null) {
474                         contextsMap = new WeakHashMap<>();
475                     }
476                     context = contextsMap.get(ecx);
477                     if (context == null) {
478                         // Create a new LoggerContext for the applet.
479                         context = new LoggerContext();
480                         contextsMap.put(ecx, context);
481                     }
482                 }
483             }
484         }
485         // for standalone app, return userContext
486         return context != null ? context : userContext;
487     }
488
489     // The system context.
490     final LoggerContext getSystemContext() {
491         return systemContext;
492     }
493
494     private List<LoggerContext> contexts() {
495         List<LoggerContext> cxs = new ArrayList<>();
496         cxs.add(getSystemContext());
497         cxs.add(getUserContext());
498         return cxs;
499     }
500
501     // Find or create a specified logger instance. If a logger has
502     // already been created with the given name it is returned.
503     // Otherwise a new logger instance is created and registered
504     // in the LogManager global namespace.
505     // This method will always return a non-null Logger object.
506     // Synchronization is not required here. All synchronization for
507     // adding a new Logger object is handled by addLogger().
508     //
509     // This method must delegate to the LogManager implementation to
510     // add a new Logger or return the one that has been added previously
511     // as a LogManager subclass may override the addLogger, getLogger,
512     // readConfiguration, and other methods.
513     Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
514         final Module module = caller == null ? null : caller.getModule();
515         return demandLogger(name, resourceBundleName, module);
516     }
517
518     Logger demandLogger(String name, String resourceBundleName, Module module) {
519         Logger result = getLogger(name);
520         if (result == null) {
521             // only allocate the new logger once
522             Logger newLogger = new Logger(name, resourceBundleName,
523                                           module, thisfalse);
524             do {
525                 if (addLogger(newLogger)) {
526                     // We successfully added the new Logger that we
527                     // created above so return it without refetching.
528                     return newLogger;
529                 }
530
531                 // We didn't add the new Logger that we created above
532                 // because another thread added a Logger with the same
533                 // name after our null check above and before our call
534                 // to addLogger(). We have to refetch the Logger because
535                 // addLogger() returns a boolean instead of the Logger
536                 // reference itself. However, if the thread that created
537                 // the other Logger is not holding a strong reference to
538                 // the other Logger, then it is possible for the other
539                 // Logger to be GC'ed after we saw it in addLogger() and
540                 // before we can refetch it. If it has been GC'ed then
541                 // we'll just loop around and try again.
542                 result = getLogger(name);
543             } while (result == null);
544         }
545         return result;
546     }
547
548     Logger demandSystemLogger(String name, String resourceBundleName, Class<?> caller) {
549         final Module module = caller == null ? null : caller.getModule();
550         return demandSystemLogger(name, resourceBundleName, module);
551     }
552
553     Logger demandSystemLogger(String name, String resourceBundleName, Module module) {
554         // Add a system logger in the system context's namespace
555         final Logger sysLogger = getSystemContext()
556                 .demandLogger(name, resourceBundleName, module);
557
558         // Add the system logger to the LogManager's namespace if not exist
559         // so that there is only one single logger of the given name.
560         // System loggers are visible to applications unless a logger of
561         // the same name has been added.
562         Logger logger;
563         do {
564             // First attempt to call addLogger instead of getLogger
565             // This would avoid potential bug in custom LogManager.getLogger
566             // implementation that adds a logger if does not exist
567             if (addLogger(sysLogger)) {
568                 // successfully added the new system logger
569                 logger = sysLogger;
570             } else {
571                 logger = getLogger(name);
572             }
573         } while (logger == null);
574
575         // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
576         if (logger != sysLogger) {
577             // if logger already exists we merge the two logger configurations.
578             final Logger l = logger;
579             AccessController.doPrivileged(new PrivilegedAction<Void>() {
580                 @Override
581                 public Void run() {
582                     l.mergeWithSystemLogger(sysLogger);
583                     return null;
584                 }
585             });
586         }
587         return sysLogger;
588     }
589
590     // LoggerContext maintains the logger namespace per context.
591     // The default LogManager implementation has one system context and user
592     // context.  The system context is used to maintain the namespace for
593     // all system loggers and is queried by the system code.  If a system logger
594     // doesn't exist in the user context, it'll also be added to the user context.
595     // The user context is queried by the user code and all other loggers are
596     // added in the user context.
597     class LoggerContext {
598         // Table of named Loggers that maps names to Loggers.
599         private final ConcurrentHashMap<String,LoggerWeakRef> namedLoggers =
600                 new ConcurrentHashMap<>();
601         // Tree of named Loggers
602         private final LogNode root;
603         private LoggerContext() {
604             this.root = new LogNode(nullthis);
605         }
606
607
608         // Tells whether default loggers are required in this context.
609         // If true, the default loggers will be lazily added.
610         final boolean requiresDefaultLoggers() {
611             final boolean requiresDefaultLoggers = (getOwner() == manager);
612             if (requiresDefaultLoggers) {
613                 getOwner().ensureLogManagerInitialized();
614             }
615             return requiresDefaultLoggers;
616         }
617
618         // This context's LogManager.
619         final LogManager getOwner() {
620             return LogManager.this;
621         }
622
623         // This context owner's root logger, which if not null, and if
624         // the context requires default loggers, will be added to the context
625         // logger's tree.
626         final Logger getRootLogger() {
627             return getOwner().rootLogger;
628         }
629
630         // The global logger, which if not null, and if
631         // the context requires default loggers, will be added to the context
632         // logger's tree.
633         final Logger getGlobalLogger() {
634             @SuppressWarnings("deprecation"// avoids initialization cycles.
635             final Logger global = Logger.global;
636             return global;
637         }
638
639         Logger demandLogger(String name, String resourceBundleName, Module module) {
640             // a LogManager subclass may have its own implementation to add and
641             // get a Logger.  So delegate to the LogManager to do the work.
642             final LogManager owner = getOwner();
643             return owner.demandLogger(name, resourceBundleName, module);
644         }
645
646
647         // Due to subtle deadlock issues getUserContext() no longer
648         // calls addLocalLogger(rootLogger);
649         // Therefore - we need to add the default loggers later on.
650         // Checks that the context is properly initialized
651         // This is necessary before calling e.g. find(name)
652         // or getLoggerNames()
653         //
654         private void ensureInitialized() {
655             if (requiresDefaultLoggers()) {
656                 // Ensure that the root and global loggers are set.
657                 ensureDefaultLogger(getRootLogger());
658                 ensureDefaultLogger(getGlobalLogger());
659             }
660         }
661
662
663         Logger findLogger(String name) {
664             // Attempt to find logger without locking.
665             LoggerWeakRef ref = namedLoggers.get(name);
666             Logger logger = ref == null ? null : ref.get();
667
668             // if logger is not null, then we can return it right away.
669             // if name is "" or "global" and logger is null
670             // we need to fall through and check that this context is
671             // initialized.
672             // if ref is not null and logger is null we also need to
673             // fall through.
674             if (logger != null || (ref == null && !name.isEmpty()
675                     && !name.equals(Logger.GLOBAL_LOGGER_NAME))) {
676                 return logger;
677             }
678
679             // We either found a stale reference, or we were looking for
680             // "" or "global" and didn't find them.
681             // Make sure context is initialized (has the default loggers),
682             // and look up again, cleaning the stale reference if it hasn't
683             // been cleaned up in between. All this needs to be done inside
684             // a synchronized block.
685             synchronized(this) {
686                 // ensure that this context is properly initialized before
687                 // looking for loggers.
688                 ensureInitialized();
689                 ref = namedLoggers.get(name);
690                 if (ref == null) {
691                     return null;
692                 }
693                 logger = ref.get();
694                 if (logger == null) {
695                     // The namedLoggers map holds stale weak reference
696                     // to a logger which has been GC-ed.
697                     ref.dispose();
698                 }
699                 return logger;
700             }
701         }
702
703         // This method is called before adding a logger to the
704         // context.
705         // 'logger' is the context that will be added.
706         // This method will ensure that the defaults loggers are added
707         // before adding 'logger'.
708         //
709         private void ensureAllDefaultLoggers(Logger logger) {
710             if (requiresDefaultLoggers()) {
711                 final String name = logger.getName();
712                 if (!name.isEmpty()) {
713                     ensureDefaultLogger(getRootLogger());
714                     if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
715                         ensureDefaultLogger(getGlobalLogger());
716                     }
717                 }
718             }
719         }
720
721         private void ensureDefaultLogger(Logger logger) {
722             // Used for lazy addition of root logger and global logger
723             // to a LoggerContext.
724
725             // This check is simple sanity: we do not want that this
726             // method be called for anything else than Logger.global
727             // or owner.rootLogger.
728             if (!requiresDefaultLoggers() || logger == null
729                     || logger != getGlobalLogger() && logger != LogManager.this.rootLogger ) {
730
731                 // the case where we have a non null logger which is neither
732                 // Logger.global nor manager.rootLogger indicates a serious
733                 // issue - as ensureDefaultLogger should never be called
734                 // with any other loggers than one of these two (or null - if
735                 // e.g manager.rootLogger is not yet initialized)...
736                 assert logger == null;
737
738                 return;
739             }
740
741             // Adds the logger if it's not already there.
742             if (!namedLoggers.containsKey(logger.getName())) {
743                 // It is important to prevent addLocalLogger to
744                 // call ensureAllDefaultLoggers when we're in the process
745                 // off adding one of those default loggers - as this would
746                 // immediately cause a stack overflow.
747                 // Therefore we must pass addDefaultLoggersIfNeeded=false,
748                 // even if requiresDefaultLoggers is true.
749                 addLocalLogger(logger, false);
750             }
751         }
752
753         boolean addLocalLogger(Logger logger) {
754             // no need to add default loggers if it's not required
755             return addLocalLogger(logger, requiresDefaultLoggers());
756         }
757
758         // Add a logger to this context.  This method will only set its level
759         // and process parent loggers.  It doesn't set its handlers.
760         synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
761             // addDefaultLoggersIfNeeded serves to break recursion when adding
762             // default loggers. If we're adding one of the default loggers
763             // (we're being called from ensureDefaultLogger()) then
764             // addDefaultLoggersIfNeeded will be false: we don't want to
765             // call ensureAllDefaultLoggers again.
766             //
767             // Note: addDefaultLoggersIfNeeded can also be false when
768             //       requiresDefaultLoggers is false - since calling
769             //       ensureAllDefaultLoggers would have no effect in this case.
770             if (addDefaultLoggersIfNeeded) {
771                 ensureAllDefaultLoggers(logger);
772             }
773
774             final String name = logger.getName();
775             if (name == null) {
776                 throw new NullPointerException();
777             }
778             LoggerWeakRef ref = namedLoggers.get(name);
779             if (ref != null) {
780                 if (ref.get() == null) {
781                     // It's possible that the Logger was GC'ed after a
782                     // drainLoggerRefQueueBounded() call above so allow
783                     // a new one to be registered.
784                     ref.dispose();
785                 } else {
786                     // We already have a registered logger with the given name.
787                     return false;
788                 }
789             }
790
791             // We're adding a new logger.
792             // Note that we are creating a weak reference here.
793             final LogManager owner = getOwner();
794             logger.setLogManager(owner);
795             ref = owner.new LoggerWeakRef(logger);
796
797             // Apply any initial level defined for the new logger, unless
798             // the logger's level is already initialized
799             Level level = owner.getLevelProperty(name + ".level"null);
800             if (level != null && !logger.isLevelInitialized()) {
801                 doSetLevel(logger, level);
802             }
803
804             // instantiation of the handler is done in the LogManager.addLogger
805             // implementation as a handler class may be only visible to LogManager
806             // subclass for the custom log manager case
807             processParentHandlers(logger, name, VisitedLoggers.NEVER);
808
809             // Find the new node and its parent.
810             LogNode node = getNode(name);
811             node.loggerRef = ref;
812             Logger parent = null;
813             LogNode nodep = node.parent;
814             while (nodep != null) {
815                 LoggerWeakRef nodeRef = nodep.loggerRef;
816                 if (nodeRef != null) {
817                     parent = nodeRef.get();
818                     if (parent != null) {
819                         break;
820                     }
821                 }
822                 nodep = nodep.parent;
823             }
824
825             if (parent != null) {
826                 doSetParent(logger, parent);
827             }
828             // Walk over the children and tell them we are their new parent.
829             node.walkAndSetParent(logger);
830             // new LogNode is ready so tell the LoggerWeakRef about it
831             ref.setNode(node);
832
833             // Do not publish 'ref' in namedLoggers before the logger tree
834             // is fully updated - because the named logger will be visible as
835             // soon as it is published in namedLoggers (findLogger takes
836             // benefit of the ConcurrentHashMap implementation of namedLoggers
837             // to avoid synchronizing on retrieval when that is possible).
838             namedLoggers.put(name, ref);
839             return true;
840         }
841
842         void removeLoggerRef(String name, LoggerWeakRef ref) {
843             namedLoggers.remove(name, ref);
844         }
845
846         synchronized Enumeration<String> getLoggerNames() {
847             // ensure that this context is properly initialized before
848             // returning logger names.
849             ensureInitialized();
850             return Collections.enumeration(namedLoggers.keySet());
851         }
852
853         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
854         // parents have levels or handlers defined, make sure they are instantiated.
855         private void processParentHandlers(final Logger logger, final String name,
856                Predicate<Logger> visited) {
857             final LogManager owner = getOwner();
858             AccessController.doPrivileged(new PrivilegedAction<Void>() {
859                 @Override
860                 public Void run() {
861                     if (logger != owner.rootLogger) {
862                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers"true);
863                         if (!useParent) {
864                             logger.setUseParentHandlers(false);
865                         }
866                     }
867                     return null;
868                 }
869             });
870
871             int ix = 1;
872             for (;;) {
873                 int ix2 = name.indexOf('.', ix);
874                 if (ix2 < 0) {
875                     break;
876                 }
877                 String pname = name.substring(0, ix2);
878                 if (owner.getProperty(pname + ".level") != null ||
879                     owner.getProperty(pname + ".handlers") != null) {
880                     // This pname has a level/handlers definition.
881                     // Make sure it exists.
882                     if (visited.test(demandLogger(pname, nullnull))) {
883                         break;
884                     }
885                 }
886                 ix = ix2+1;
887             }
888         }
889
890         // Gets a node in our tree of logger nodes.
891         // If necessary, create it.
892         LogNode getNode(String name) {
893             if (name == null || name.equals("")) {
894                 return root;
895             }
896             LogNode node = root;
897             while (name.length() > 0) {
898                 int ix = name.indexOf('.');
899                 String head;
900                 if (ix > 0) {
901                     head = name.substring(0, ix);
902                     name = name.substring(ix + 1);
903                 } else {
904                     head = name;
905                     name = "";
906                 }
907                 if (node.children == null) {
908                     node.children = new HashMap<>();
909                 }
910                 LogNode child = node.children.get(head);
911                 if (child == null) {
912                     child = new LogNode(node, this);
913                     node.children.put(head, child);
914                 }
915                 node = child;
916             }
917             return node;
918         }
919     }
920
921     final class SystemLoggerContext extends LoggerContext {
922         // Add a system logger in the system context's namespace as well as
923         // in the LogManager's namespace if not exist so that there is only
924         // one single logger of the given name.  System loggers are visible
925         // to applications unless a logger of the same name has been added.
926         @Override
927         Logger demandLogger(String name, String resourceBundleName,
928                             Module module) {
929             Logger result = findLogger(name);
930             if (result == null) {
931                 // only allocate the new system logger once
932                 Logger newLogger = new Logger(name, resourceBundleName,
933                                               module, getOwner(), true);
934                 do {
935                     if (addLocalLogger(newLogger)) {
936                         // We successfully added the new Logger that we
937                         // created above so return it without refetching.
938                         result = newLogger;
939                     } else {
940                         // We didn't add the new Logger that we created above
941                         // because another thread added a Logger with the same
942                         // name after our null check above and before our call
943                         // to addLogger(). We have to refetch the Logger because
944                         // addLogger() returns a boolean instead of the Logger
945                         // reference itself. However, if the thread that created
946                         // the other Logger is not holding a strong reference to
947                         // the other Logger, then it is possible for the other
948                         // Logger to be GC'ed after we saw it in addLogger() and
949                         // before we can refetch it. If it has been GC'ed then
950                         // we'll just loop around and try again.
951                         result = findLogger(name);
952                     }
953                 } while (result == null);
954             }
955             return result;
956         }
957     }
958
959     // Add new per logger handlers.
960     // We need to raise privilege here. All our decisions will
961     // be made based on the logging configuration, which can
962     // only be modified by trusted code.
963     private void loadLoggerHandlers(final Logger logger, final String name,
964                                     final String handlersPropertyName)
965     {
966         AccessController.doPrivileged(new PrivilegedAction<Void>() {
967             @Override
968             public Void run() {
969                 setLoggerHandlers(logger, name, handlersPropertyName,
970                     createLoggerHandlers(name, handlersPropertyName));
971                 return null;
972             }
973         });
974     }
975
976     private void setLoggerHandlers(final Logger logger, final String name,
977                                    final String handlersPropertyName,
978                                    List<Handler> handlers)
979     {
980         final boolean ensureCloseOnReset = ! handlers.isEmpty()
981                     && getBooleanProperty(handlersPropertyName + ".ensureCloseOnReset",true);
982         int count = 0;
983         for (Handler hdl : handlers) {
984             logger.addHandler(hdl);
985             if (++count == 1 && ensureCloseOnReset) {
986                 // add this logger to the closeOnResetLoggers list.
987                 closeOnResetLoggers.addIfAbsent(CloseOnReset.create(logger));
988             }
989         }
990     }
991
992     private List<Handler> createLoggerHandlers(final String name,
993                                                final String handlersPropertyName)
994     {
995         String names[] = parseClassNames(handlersPropertyName);
996         List<Handler> handlers = new ArrayList<>(names.length);
997         for (String type : names) {
998             try {
999                 @SuppressWarnings("deprecation")
1000                 Object o = ClassLoader.getSystemClassLoader().loadClass(type).newInstance();
1001                 Handler hdl = (Handler) o;
1002                 // Check if there is a property defining the
1003                 // this handler's level.
1004                 String levs = getProperty(type + ".level");
1005                 if (levs != null) {
1006                     Level l = Level.findLevel(levs);
1007                     if (l != null) {
1008                         hdl.setLevel(l);
1009                     } else {
1010                         // Probably a bad level. Drop through.
1011                         System.err.println("Can't set level for " + type);
1012                     }
1013                 }
1014                 // Add this Handler to the logger
1015                 handlers.add(hdl);
1016             } catch (Exception ex) {
1017                 System.err.println("Can't load log handler \"" + type + "\"");
1018                 System.err.println("" + ex);
1019                 ex.printStackTrace();
1020             }
1021         }
1022
1023         return handlers;
1024     }
1025
1026
1027     // loggerRefQueue holds LoggerWeakRef objects for Logger objects
1028     // that have been GC'ed.
1029     private final ReferenceQueue<Logger> loggerRefQueue
1030         = new ReferenceQueue<>();
1031
1032     // Package-level inner class.
1033     // Helper class for managing WeakReferences to Logger objects.
1034     //
1035     // LogManager.namedLoggers
1036     //     - has weak references to all named Loggers
1037     //     - namedLoggers keeps the LoggerWeakRef objects for the named
1038     //       Loggers around until we can deal with the book keeping for
1039     //       the named Logger that is being GC'ed.
1040     // LogManager.LogNode.loggerRef
1041     //     - has a weak reference to a named Logger
1042     //     - the LogNode will also keep the LoggerWeakRef objects for
1043     //       the named Loggers around; currently LogNodes never go away.
1044     // Logger.kids
1045     //     - has a weak reference to each direct child Logger; this
1046     //       includes anonymous and named Loggers
1047     //     - anonymous Loggers are always children of the rootLogger
1048     //       which is a strong reference; rootLogger.kids keeps the
1049     //       LoggerWeakRef objects for the anonymous Loggers around
1050     //       until we can deal with the book keeping.
1051     //
1052     final class LoggerWeakRef extends WeakReference<Logger> {
1053         private String                name;       // for namedLoggers cleanup
1054         private LogNode               node;       // for loggerRef cleanup
1055         private WeakReference<Logger> parentRef;  // for kids cleanup
1056         private boolean disposed = false;         // avoid calling dispose twice
1057
1058         LoggerWeakRef(Logger logger) {
1059             super(logger, loggerRefQueue);
1060
1061             name = logger.getName();  // save for namedLoggers cleanup
1062         }
1063
1064         // dispose of this LoggerWeakRef object
1065         void dispose() {
1066             // Avoid calling dispose twice. When a Logger is gc'ed, its
1067             // LoggerWeakRef will be enqueued.
1068             // However, a new logger of the same name may be added (or looked
1069             // up) before the queue is drained. When that happens, dispose()
1070             // will be called by addLocalLogger() or findLogger().
1071             // Later when the queue is drained, dispose() will be called again
1072             // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed
1073             // avoids processing the data twice (even though the code should
1074             // now be reentrant).
1075             synchronized(this) {
1076                 // Note to maintainers:
1077                 // Be careful not to call any method that tries to acquire
1078                 // another lock from within this block - as this would surely
1079                 // lead to deadlocks, given that dispose() can be called by
1080                 // multiple threads, and from within different synchronized
1081                 // methods/blocks.
1082                 if (disposed) return;
1083                 disposed = true;
1084             }
1085
1086             final LogNode n = node;
1087             if (n != null) {
1088                 // n.loggerRef can only be safely modified from within
1089                 // a lock on LoggerContext. removeLoggerRef is already
1090                 // synchronized on LoggerContext so calling
1091                 // n.context.removeLoggerRef from within this lock is safe.
1092                 synchronized (n.context) {
1093                     // if we have a LogNode, then we were a named Logger
1094                     // so clear namedLoggers weak ref to us
1095                     n.context.removeLoggerRef(name, this);
1096                     name = null;  // clear our ref to the Logger's name
1097
1098                     // LogNode may have been reused - so only clear
1099                     // LogNode.loggerRef if LogNode.loggerRef == this
1100                     if (n.loggerRef == this) {
1101                         n.loggerRef = null;  // clear LogNode's weak ref to us
1102                     }
1103                     node = null;            // clear our ref to LogNode
1104                 }
1105             }
1106
1107             if (parentRef != null) {
1108                 // this LoggerWeakRef has or had a parent Logger
1109                 Logger parent = parentRef.get();
1110                 if (parent != null) {
1111                     // the parent Logger is still there so clear the
1112                     // parent Logger's weak ref to us
1113                     parent.removeChildLogger(this);
1114                 }
1115                 parentRef = null;  // clear our weak ref to the parent Logger
1116             }
1117         }
1118
1119         // set the node field to the specified value
1120         void setNode(LogNode node) {
1121             this.node = node;
1122         }
1123
1124         // set the parentRef field to the specified value
1125         void setParentRef(WeakReference<Logger> parentRef) {
1126             this.parentRef = parentRef;
1127         }
1128     }
1129
1130     // Package-level method.
1131     // Drain some Logger objects that have been GC'ed.
1132     //
1133     // drainLoggerRefQueueBounded() is called by addLogger() below
1134     // and by Logger.getAnonymousLogger(String) so we'll drain up to
1135     // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
1136     //
1137     // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
1138     // us about a 50/50 mix in increased weak ref counts versus
1139     // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
1140     // Here are stats for cleaning up sets of 400 anonymous Loggers:
1141     //   - test duration 1 minute
1142     //   - sample size of 125 sets of 400
1143     //   - average: 1.99 ms
1144     //   - minimum: 0.57 ms
1145     //   - maximum: 25.3 ms
1146     //
1147     // The same config gives us a better decreased weak ref count
1148     // than increased weak ref count in the LoggerWeakRefLeak test.
1149     // Here are stats for cleaning up sets of 400 named Loggers:
1150     //   - test duration 2 minutes
1151     //   - sample size of 506 sets of 400
1152     //   - average: 0.57 ms
1153     //   - minimum: 0.02 ms
1154     //   - maximum: 10.9 ms
1155     //
1156     private final static int MAX_ITERATIONS = 400;
1157     final void drainLoggerRefQueueBounded() {
1158         for (int i = 0; i < MAX_ITERATIONS; i++) {
1159             if (loggerRefQueue == null) {
1160                 // haven't finished loading LogManager yet
1161                 break;
1162             }
1163
1164             LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
1165             if (ref == null) {
1166                 break;
1167             }
1168             // a Logger object has been GC'ed so clean it up
1169             ref.dispose();
1170         }
1171     }
1172
1173     /**
1174      * Add a named logger.  This does nothing and returns false if a logger
1175      * with the same name is already registered.
1176      * <p>
1177      * The Logger factory methods call this method to register each
1178      * newly created Logger.
1179      * <p>
1180      * The application should retain its own reference to the Logger
1181      * object to avoid it being garbage collected.  The LogManager
1182      * may only retain a weak reference.
1183      *
1184      * @param   logger the new logger.
1185      * @return  true if the argument logger was registered successfully,
1186      *          false if a logger of that name already exists.
1187      * @exception NullPointerException if the logger name is null.
1188      */

1189     public boolean addLogger(Logger logger) {
1190         final String name = logger.getName();
1191         if (name == null) {
1192             throw new NullPointerException();
1193         }
1194         drainLoggerRefQueueBounded();
1195         LoggerContext cx = getUserContext();
1196         if (cx.addLocalLogger(logger) || forceLoadHandlers(logger)) {
1197             // Do we have a per logger handler too?
1198             // Note: this will add a 200ms penalty
1199             loadLoggerHandlers(logger, name, name + ".handlers");
1200             return true;
1201         } else {
1202             return false;
1203         }
1204     }
1205
1206
1207     // Checks whether the given logger is a special logger
1208     // that still requires handler initialization.
1209     // This method will only return true for the root and
1210     // global loggers and only if called by the thread that
1211     // performs initialization of the LogManager, during that
1212     // initialization. Must only be called by addLogger.
1213     @SuppressWarnings("deprecation")
1214     private boolean forceLoadHandlers(Logger logger) {
1215         // Called just after reading the primordial configuration, in
1216         // the same thread that reads it.
1217         // The root and global logger would already be present in the context
1218         // by this point, but we would not have called loadLoggerHandlers
1219         // yet.
1220         return (logger == rootLogger ||  logger == Logger.global)
1221                 && !initializationDone
1222                 && initializedCalled
1223                 && configurationLock.isHeldByCurrentThread();
1224     }
1225
1226     // Private method to set a level on a logger.
1227     // If necessary, we raise privilege before doing the call.
1228     private static void doSetLevel(final Logger logger, final Level level) {
1229         SecurityManager sm = System.getSecurityManager();
1230         if (sm == null) {
1231             // There is no security manager, so things are easy.
1232             logger.setLevel(level);
1233             return;
1234         }
1235         // There is a security manager.  Raise privilege before
1236         // calling setLevel.
1237         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1238             @Override
1239             public Object run() {
1240                 logger.setLevel(level);
1241                 return null;
1242             }});
1243     }
1244
1245     // Private method to set a parent on a logger.
1246     // If necessary, we raise privilege before doing the setParent call.
1247     private static void doSetParent(final Logger logger, final Logger parent) {
1248         SecurityManager sm = System.getSecurityManager();
1249         if (sm == null) {
1250             // There is no security manager, so things are easy.
1251             logger.setParent(parent);
1252             return;
1253         }
1254         // There is a security manager.  Raise privilege before
1255         // calling setParent.
1256         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1257             @Override
1258             public Object run() {
1259                 logger.setParent(parent);
1260                 return null;
1261             }});
1262     }
1263
1264     /**
1265      * Method to find a named logger.
1266      * <p>
1267      * Note that since untrusted code may create loggers with
1268      * arbitrary names this method should not be relied on to
1269      * find Loggers for security sensitive logging.
1270      * It is also important to note that the Logger associated with the
1271      * String {@code name} may be garbage collected at any time if there
1272      * is no strong reference to the Logger. The caller of this method
1273      * must check the return value for null in order to properly handle
1274      * the case where the Logger has been garbage collected.
1275      *
1276      * @param name name of the logger
1277      * @return  matching logger or null if none is found
1278      */

1279     public Logger getLogger(String name) {
1280         return getUserContext().findLogger(name);
1281     }
1282
1283     /**
1284      * Get an enumeration of known logger names.
1285      * <p>
1286      * Note:  Loggers may be added dynamically as new classes are loaded.
1287      * This method only reports on the loggers that are currently registered.
1288      * It is also important to note that this method only returns the name
1289      * of a Logger, not a strong reference to the Logger itself.
1290      * The returned String does nothing to prevent the Logger from being
1291      * garbage collected. In particular, if the returned name is passed
1292      * to {@code LogManager.getLogger()}, then the caller must check the
1293      * return value from {@code LogManager.getLogger()} for null to properly
1294      * handle the case where the Logger has been garbage collected in the
1295      * time since its name was returned by this method.
1296      *
1297      * @return  enumeration of logger name strings
1298      */

1299     public Enumeration<String> getLoggerNames() {
1300         return getUserContext().getLoggerNames();
1301     }
1302
1303     /**
1304      * Reads and initializes the logging configuration.
1305      * <p>
1306      * If the "java.util.logging.config.class" system property is set, then the
1307      * property value is treated as a class name.  The given class will be
1308      * loaded, an object will be instantiated, and that object's constructor
1309      * is responsible for reading in the initial configuration.  (That object
1310      * may use other system properties to control its configuration.)  The
1311      * alternate configuration class can use {@code readConfiguration(InputStream)}
1312      * to define properties in the LogManager.
1313      * <p>
1314      * If "java.util.logging.config.class" system property is <b>not</b> set,
1315      * then this method will read the initial configuration from a properties
1316      * file and calls the {@link #readConfiguration(InputStream)} method to initialize
1317      * the configuration. The "java.util.logging.config.file" system property can be used
1318      * to specify the properties file that will be read as the initial configuration;
1319      * if not set, then the LogManager default configuration is used.
1320      * The default configuration is typically loaded from the
1321      * properties file "{@code conf/logging.properties}" in the Java installation
1322      * directory.
1323      *
1324      * <p>
1325      * Any {@linkplain #addConfigurationListener registered configuration
1326      * listener} will be invoked after the properties are read.
1327      *
1328      * @apiNote This {@code readConfiguration} method should only be used for
1329      * initializing the configuration during LogManager initialization or
1330      * used with the "java.util.logging.config.class" property.
1331      * When this method is called after loggers have been created, and
1332      * the "java.util.logging.config.class" system property is not set, all
1333      * existing loggers will be {@linkplain #reset() reset}. Then any
1334      * existing loggers that have a level property specified in the new
1335      * configuration stream will be {@linkplain
1336      * Logger#setLevel(java.util.logging.Level) set} to the specified log level.
1337      * <p>
1338      * To properly update the logging configuration, use the
1339      * {@link #updateConfiguration(java.util.function.Function)} or
1340      * {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)}
1341      * methods instead.
1342      *
1343      * @throws   SecurityException  if a security manager exists and if
1344      *              the caller does not have LoggingPermission("control").
1345      * @throws   IOException if there are IO problems reading the configuration.
1346      */

1347     public void readConfiguration() throws IOException, SecurityException {
1348         checkPermission();
1349
1350         // if a configuration class is specified, load it and use it.
1351         String cname = System.getProperty("java.util.logging.config.class");
1352         if (cname != null) {
1353             try {
1354                 // Instantiate the named class.  It is its constructor's
1355                 // responsibility to initialize the logging configuration, by
1356                 // calling readConfiguration(InputStream) with a suitable stream.
1357                 try {
1358                     Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
1359                     @SuppressWarnings("deprecation")
1360                     Object witness = clz.newInstance();
1361                     return;
1362                 } catch (ClassNotFoundException ex) {
1363                     Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
1364                     @SuppressWarnings("deprecation")
1365                     Object witness = clz.newInstance();
1366                     return;
1367                 }
1368             } catch (Exception ex) {
1369                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1370                 System.err.println("" + ex);
1371                 // keep going and useful config file.
1372             }
1373         }
1374
1375         String fname = getConfigurationFileName();
1376         try (final InputStream in = new FileInputStream(fname)) {
1377             final BufferedInputStream bin = new BufferedInputStream(in);
1378             readConfiguration(bin);
1379         }
1380     }
1381
1382     String getConfigurationFileName() throws IOException {
1383         String fname = System.getProperty("java.util.logging.config.file");
1384         if (fname == null) {
1385             fname = System.getProperty("java.home");
1386             if (fname == null) {
1387                 throw new Error("Can't find java.home ??");
1388             }
1389             fname = Paths.get(fname, "conf""logging.properties")
1390                     .toAbsolutePath().normalize().toString();
1391         }
1392         return fname;
1393     }
1394
1395     /**
1396      * Reset the logging configuration.
1397      * <p>
1398      * For all named loggers, the reset operation removes and closes
1399      * all Handlers and (except for the root logger) sets the level
1400      * to {@code null}. The root logger's level is set to {@code Level.INFO}.
1401      *
1402      * @apiNote Calling this method also clears the LogManager {@linkplain
1403      * #getProperty(java.lang.String) properties}. The {@link
1404      * #updateConfiguration(java.util.function.Function)
1405      * updateConfiguration(Function)} or
1406      * {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)
1407      * updateConfiguration(InputStream, Function)} method can be used to
1408      * properly update to a new configuration.
1409      *
1410      * @throws  SecurityException  if a security manager exists and if
1411      *             the caller does not have LoggingPermission("control").
1412      */

1413
1414     public void reset() throws SecurityException {
1415         checkPermission();
1416
1417         List<CloseOnReset> persistent;
1418
1419         // We don't want reset() and readConfiguration()
1420         // to run in parallel
1421         configurationLock.lock();
1422         try {
1423             // install new empty properties
1424             props = new Properties();
1425             // make sure we keep the loggers persistent until reset is done.
1426             // Those are the loggers for which we previously created a
1427             // handler from the configuration, and we need to prevent them
1428             // from being gc'ed until those handlers are closed.
1429             persistent = new ArrayList<>(closeOnResetLoggers);
1430             closeOnResetLoggers.clear();
1431
1432             // if reset has been called from shutdown-hook (Cleaner),
1433             // or if reset has been called from readConfiguration() which
1434             // already holds the lock and will change the state itself,
1435             // then do not change state here...
1436             if (globalHandlersState != STATE_SHUTDOWN &&
1437                 globalHandlersState != STATE_READING_CONFIG) {
1438                 // ...else user called reset()...
1439                 // Since we are doing a reset we no longer want to initialize
1440                 // the global handlers, if they haven't been initialized yet.
1441                 globalHandlersState = STATE_INITIALIZED;
1442             }
1443
1444             for (LoggerContext cx : contexts()) {
1445                 resetLoggerContext(cx);
1446             }
1447
1448             persistent.clear();
1449         } finally {
1450             configurationLock.unlock();
1451         }
1452     }
1453
1454     private void resetLoggerContext(LoggerContext cx) {
1455         Enumeration<String> enum_ = cx.getLoggerNames();
1456         while (enum_.hasMoreElements()) {
1457             String name = enum_.nextElement();
1458             Logger logger = cx.findLogger(name);
1459             if (logger != null) {
1460                 resetLogger(logger);
1461             }
1462         }
1463     }
1464
1465     private void closeHandlers(Logger logger) {
1466         Handler[] targets = logger.getHandlers();
1467         for (Handler h : targets) {
1468             logger.removeHandler(h);
1469             try {
1470                 h.close();
1471             } catch (Exception ex) {
1472                 // Problems closing a handler?  Keep going...
1473             } catch (Error e) {
1474                 // ignore Errors while shutting down
1475                 if (globalHandlersState != STATE_SHUTDOWN) {
1476                     throw e;
1477                 }
1478             }
1479         }
1480     }
1481
1482     // Private method to reset an individual target logger.
1483     private void resetLogger(Logger logger) {
1484         // Close all the Logger handlers.
1485         closeHandlers(logger);
1486
1487         // Reset Logger level
1488         String name = logger.getName();
1489         if (name != null && name.equals("")) {
1490             // This is the root logger.
1491             logger.setLevel(defaultLevel);
1492         } else {
1493             logger.setLevel(null);
1494         }
1495     }
1496
1497     // get a list of whitespace separated classnames from a property.
1498     private String[] parseClassNames(String propertyName) {
1499         String hands = getProperty(propertyName);
1500         if (hands == null) {
1501             return new String[0];
1502         }
1503         hands = hands.trim();
1504         int ix = 0;
1505         final List<String> result = new ArrayList<>();
1506         while (ix < hands.length()) {
1507             int end = ix;
1508             while (end < hands.length()) {
1509                 if (Character.isWhitespace(hands.charAt(end))) {
1510                     break;
1511                 }
1512                 if (hands.charAt(end) == ',') {
1513                     break;
1514                 }
1515                 end++;
1516             }
1517             String word = hands.substring(ix, end);
1518             ix = end+1;
1519             word = word.trim();
1520             if (word.length() == 0) {
1521                 continue;
1522             }
1523             result.add(word);
1524         }
1525         return result.toArray(new String[result.size()]);
1526     }
1527
1528     /**
1529      * Reads and initializes the logging configuration from the given input stream.
1530      *
1531      * <p>
1532      * Any {@linkplain #addConfigurationListener registered configuration
1533      * listener} will be invoked after the properties are read.
1534      *
1535      * @apiNote This {@code readConfiguration} method should only be used for
1536      * initializing the configuration during LogManager initialization or
1537      * used with the "java.util.logging.config.class" property.
1538      * When this method is called after loggers have been created, all
1539      * existing loggers will be {@linkplain #reset() reset}. Then any
1540      * existing loggers that have a level property specified in the
1541      * given input stream will be {@linkplain
1542      * Logger#setLevel(java.util.logging.Level) set} to the specified log level.
1543      * <p>
1544      * To properly update the logging configuration, use the
1545      * {@link #updateConfiguration(java.util.function.Function)} or
1546      * {@link #updateConfiguration(java.io.InputStream, java.util.function.Function)}
1547      * method instead.
1548      *
1549      * @param ins  stream to read properties from
1550      * @throws  SecurityException  if a security manager exists and if
1551      *             the caller does not have LoggingPermission("control").
1552      * @throws  IOException if there are problems reading from the stream,
1553      *             or the given stream is not in the
1554      *             {@linkplain java.util.Properties properties file} format.
1555      */

1556     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1557         checkPermission();
1558
1559         // We don't want reset() and readConfiguration() to run
1560         // in parallel.
1561         configurationLock.lock();
1562         try {
1563             if (globalHandlersState == STATE_SHUTDOWN) {
1564                 // already in terminal state: don't even bother
1565                 // to read the configuration
1566                 return;
1567             }
1568
1569             // change state to STATE_READING_CONFIG to signal reset() to not change it
1570             globalHandlersState = STATE_READING_CONFIG;
1571             try {
1572                 // reset configuration which leaves globalHandlersState at STATE_READING_CONFIG
1573                 // so that while reading configuration, any ongoing logging requests block and
1574                 // wait for the outcome (see the end of this try statement)
1575                 reset();
1576
1577                 try {
1578                     // Load the properties
1579                     props.load(ins);
1580                 } catch (IllegalArgumentException x) {
1581                     // props.load may throw an IllegalArgumentException if the stream
1582                     // contains malformed Unicode escape sequences.
1583                     // We wrap that in an IOException as readConfiguration is
1584                     // specified to throw IOException if there are problems reading
1585                     // from the stream.
1586                     // Note: new IOException(x.getMessage(), x) allow us to get a more
1587                     // concise error message than new IOException(x);
1588                     throw new IOException(x.getMessage(), x);
1589                 }
1590
1591                 // Instantiate new configuration objects.
1592                 String names[] = parseClassNames("config");
1593
1594                 for (String word : names) {
1595                     try {
1596                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
1597                         @SuppressWarnings("deprecation")
1598                         Object witness = clz.newInstance();
1599                     } catch (Exception ex) {
1600                         System.err.println("Can't load config class \"" + word + "\"");
1601                         System.err.println("" + ex);
1602                         // ex.printStackTrace();
1603                     }
1604                 }
1605
1606                 // Set levels on any pre-existing loggers, based on the new properties.
1607                 setLevelsOnExistingLoggers();
1608
1609                 // Note that we need to reinitialize global handles when
1610                 // they are first referenced.
1611                 globalHandlersState = STATE_UNINITIALIZED;
1612             } catch (Throwable t) {
1613                 // If there were any trouble, then set state to STATE_INITIALIZED
1614                 // so that no global handlers reinitialization is performed on not fully
1615                 // initialized configuration.
1616                 globalHandlersState = STATE_INITIALIZED;
1617                 // re-throw
1618                 throw t;
1619             }
1620         } finally {
1621             configurationLock.unlock();
1622         }
1623
1624         // should be called out of lock to avoid dead-lock situations
1625         // when user code is involved
1626         invokeConfigurationListeners();
1627     }
1628
1629     // This enum enumerate the configuration properties that will be
1630     // updated on existing loggers when the configuration is updated
1631     // with LogManager.updateConfiguration().
1632     //
1633     // Note that this works properly only for the global LogManager - as
1634     // Handler and its subclasses get their configuration from
1635     // LogManager.getLogManager().
1636     //
1637     static enum ConfigProperty {
1638         LEVEL(".level"), HANDLERS(".handlers"), USEPARENT(".useParentHandlers");
1639         final String suffix;
1640         final int length;
1641         private ConfigProperty(String suffix) {
1642             this.suffix = Objects.requireNonNull(suffix);
1643             length = suffix.length();
1644         }
1645
1646         public boolean handleKey(String key) {
1647             if (this == HANDLERS && suffix.substring(1).equals(key)) return true;
1648             if (this == HANDLERS && suffix.equals(key)) return false;
1649             return key.endsWith(suffix);
1650         }
1651         String key(String loggerName) {
1652             if (this == HANDLERS && (loggerName == null || loggerName.isEmpty())) {
1653                 return suffix.substring(1);
1654             }
1655             return loggerName + suffix;
1656         }
1657         String loggerName(String key) {
1658             assert key.equals(suffix.substring(1)) && this == HANDLERS || key.endsWith(suffix);
1659             if (this == HANDLERS && suffix.substring(1).equals(key)) return "";
1660             return key.substring(0, key.length() - length);
1661         }
1662
1663         /**
1664          * If the property is one that should be updated on existing loggers by
1665          * updateConfiguration, returns the name of the logger for which the
1666          * property is configured. Otherwise, returns null.
1667          * @param property a property key in 'props'
1668          * @return the name of the logger on which the property is to be set,
1669          *         if the property is one that should be updated on existing
1670          *         loggers, {@code null} otherwise.
1671          */

1672         static String getLoggerName(String property) {
1673             for (ConfigProperty p : ConfigProperty.ALL) {
1674                 if (p.handleKey(property)) {
1675                     return p.loggerName(property);
1676                 }
1677             }
1678             return null// Not a property that should be updated.
1679         }
1680
1681         /**
1682          * Find the ConfigProperty corresponding to the given
1683          * property key (may find none).
1684          * @param property a property key in 'props'
1685          * @return An optional containing a ConfigProperty object,
1686          *         if the property is one that should be updated on existing
1687          *         loggers, empty otherwise.
1688          */

1689         static Optional<ConfigProperty> find(String property) {
1690             return ConfigProperty.ALL.stream()
1691                     .filter(p -> p.handleKey(property))
1692                     .findFirst();
1693          }
1694
1695         /**
1696          * Returns true if the given property is one that should be updated
1697          * on existing loggers.
1698          * Used to filter property name streams.
1699          * @param property a property key from the configuration.
1700          * @return true if this property is of interest for updateConfiguration.
1701          */

1702         static boolean matches(String property) {
1703             return find(property).isPresent();
1704         }
1705
1706         /**
1707          * Returns true if the new property value is different from the old,
1708          * and therefore needs to be updated on existing loggers.
1709          * @param k a property key in the configuration
1710          * @param previous the old configuration
1711          * @param next the new configuration
1712          * @return true if the property is changing value between the two
1713          *         configurations.
1714          */

1715         static boolean needsUpdating(String k, Properties previous, Properties next) {
1716             final String p = trim(previous.getProperty(k, null));
1717             final String n = trim(next.getProperty(k, null));
1718             return ! Objects.equals(p,n);
1719         }
1720
1721         /**
1722          * Applies the mapping function for the given key to the next
1723          * configuration.
1724          * If the mapping function is null then this method does nothing.
1725          * Otherwise, it calls the mapping function to compute the value
1726          * that should be associated with {@code key} in the resulting
1727          * configuration, and applies it to {@code next}.
1728          * If the mapping function returns {@code null} the key is removed
1729          * from {@code next}.
1730          *
1731          * @param k a property key in the configuration
1732          * @param previous the old configuration
1733          * @param next the new configuration (modified by this function)
1734          * @param mappingFunction the mapping function.
1735          */

1736         static void merge(String k, Properties previous, Properties next,
1737                           BiFunction<String, String, String> mappingFunction) {
1738             String p = trim(previous.getProperty(k, null));
1739             String n = trim(next.getProperty(k, null));
1740             String mapped = trim(mappingFunction.apply(p,n));
1741             if (!Objects.equals(n, mapped)) {
1742                 if (mapped == null) {
1743                     next.remove(k);
1744                 } else {
1745                     next.setProperty(k, mapped);
1746                 }
1747             }
1748         }
1749
1750         private static final EnumSet<ConfigProperty> ALL =
1751                 EnumSet.allOf(ConfigProperty.class);
1752     }
1753
1754     // trim the value if not null.
1755     private static String trim(String value) {
1756         return value == null ? null : value.trim();
1757     }
1758
1759     /**
1760      * An object that keep track of loggers we have already visited.
1761      * Used when updating configuration, to avoid processing the same logger
1762      * twice.
1763      */

1764     static final class VisitedLoggers implements Predicate<Logger> {
1765         final IdentityHashMap<Logger,Boolean> visited;
1766         private VisitedLoggers(IdentityHashMap<Logger,Boolean> visited) {
1767             this.visited = visited;
1768         }
1769         VisitedLoggers() {
1770             this(new IdentityHashMap<>());
1771         }
1772         @Override
1773         public boolean test(Logger logger) {
1774             return visited != null && visited.put(logger, Boolean.TRUE) != null;
1775         }
1776         public void clear() {
1777             if (visited != null) visited.clear();
1778         }
1779
1780         // An object that considers that no logger has ever been visited.
1781         // This is used when processParentHandlers is called from
1782         // LoggerContext.addLocalLogger
1783         static final VisitedLoggers NEVER = new VisitedLoggers(null);
1784     }
1785
1786
1787     /**
1788      * Type of the modification for a given property. One of SAME, ADDED, CHANGED,
1789      * or REMOVED.
1790      */

1791     static enum ModType {
1792         SAME,    // property had no value in the old and new conf, or had the
1793                  // same value in both.
1794         ADDED,   // property had no value in the old conf, but has one in the new.
1795         CHANGED, // property has a different value in the old conf and the new conf.
1796         REMOVED; // property has no value in the new conf, but had one in the old.
1797         static ModType of(String previous, String next) {
1798             if (previous == null && next != null) {
1799                 return ADDED;
1800             }
1801             if (next == null && previous != null) {
1802                 return REMOVED;
1803             }
1804             if (!Objects.equals(trim(previous), trim(next))) {
1805                 return CHANGED;
1806             }
1807             return SAME;
1808         }
1809     }
1810
1811     /**
1812      * Updates the logging configuration.
1813      * <p>
1814      * If the "java.util.logging.config.file" system property is set,
1815      * then the property value specifies the properties file to be read
1816      * as the new configuration. Otherwise, the LogManager default
1817      * configuration is used.
1818      * <br>The default configuration is typically loaded from the
1819      * properties file "{@code conf/logging.properties}" in the
1820      * Java installation directory.
1821      * <p>
1822      * This method reads the new configuration and calls the {@link
1823      * #updateConfiguration(java.io.InputStream, java.util.function.Function)
1824      * updateConfiguration(ins, mapper)} method to
1825      * update the configuration.
1826      *
1827      * @apiNote
1828      * This method updates the logging configuration from reading
1829      * a properties file and ignores the "java.util.logging.config.class"
1830      * system property.  The "java.util.logging.config.class" property is
1831      * only used by the {@link #readConfiguration()}  method to load a custom
1832      * configuration class as an initial configuration.
1833      *
1834      * @param mapper a functional interface that takes a configuration
1835      *   key <i>k</i> and returns a function <i>f(o,n)</i> whose returned
1836      *   value will be applied to the resulting configuration. The
1837      *   function <i>f</i> may return {@code null} to indicate that the property
1838      *   <i>k</i> will not be added to the resulting configuration.
1839      *   <br>
1840      *   If {@code mapper} is {@code null} then {@code (k) -> ((o, n) -> n)} is
1841      *   assumed.
1842      *   <br>
1843      *   For each <i>k</i>, the mapped function <i>f</i> will
1844      *   be invoked with the value associated with <i>k</i> in the old
1845      *   configuration (i.e <i>o</i>) and the value associated with
1846      *   <i>k</i> in the new configuration (i.e. <i>n</i>).
1847      *   <br>A {@code null} value for <i>o</i> or <i>n</i> indicates that no
1848      *   value was present for <i>k</i> in the corresponding configuration.
1849      *
1850      * @throws  SecurityException  if a security manager exists and if
1851      *          the caller does not have LoggingPermission("control"), or
1852      *          does not have the permissions required to set up the
1853      *          configuration (e.g. open file specified for FileHandlers
1854      *          etc...)
1855      *
1856      * @throws  NullPointerException  if {@code mapper} returns a {@code null}
1857      *         function when invoked.
1858      *
1859      * @throws  IOException if there are problems reading from the
1860      *          logging configuration file.
1861      *
1862      * @see #updateConfiguration(java.io.InputStream, java.util.function.Function)
1863      * @since 9
1864      */

1865     public void updateConfiguration(Function<String, BiFunction<String,String,String>> mapper)
1866             throws IOException {
1867         checkPermission();
1868         ensureLogManagerInitialized();
1869         drainLoggerRefQueueBounded();
1870
1871         String fname = getConfigurationFileName();
1872         try (final InputStream in = new FileInputStream(fname)) {
1873             final BufferedInputStream bin = new BufferedInputStream(in);
1874             updateConfiguration(bin, mapper);
1875         }
1876     }
1877
1878     /**
1879      * Updates the logging configuration.
1880      * <p>
1881      * For each configuration key in the {@linkplain
1882      * #getProperty(java.lang.String) existing configuration} and
1883      * the given input stream configuration, the given {@code mapper} function
1884      * is invoked to map from the configuration key to a function,
1885      * <i>f(o,n)</i>, that takes the old value and new value and returns
1886      * the resulting value to be applied in the resulting configuration,
1887      * as specified in the table below.
1888      * <p>Let <i>k</i> be a configuration key in the old or new configuration,
1889      * <i>o</i> be the old value (i.e. the value associated
1890      * with <i>k</i> in the old configuration), <i>n</i> be the
1891      * new value (i.e. the value associated with <i>k</i> in the new
1892      * configuration), and <i>f</i> be the function returned
1893      * by {@code mapper.apply(}<i>k</i>{@code )}: then <i>v = f(o,n)</i> is the
1894      * resulting value. If <i>v</i> is not {@code null}, then a property
1895      * <i>k</i> with value <i>v</i> will be added to the resulting configuration.
1896      * Otherwise, it will be omitted.
1897      * <br>A {@code null} value may be passed to function
1898      * <i>f</i> to indicate that the corresponding configuration has no
1899      * configuration key <i>k</i>.
1900      * The function <i>f</i> may return {@code null} to indicate that
1901      * there will be no value associated with <i>k</i> in the resulting
1902      * configuration.
1903      * <p>
1904      * If {@code mapper} is {@code null}, then <i>v</i> will be set to
1905      * <i>n</i>.
1906      * <p>
1907      * LogManager {@linkplain #getProperty(java.lang.String) properties} are
1908      * updated with the resulting value in the resulting configuration.
1909      * <p>
1910      * The registered {@linkplain #addConfigurationListener configuration
1911      * listeners} will be invoked after the configuration is successfully updated.
1912      * <br><br>
1913      * <table class="striped">
1914      * <caption style="display:none">Updating configuration properties</caption>
1915      * <thead>
1916      * <tr>
1917      * <th scope="col">Property</th>
1918      * <th scope="col">Resulting Behavior</th>
1919      * </tr>
1920      * </thead>
1921      * <tbody>
1922      * <tr>
1923      * <th scope="row" valign="top">{@code <logger>.level}</th>
1924      * <td>
1925      * <ul>
1926      *   <li>If the resulting configuration defines a level for a logger and
1927      *       if the resulting level is different than the level specified in the
1928      *       the old configuration, or not specified in
1929      *       the old configuration, then if the logger exists or if children for
1930      *       that logger exist, the level for that logger will be updated,
1931      *       and the change propagated to any existing logger children.
1932      *       This may cause the logger to be created, if necessary.
1933      *   </li>
1934      *   <li>If the old configuration defined a level for a logger, and the
1935      *       resulting configuration doesn't, then this change will not be
1936      *       propagated to existing loggers, if any.
1937      *       To completely replace a configuration - the caller should therefore
1938      *       call {@link #reset() reset} to empty the current configuration,
1939      *       before calling {@code updateConfiguration}.
1940      *   </li>
1941      * </ul>
1942      * </td>
1943      * <tr>
1944      * <th scope="row" valign="top">{@code <logger>.useParentHandlers}</th>
1945      * <td>
1946      * <ul>
1947      *   <li>If either the resulting or the old value for the useParentHandlers
1948      *       property is not null, then if the logger exists or if children for
1949      *       that logger exist, that logger will be updated to the resulting
1950      *       value.
1951      *       The value of the useParentHandlers property is the value specified
1952      *       in the configuration; if not specified, the default is true.
1953      *   </li>
1954      * </ul>
1955      * </td>
1956      * </tr>
1957      * <tr>
1958      * <th scope="row" valign="top">{@code <logger>.handlers}</th>
1959      * <td>
1960      * <ul>
1961      *   <li>If the resulting configuration defines a list of handlers for a
1962      *       logger, and if the resulting list is different than the list
1963      *       specified in the old configuration for that logger (that could be
1964      *       empty), then if the logger exists or its children exist, the
1965      *       handlers associated with that logger are closed and removed and
1966      *       the new handlers will be created per the resulting configuration
1967      *       and added to that logger, creating that logger if necessary.
1968      *   </li>
1969      *   <li>If the old configuration defined some handlers for a logger, and
1970      *       the resulting configuration doesn't, if that logger exists,
1971      *       its handlers will be removed and closed.
1972      *   </li>
1973      *   <li>Changing the list of handlers on an existing logger will cause all
1974      *       its previous handlers to be removed and closed, regardless of whether
1975      *       they had been created from the configuration or programmatically.
1976      *       The old handlers will be replaced by new handlers, if any.
1977      *   </li>
1978      * </ul>
1979      * </td>
1980      * </tr>
1981      * <tr>
1982      * <th scope="row" valign="top">{@code <handler-name>.*}</th>
1983      * <td>
1984      * <ul>
1985      *   <li>Properties configured/changed on handler classes will only affect
1986      *       newly created handlers. If a node is configured with the same list
1987      *       of handlers in the old and the resulting configuration, then these
1988      *       handlers will remain unchanged.
1989      *   </li>
1990      * </ul>
1991      * </td>
1992      * </tr>
1993      * <tr>
1994      * <th scope="row" valign="top">{@code config} and any other property</th>
1995      * <td>
1996      * <ul>
1997      *   <li>The resulting value for these property will be stored in the
1998      *   LogManager properties, but {@code updateConfiguration} will not parse
1999      *   or process their values.
2000      *   </li>
2001      * </ul>
2002      * </td>
2003      * </tr>
2004      * </tbody>
2005      * </table>
2006      * <p>
2007      * <em>Example mapper functions:</em>
2008      * <br><br>
2009      * <ul>
2010      * <li>Replace all logging properties with the new configuration:
2011      * <br><br>{@code     (k) -> ((o, n) -> n)}:
2012      * <br><br>this is equivalent to passing a null {@code mapper} parameter.
2013      * </li>
2014      * <li>Merge the new configuration and old configuration and use the
2015      * new value if <i>k</i> exists in the new configuration:
2016      * <br><br>{@code     (k) -> ((o, n) -> n == null ? o : n)}:
2017      * <br><br>as if merging two collections as follows:
2018      * {@code result.putAll(oldc); result.putAll(newc)}.<br></li>
2019      * <li>Merge the new configuration and old configuration and use the old
2020      * value if <i>k</i> exists in the old configuration:
2021      * <br><br>{@code     (k) -> ((o, n) -> o == null ? n : o)}:
2022      * <br><br>as if merging two collections as follows:
2023      * {@code result.putAll(newc); result.putAll(oldc)}.<br></li>
2024      * <li>Replace all properties with the new configuration except the handler
2025      * property to configure Logger's handler that is not root logger:
2026      * <br>
2027      * <pre>{@code (k) -> k.endsWith(".handlers")}
2028      *      {@code     ? ((o, n) -> (o == null ? n : o))}
2029      *      {@code     : ((o, n) -> n)}</pre>
2030      * </li>
2031      * </ul>
2032      * <p>
2033      * To completely reinitialize a configuration, an application can first call
2034      * {@link #reset() reset} to fully remove the old configuration, followed by
2035      * {@code updateConfiguration} to initialize the new configuration.
2036      *
2037      * @param ins    a stream to read properties from
2038      * @param mapper a functional interface that takes a configuration
2039      *   key <i>k</i> and returns a function <i>f(o,n)</i> whose returned
2040      *   value will be applied to the resulting configuration. The
2041      *   function <i>f</i> may return {@code null} to indicate that the property
2042      *   <i>k</i> will not be added to the resulting configuration.
2043      *   <br>
2044      *   If {@code mapper} is {@code null} then {@code (k) -> ((o, n) -> n)} is
2045      *   assumed.
2046      *   <br>
2047      *   For each <i>k</i>, the mapped function <i>f</i> will
2048      *   be invoked with the value associated with <i>k</i> in the old
2049      *   configuration (i.e <i>o</i>) and the value associated with
2050      *   <i>k</i> in the new configuration (i.e. <i>n</i>).
2051      *   <br>A {@code null} value for <i>o</i> or <i>n</i> indicates that no
2052      *   value was present for <i>k</i> in the corresponding configuration.
2053      *
2054      * @throws  SecurityException if a security manager exists and if
2055      *          the caller does not have LoggingPermission("control"), or
2056      *          does not have the permissions required to set up the
2057      *          configuration (e.g. open files specified for FileHandlers)
2058      *
2059      * @throws  NullPointerException if {@code ins} is null or if
2060      *          {@code mapper} returns a null function when invoked.
2061      *
2062      * @throws  IOException if there are problems reading from the stream,
2063      *          or the given stream is not in the
2064      *          {@linkplain java.util.Properties properties file} format.
2065      * @since 9
2066      */

2067     public void updateConfiguration(InputStream ins,
2068             Function<String, BiFunction<String,String,String>> mapper)
2069             throws IOException {
2070         checkPermission();
2071         ensureLogManagerInitialized();
2072         drainLoggerRefQueueBounded();
2073
2074         final Properties previous;
2075         final Set<String> updatePropertyNames;
2076         List<LoggerContext> cxs = Collections.emptyList();
2077         final VisitedLoggers visited = new VisitedLoggers();
2078         final Properties next = new Properties();
2079
2080         try {
2081             // Load the properties
2082             next.load(ins);
2083         } catch (IllegalArgumentException x) {
2084             // props.load may throw an IllegalArgumentException if the stream
2085             // contains malformed Unicode escape sequences.
2086             // We wrap that in an IOException as updateConfiguration is
2087             // specified to throw IOException if there are problems reading
2088             // from the stream.
2089             // Note: new IOException(x.getMessage(), x) allow us to get a more
2090             // concise error message than new IOException(x);
2091             throw new IOException(x.getMessage(), x);
2092         }
2093
2094         if (globalHandlersState == STATE_SHUTDOWN) return;
2095
2096         // exclusive lock: readConfiguration/reset/updateConfiguration can't
2097         //           run concurrently.
2098         // configurationLock.writeLock().lock();
2099         configurationLock.lock();
2100         try {
2101             if (globalHandlersState == STATE_SHUTDOWN) return;
2102             previous = props;
2103
2104             // Builds a TreeSet of all (old and new) property names.
2105             updatePropertyNames =
2106                     Stream.concat(previous.stringPropertyNames().stream(),
2107                                   next.stringPropertyNames().stream())
2108                         .collect(Collectors.toCollection(TreeSet::new));
2109
2110             if (mapper != null) {
2111                 // mapper will potentially modify the content of
2112                 // 'next', so we need to call it before affecting props=next.
2113                 // give a chance to the mapper to control all
2114                 // properties - not just those we will reset.
2115                 updatePropertyNames.stream()
2116                         .forEachOrdered(k -> ConfigProperty
2117                                 .merge(k, previous, next,
2118                                        Objects.requireNonNull(mapper.apply(k))));
2119             }
2120
2121             props = next;
2122
2123             // allKeys will contain all keys:
2124             //    - which correspond to a configuration property we are interested in
2125             //      (first filter)
2126             //    - whose value needs to be updated (because it's new, removed, or
2127             //      different) in the resulting configuration (second filter)
2128             final Stream<String> allKeys = updatePropertyNames.stream()
2129                     .filter(ConfigProperty::matches)
2130                     .filter(k -> ConfigProperty.needsUpdating(k, previous, next));
2131
2132             // Group configuration properties by logger name
2133             // We use a TreeMap so that parent loggers will be visited before
2134             // child loggers.
2135             final Map<String, TreeSet<String>> loggerConfigs =
2136                     allKeys.collect(Collectors.groupingBy(ConfigProperty::getLoggerName,
2137                                     TreeMap::new,
2138                                     Collectors.toCollection(TreeSet::new)));
2139
2140             if (!loggerConfigs.isEmpty()) {
2141                 cxs = contexts();
2142             }
2143             final List<Logger> loggers = cxs.isEmpty()
2144                     ? Collections.emptyList() : new ArrayList<>(cxs.size());
2145             for (Map.Entry<String, TreeSet<String>> e : loggerConfigs.entrySet()) {
2146                 // This can be a logger name, or something else...
2147                 // The only thing we know is that we found a property
2148                 //    we are interested in.
2149                 // For instance, if we found x.y.z.level, then x.y.z could be
2150                 // a logger, but it could also be a handler class...
2151                 // Anyway...
2152                 final String name = e.getKey();
2153                 final Set<String> properties = e.getValue();
2154                 loggers.clear();
2155                 for (LoggerContext cx : cxs) {
2156                     Logger l = cx.findLogger(name);
2157                     if (l != null && !visited.test(l)) {
2158                         loggers.add(l);
2159                     }
2160                 }
2161                 if (loggers.isEmpty()) continue;
2162                 for (String pk : properties) {
2163                     ConfigProperty cp = ConfigProperty.find(pk).get();
2164                     String p = previous.getProperty(pk, null);
2165                     String n = next.getProperty(pk, null);
2166
2167                     // Determines the type of modification.
2168                     ModType mod = ModType.of(p, n);
2169
2170                     // mod == SAME means that the two values are equals, there
2171                     // is nothing to do. Usually, this should not happen as such
2172                     // properties should have been filtered above.
2173                     // It could happen however if the properties had
2174                     // trailing/leading whitespaces.
2175                     if (mod == ModType.SAME) continue;
2176
2177                     switch (cp) {
2178                         case LEVEL:
2179                             if (mod == ModType.REMOVED) continue;
2180                             Level level = Level.findLevel(trim(n));
2181                             if (level != null) {
2182                                 if (name.isEmpty()) {
2183                                     rootLogger.setLevel(level);
2184                                 }
2185                                 for (Logger l : loggers) {
2186                                     if (!name.isEmpty() || l != rootLogger) {
2187                                         l.setLevel(level);
2188                                     }
2189                                 }
2190                             }
2191                             break;
2192                         case USEPARENT:
2193                             if (!name.isEmpty()) {
2194                                 boolean useParent = getBooleanProperty(pk, true);
2195                                 if (n != null || p != null) {
2196                                     // reset the flag only if the previous value
2197                                     // or the new value are not null.
2198                                     for (Logger l : loggers) {
2199                                         l.setUseParentHandlers(useParent);
2200                                     }
2201                                 }
2202                             }
2203                             break;
2204                         case HANDLERS:
2205                             List<Handler> hdls = null;
2206                             if (name.isEmpty()) {
2207                                 // special handling for the root logger.
2208                                 globalHandlersState = STATE_READING_CONFIG;
2209                                 try {
2210                                     closeHandlers(rootLogger);
2211                                     globalHandlersState = STATE_UNINITIALIZED;
2212                                 } catch (Throwable t) {
2213                                     globalHandlersState = STATE_INITIALIZED;
2214                                     throw t;
2215                                 }
2216                             }
2217                             for (Logger l : loggers) {
2218                                 if (l == rootLogger) continue;
2219                                 closeHandlers(l);
2220                                 if (mod == ModType.REMOVED) {
2221                                     closeOnResetLoggers.removeIf(c -> c.logger == l);
2222                                     continue;
2223                                 }
2224                                 if (hdls == null) {
2225                                     hdls = name.isEmpty()
2226                                             ? Arrays.asList(rootLogger.getHandlers())
2227                                             : createLoggerHandlers(name, pk);
2228                                 }
2229                                 setLoggerHandlers(l, name, pk, hdls);
2230                             }
2231                             break;
2232                         defaultbreak;
2233                     }
2234                 }
2235             }
2236         } finally {
2237             configurationLock.unlock();
2238             visited.clear();
2239         }
2240
2241         // Now ensure that if an existing logger has acquired a new parent
2242         // in the configuration, this new parent will be created - if needed,
2243         // and added to the context of the existing child.
2244         //
2245         drainLoggerRefQueueBounded();
2246         for (LoggerContext cx : cxs) {
2247             for (Enumeration<String> names = cx.getLoggerNames() ; names.hasMoreElements();) {
2248                 String name = names.nextElement();
2249                 if (name.isEmpty()) continue;  // don't need to process parents on root.
2250                 Logger l = cx.findLogger(name);
2251                 if (l != null && !visited.test(l)) {
2252                     // should pass visited here to cut the processing when
2253                     // reaching a logger already visited.
2254                     cx.processParentHandlers(l, name, visited);
2255                 }
2256             }
2257         }
2258
2259         // We changed the configuration: invoke configuration listeners
2260         invokeConfigurationListeners();
2261     }
2262
2263     /**
2264      * Get the value of a logging property.
2265      * The method returns null if the property is not found.
2266      * @param name      property name
2267      * @return          property value
2268      */

2269     public String getProperty(String name) {
2270         return props.getProperty(name);
2271     }
2272
2273     // Package private method to get a String property.
2274     // If the property is not defined we return the given
2275     // default value.
2276     String getStringProperty(String name, String defaultValue) {
2277         String val = getProperty(name);
2278         if (val == null) {
2279             return defaultValue;
2280         }
2281         return val.trim();
2282     }
2283
2284     // Package private method to get an integer property.
2285     // If the property is not defined or cannot be parsed
2286     // we return the given default value.
2287     int getIntProperty(String name, int defaultValue) {
2288         String val = getProperty(name);
2289         if (val == null) {
2290             return defaultValue;
2291         }
2292         try {
2293             return Integer.parseInt(val.trim());
2294         } catch (Exception ex) {
2295             return defaultValue;
2296         }
2297     }
2298
2299     // Package private method to get a long property.
2300     // If the property is not defined or cannot be parsed
2301     // we return the given default value.
2302     long getLongProperty(String name, long defaultValue) {
2303         String val = getProperty(name);
2304         if (val == null) {
2305             return defaultValue;
2306         }
2307         try {
2308             return Long.parseLong(val.trim());
2309         } catch (Exception ex) {
2310             return defaultValue;
2311         }
2312     }
2313
2314     // Package private method to get a boolean property.
2315     // If the property is not defined or cannot be parsed
2316     // we return the given default value.
2317     boolean getBooleanProperty(String name, boolean defaultValue) {
2318         String val = getProperty(name);
2319         if (val == null) {
2320             return defaultValue;
2321         }
2322         val = val.toLowerCase();
2323         if (val.equals("true") || val.equals("1")) {
2324             return true;
2325         } else if (val.equals("false") || val.equals("0")) {
2326             return false;
2327         }
2328         return defaultValue;
2329     }
2330
2331     // Package private method to get a Level property.
2332     // If the property is not defined or cannot be parsed
2333     // we return the given default value.
2334     Level getLevelProperty(String name, Level defaultValue) {
2335         String val = getProperty(name);
2336         if (val == null) {
2337             return defaultValue;
2338         }
2339         Level l = Level.findLevel(val.trim());
2340         return l != null ? l : defaultValue;
2341     }
2342
2343     // Package private method to get a filter property.
2344     // We return an instance of the class named by the "name"
2345     // property. If the property is not defined or has problems
2346     // we return the defaultValue.
2347     Filter getFilterProperty(String name, Filter defaultValue) {
2348         String val = getProperty(name);
2349         try {
2350             if (val != null) {
2351                 @SuppressWarnings("deprecation")
2352                 Object o = ClassLoader.getSystemClassLoader().loadClass(val).newInstance();
2353                 return (Filter) o;
2354             }
2355         } catch (Exception ex) {
2356             // We got one of a variety of exceptions in creating the
2357             // class or creating an instance.
2358             // Drop through.
2359         }
2360         // We got an exception.  Return the defaultValue.
2361         return defaultValue;
2362     }
2363
2364
2365     // Package private method to get a formatter property.
2366     // We return an instance of the class named by the "name"
2367     // property. If the property is not defined or has problems
2368     // we return the defaultValue.
2369     Formatter getFormatterProperty(String name, Formatter defaultValue) {
2370         String val = getProperty(name);
2371         try {
2372             if (val != null) {
2373                 @SuppressWarnings("deprecation")
2374                 Object o = ClassLoader.getSystemClassLoader().loadClass(val).newInstance();
2375                 return (Formatter) o;
2376             }
2377         } catch (Exception ex) {
2378             // We got one of a variety of exceptions in creating the
2379             // class or creating an instance.
2380             // Drop through.
2381         }
2382         // We got an exception.  Return the defaultValue.
2383         return defaultValue;
2384     }
2385
2386     // Private method to load the global handlers.
2387     // We do the real work lazily, when the global handlers
2388     // are first used.
2389     private void initializeGlobalHandlers() {
2390         int state = globalHandlersState;
2391         if (state == STATE_INITIALIZED ||
2392             state == STATE_SHUTDOWN) {
2393             // Nothing to doreturn.
2394             return;
2395         }
2396
2397         // If we have not initialized global handlers yet (or need to
2398         // reinitialize them), lets do it now (this case is indicated by
2399         // globalHandlersState == STATE_UNINITIALIZED).
2400         // If we are in the process of initializing global handlers we
2401         // also need to lock & wait (this case is indicated by
2402         // globalHandlersState == STATE_INITIALIZING).
2403         // If we are in the process of reading configuration we also need to
2404         // wait to see what the outcome will be (this case
2405         // is indicated by globalHandlersState == STATE_READING_CONFIG)
2406         // So in either case we need to wait for the lock.
2407         configurationLock.lock();
2408         try {
2409             if (globalHandlersState != STATE_UNINITIALIZED) {
2410                 return// recursive call or nothing to do
2411             }
2412             // set globalHandlersState to STATE_INITIALIZING first to avoid
2413             // getting an infinite recursion when loadLoggerHandlers(...)
2414             // is going to call addHandler(...)
2415             globalHandlersState = STATE_INITIALIZING;
2416             try {
2417                 loadLoggerHandlers(rootLogger, null"handlers");
2418             } finally {
2419                 globalHandlersState = STATE_INITIALIZED;
2420             }
2421         } finally {
2422             configurationLock.unlock();
2423         }
2424     }
2425
2426     static final Permission controlPermission =
2427             new LoggingPermission("control"null);
2428
2429     void checkPermission() {
2430         SecurityManager sm = System.getSecurityManager();
2431         if (sm != null)
2432             sm.checkPermission(controlPermission);
2433     }
2434
2435     /**
2436      * Check that the current context is trusted to modify the logging
2437      * configuration.  This requires LoggingPermission("control").
2438      * <p>
2439      * If the check fails we throw a SecurityException, otherwise
2440      * we return normally.
2441      *
2442      * @exception  SecurityException  if a security manager exists and if
2443      *             the caller does not have LoggingPermission("control").
2444      */

2445     public void checkAccess() throws SecurityException {
2446         checkPermission();
2447     }
2448
2449     // Nested class to represent a node in our tree of named loggers.
2450     private static class LogNode {
2451         HashMap<String,LogNode> children;
2452         LoggerWeakRef loggerRef;
2453         LogNode parent;
2454         final LoggerContext context;
2455
2456         LogNode(LogNode parent, LoggerContext context) {
2457             this.parent = parent;
2458             this.context = context;
2459         }
2460
2461         // Recursive method to walk the tree below a node and set
2462         // a new parent logger.
2463         void walkAndSetParent(Logger parent) {
2464             if (children == null) {
2465                 return;
2466             }
2467             for (LogNode node : children.values()) {
2468                 LoggerWeakRef ref = node.loggerRef;
2469                 Logger logger = (ref == null) ? null : ref.get();
2470                 if (logger == null) {
2471                     node.walkAndSetParent(parent);
2472                 } else {
2473                     doSetParent(logger, parent);
2474                 }
2475             }
2476         }
2477     }
2478
2479     // We use a subclass of Logger for the root logger, so
2480     // that we only instantiate the global handlers when they
2481     // are first needed.
2482     private final class RootLogger extends Logger {
2483         private RootLogger() {
2484             // We do not call the protected Logger two args constructor here,
2485             // to avoid calling LogManager.getLogManager() from within the
2486             // RootLogger constructor.
2487             super(""nullnull, LogManager.thistrue);
2488         }
2489
2490         @Override
2491         public void log(LogRecord record) {
2492             // Make sure that the global handlers have been instantiated.
2493             initializeGlobalHandlers();
2494             super.log(record);
2495         }
2496
2497         @Override
2498         public void addHandler(Handler h) {
2499             initializeGlobalHandlers();
2500             super.addHandler(h);
2501         }
2502
2503         @Override
2504         public void removeHandler(Handler h) {
2505             initializeGlobalHandlers();
2506             super.removeHandler(h);
2507         }
2508
2509         @Override
2510         Handler[] accessCheckedHandlers() {
2511             initializeGlobalHandlers();
2512             return super.accessCheckedHandlers();
2513         }
2514     }
2515
2516
2517     // Private method to be called when the configuration has
2518     // changed to apply any level settings to any pre-existing loggers.
2519     private void setLevelsOnExistingLoggers() {
2520         Enumeration<?> enum_ = props.propertyNames();
2521         while (enum_.hasMoreElements()) {
2522             String key = (String)enum_.nextElement();
2523             if (!key.endsWith(".level")) {
2524                 // Not a level definition.
2525                 continue;
2526             }
2527             int ix = key.length() - 6;
2528             String name = key.substring(0, ix);
2529             Level level = getLevelProperty(key, null);
2530             if (level == null) {
2531                 System.err.println("Bad level value for property: " + key);
2532                 continue;
2533             }
2534             for (LoggerContext cx : contexts()) {
2535                 Logger l = cx.findLogger(name);
2536                 if (l == null) {
2537                     continue;
2538                 }
2539                 l.setLevel(level);
2540             }
2541         }
2542     }
2543
2544     /**
2545      * String representation of the
2546      * {@link javax.management.ObjectName} for the management interface
2547      * for the logging facility.
2548      *
2549      * @see java.lang.management.PlatformLoggingMXBean
2550      *
2551      * @since 1.5
2552      */

2553     public final static String LOGGING_MXBEAN_NAME
2554         = "java.util.logging:type=Logging";
2555
2556     /**
2557      * Returns {@code LoggingMXBean} for managing loggers.
2558      *
2559      * @return a {@link LoggingMXBean} object.
2560      *
2561      * @deprecated {@code java.util.logging.LoggingMXBean} is deprecated and
2562      *      replaced with {@code java.lang.management.PlatformLoggingMXBean}. Use
2563      *      {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
2564      *      ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class)
2565      *      instead.
2566      *
2567      * @see java.lang.management.PlatformLoggingMXBean
2568      * @since 1.5
2569      */

2570     @Deprecated(since="9")
2571     public static synchronized LoggingMXBean getLoggingMXBean() {
2572         return Logging.getInstance();
2573     }
2574
2575     /**
2576      * Adds a configuration listener to be invoked each time the logging
2577      * configuration is read.
2578      * If the listener is already registered the method does nothing.
2579      * <p>
2580      * The listener is invoked with privileges that are restricted by the
2581      * calling context of this method.
2582      * The order in which the listeners are invoked is unspecified.
2583      * <p>
2584      * It is recommended that listeners do not throw errors or exceptions.
2585      *
2586      * If a listener terminates with an uncaught error or exception then
2587      * the first exception will be propagated to the caller of
2588      * {@link #readConfiguration()} (or {@link #readConfiguration(java.io.InputStream)})
2589      * after all listeners have been invoked.
2590      *
2591      * @implNote If more than one listener terminates with an uncaught error or
2592      * exception, an implementation may record the additional errors or
2593      * exceptions as {@linkplain Throwable#addSuppressed(java.lang.Throwable)
2594      * suppressed exceptions}.
2595      *
2596      * @param listener A configuration listener that will be invoked after the
2597      *        configuration changed.
2598      * @return This LogManager.
2599      * @throws SecurityException if a security manager exists and if the
2600      * caller does not have LoggingPermission("control").
2601      * @throws NullPointerException if the listener is null.
2602      *
2603      * @since 9
2604      */

2605     public LogManager addConfigurationListener(Runnable listener) {
2606         final Runnable r = Objects.requireNonNull(listener);
2607         checkPermission();
2608         final SecurityManager sm = System.getSecurityManager();
2609         final AccessControlContext acc =
2610                 sm == null ? null : AccessController.getContext();
2611         final PrivilegedAction<Void> pa =
2612                 acc == null ? null : () -> { r.run() ; return null; };
2613         final Runnable pr =
2614                 acc == null ? r : () -> AccessController.doPrivileged(pa, acc);
2615         // Will do nothing if already registered.
2616         listeners.putIfAbsent(r, pr);
2617         return this;
2618     }
2619
2620     /**
2621      * Removes a previously registered configuration listener.
2622      *
2623      * Returns silently if the listener is not found.
2624      *
2625      * @param listener the configuration listener to remove.
2626      * @throws NullPointerException if the listener is null.
2627      * @throws SecurityException if a security manager exists and if the
2628      * caller does not have LoggingPermission("control").
2629      *
2630      * @since 9
2631      */

2632     public void removeConfigurationListener(Runnable listener) {
2633         final Runnable key = Objects.requireNonNull(listener);
2634         checkPermission();
2635         listeners.remove(key);
2636     }
2637
2638     private void invokeConfigurationListeners() {
2639         Throwable t = null;
2640
2641         // We're using an IdentityHashMap because we want to compare
2642         // keys using identity (==).
2643         // We don't want to loop within a block synchronized on 'listeners'
2644         // to avoid invoking listeners from yet another synchronized block.
2645         // So we're taking a snapshot of the values list to avoid the risk of
2646         // ConcurrentModificationException while looping.
2647         //
2648         for (Runnable c : listeners.values().toArray(new Runnable[0])) {
2649             try {
2650                 c.run();
2651             } catch (ThreadDeath death) {
2652                 throw death;
2653             } catch (Error | RuntimeException x) {
2654                 if (t == null) t = x;
2655                 else t.addSuppressed(x);
2656             }
2657         }
2658         // Listeners are not supposed to throw exceptions, but if that
2659         // happens, we will rethrow the first error or exception that is raised
2660         // after all listeners have been invoked.
2661         if (t instanceof Error) throw (Error)t;
2662         if (t instanceof RuntimeException) throw (RuntimeException)t;
2663     }
2664
2665     /**
2666      * This class allows the {@link LoggingProviderImpl} to demand loggers on
2667      * behalf of system and application classes.
2668      */

2669     private static final class LoggingProviderAccess
2670         implements LoggingProviderImpl.LogManagerAccess,
2671                    PrivilegedAction<Void> {
2672
2673         private LoggingProviderAccess() {
2674         }
2675
2676         /**
2677          * Demands a logger on behalf of the given {@code module}.
2678          * <p>
2679          * If a named logger suitable for the given module is found
2680          * returns it.
2681          * Otherwise, creates a new logger suitable for the given module.
2682          *
2683          * @param name   The logger name.
2684          * @param module The module on which behalf the logger is created/retrieved.
2685          * @return A logger for the given {@code module}.
2686          *
2687          * @throws NullPointerException if {@code name} is {@code null}
2688          *         or {@code module} is {@code null}.
2689          * @throws IllegalArgumentException if {@code manager} is not the default
2690          *         LogManager.
2691          * @throws SecurityException if a security manager is present and the
2692          *         calling code doesn't have the
2693          *        {@link LoggingPermission LoggingPermission("demandLogger"null)}.
2694          */

2695         @Override
2696         public Logger demandLoggerFor(LogManager manager, String name, Module module) {
2697             if (manager != getLogManager()) {
2698                 // having LogManager as parameter just ensures that the
2699                 // caller will have initialized the LogManager before reaching
2700                 // here.
2701                 throw new IllegalArgumentException("manager");
2702             }
2703             Objects.requireNonNull(name);
2704             Objects.requireNonNull(module);
2705             SecurityManager sm = System.getSecurityManager();
2706             if (sm != null) {
2707                 sm.checkPermission(controlPermission);
2708             }
2709             if (isSystem(module)) {
2710                 return manager.demandSystemLogger(name,
2711                     Logger.SYSTEM_LOGGER_RB_NAME, module);
2712             } else {
2713                 return manager.demandLogger(name, null, module);
2714             }
2715         }
2716
2717         @Override
2718         public Void run() {
2719             LoggingProviderImpl.setLogManagerAccess(INSTANCE);
2720             return null;
2721         }
2722
2723         static final LoggingProviderAccess INSTANCE = new LoggingProviderAccess();
2724     }
2725
2726     static {
2727         AccessController.doPrivileged(LoggingProviderAccess.INSTANCE, null,
2728                                       controlPermission);
2729     }
2730
2731 }
2732