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