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