1f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License.  You may obtain a copy of the License at
8f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util.logging;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.beans.PropertyChangeListener;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.beans.PropertyChangeSupport;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.BufferedInputStream;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.File;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileInputStream;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collection;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Enumeration;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Hashtable;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Properties;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.StringTokenizer;
328ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilsonimport libcore.io.IoUtils;
339a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code LogManager} is used to maintain configuration properties of the
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * logging framework, and to manage a hierarchical namespace of all named
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Logger} objects.
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * There is only one global {@code LogManager} instance in the
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * application, which can be get by calling static method
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@link #getLogManager()}. This instance is created and
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * initialized during class initialization and cannot be changed.
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The {@code LogManager} class can be specified by
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * java.util.logging.manager system property, if the property is unavailable or
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * invalid, the default class {@link java.util.logging.LogManager} will
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * be used.
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
499a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson * On initialization, {@code LogManager} reads its configuration from a
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * properties file, which by default is the "lib/logging.properties" in the JRE
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * directory.
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * However, two optional system properties can be used to customize the initial
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * configuration process of {@code LogManager}.
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ul>
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>"java.util.logging.config.class"</li>
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>"java.util.logging.config.file"</li>
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </ul>
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * These two properties can be set in three ways, by the Preferences API, by the
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "java" command line property definitions, or by system property definitions
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * passed to JNI_CreateJavaVM.
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The "java.util.logging.config.class" should specifies a class name. If it is
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * set, this given class will be loaded and instantiated during
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code LogManager} initialization, so that this object's default
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * constructor can read the initial configuration and define properties for
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code LogManager}.
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If "java.util.logging.config.class" property is not set, or it is invalid, or
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * some exception is thrown during the instantiation, then the
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "java.util.logging.config.file" system property can be used to specify a
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * properties file. The {@code LogManager} will read initial
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * configuration from this file.
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If neither of these properties is defined, or some exception is thrown
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * during these two properties using, the {@code LogManager} will read
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * its initial configuration from default properties file, as described above.
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The global logging properties may include:
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <ul>
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>"handlers". This property's values should be a list of class names for
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * handler classes separated by whitespace, these classes must be subclasses of
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Handler} and each must have a default constructor, these
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * classes will be loaded, instantiated and registered as handlers on the root
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Logger} (the {@code Logger} named ""). These
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Handler}s maybe initialized lazily.</li>
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <li>"config". The property defines a list of class names separated by
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * whitespace. Each class must have a default constructor, in which it can
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * update the logging configuration, such as levels, handlers, or filters for
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * some logger, etc. These classes will be loaded and instantiated during
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code LogManager} configuration</li>
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </ul>
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class, together with any handler and configuration classes associated
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * with it, <b>must</b> be loaded from the system classpath when
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code LogManager} configuration occurs.
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Besides global properties, the properties for loggers and Handlers can be
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * specified in the property files. The names of these properties will start
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * with the complete dot separated names for the handlers or loggers.
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * In the {@code LogManager}'s hierarchical namespace,
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Loggers} are organized based on their dot separated names. For
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * example, "x.y.z" is child of "x.y".
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Levels for {@code Loggers} can be defined by properties whose name end
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * with ".level". Thus "alogger.level" defines a level for the logger named as
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "alogger" and for all its children in the naming hierarchy. Log levels
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * properties are read and applied in the same order as they are specified in
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the property file. The root logger's level can be defined by the property
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * named as ".level".
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
114d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson * This class is thread safe. It is an error to synchronize on a
115d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson * {@code LogManager} while synchronized on a {@code Logger}.
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class LogManager {
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
119d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    /** The shared logging permission. */
1208454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes    private static final LoggingPermission perm = new LoggingPermission("control", null);
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
122d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    /** The singleton instance. */
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static LogManager manager;
1249a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The {@code String} value of the {@link LoggingMXBean}'s ObjectName.
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1288454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes    public static final String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging";
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Get the {@code LoggingMXBean} instance. this implementation always throws
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * an UnsupportedOperationException.
1339a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the {@code LoggingMXBean} instance
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static LoggingMXBean getLoggingMXBean() {
1378454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        throw new UnsupportedOperationException();
1389a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson    }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1409a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson    // FIXME: use weak reference to avoid heap memory leak
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Hashtable<String, Logger> loggers;
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
143d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    /** The configuration properties */
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Properties props;
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
146d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    /** the property change listener */
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private PropertyChangeSupport listeners;
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static {
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // init LogManager singleton instance
151ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        String className = System.getProperty("java.util.logging.manager");
152ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        if (className != null) {
153ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes            manager = (LogManager) getInstanceByClass(className);
154ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        }
155ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        if (manager == null) {
156ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes            manager = new LogManager();
157ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
159ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        // read configuration
160ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        try {
161ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes            manager.readConfiguration();
162ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        } catch (Exception e) {
163ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes            e.printStackTrace();
164ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        }
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
166ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        // if global logger has been initialized, set root as its parent
167ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        Logger root = new Logger("", null);
168ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        root.setLevel(Level.INFO);
169ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        Logger.global.setParent(root);
1709a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson
171ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        manager.addLogger(root);
172ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        manager.addLogger(Logger.global);
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Default constructor. This is not public because there should be only one
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code LogManager} instance, which can be get by
178b501914f9448cc0c5852922d217ae11a29c63467Jesse Wilson     * {@code LogManager.getLogManager()}. This is protected so that
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * application can subclass the object.
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected LogManager() {
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        loggers = new Hashtable<String, Logger>();
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        props = new Properties();
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        listeners = new PropertyChangeSupport(this);
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // add shutdown hook to ensure that the associated resource will be
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // freed when JVM exits
187ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes        Runtime.getRuntime().addShutdownHook(new Thread() {
188ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes            @Override public void run() {
189ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes                reset();
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        });
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
195ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes     * Does nothing.
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void checkAccess() {
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Add a given logger into the hierarchical namespace. The
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code Logger.addLogger()} factory methods call this method to add newly
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * created Logger. This returns false if a logger with the given name has
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * existed in the namespace
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Note that the {@code LogManager} may only retain weak references to
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * registered loggers. In order to prevent {@code Logger} objects from being
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * unexpectedly garbage collected it is necessary for <i>applications</i>
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * to maintain references to them.
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </p>
2119a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param logger
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the logger to be added.
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the given logger is added into the namespace
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         successfully, false if the given logger exists in the namespace.
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized boolean addLogger(Logger logger) {
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String name = logger.getName();
219b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (loggers.get(name) != null) {
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        addToFamilyTree(logger, name);
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        loggers.put(name, logger);
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        logger.setManager(this);
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return true;
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void addToFamilyTree(Logger logger, String name) {
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Logger parent = null;
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // find parent
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int lastSeparator;
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String parentName = name;
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while ((lastSeparator = parentName.lastIndexOf('.')) != -1) {
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            parentName = parentName.substring(0, lastSeparator);
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            parent = loggers.get(parentName);
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (parent != null) {
237d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson                setParent(logger, parent);
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
2398454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            } else if (getProperty(parentName + ".level") != null ||
2408454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes                    getProperty(parentName + ".handlers") != null) {
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                parent = Logger.getLogger(parentName);
242d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson                setParent(logger, parent);
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
246b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (parent == null && (parent = loggers.get("")) != null) {
247d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson            setParent(logger, parent);
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // find children
2519a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson        // TODO: performance can be improved here?
252c505c37bdf75d820d389a172bd634d383a4786d1Bjorn Bringert        String nameDot = name + '.';
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Collection<Logger> allLoggers = loggers.values();
2549a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson        for (final Logger child : allLoggers) {
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Logger oldParent = child.getParent();
256ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes            if (parent == oldParent && (name.length() == 0 || child.getName().startsWith(nameDot))) {
2579a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson                final Logger thisLogger = logger;
258ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes                child.setParent(thisLogger);
259b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes                if (oldParent != null) {
2609a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson                    // -- remove from old parent as the parent has been changed
261d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson                    oldParent.children.remove(child);
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Get the logger with the given name.
2699a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            name of logger
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return logger with given name, or {@code null} if nothing is found.
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized Logger getLogger(String name) {
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return loggers.get(name);
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Get a {@code Enumeration} of all registered logger names.
2809a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return enumeration of registered logger names
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized Enumeration<String> getLoggerNames() {
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return loggers.keys();
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Get the global {@code LogManager} instance.
2899a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the global {@code LogManager} instance
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static LogManager getLogManager() {
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return manager;
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Get the value of property with given name.
2989a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of property
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the value of property
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getProperty(String name) {
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return props.getProperty(name);
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Re-initialize the properties and configuration. The initialization
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * process is same as the {@code LogManager} instantiation.
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notice : No {@code PropertyChangeEvent} are fired.
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </p>
3139a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if any IO related problems happened.
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readConfiguration() throws IOException {
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check config class
3198454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        String configClassName = System.getProperty("java.util.logging.config.class");
3208ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson        if (configClassName == null || getInstanceByClass(configClassName) == null) {
3219a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson            // if config class failed, check config file
3228454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            String configFile = System.getProperty("java.util.logging.config.file");
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3248ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson            if (configFile == null) {
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // if cannot find configFile, use default logging.properties
3268454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes                configFile = System.getProperty("java.home") + File.separator + "lib" +
3278454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes                        File.separator + "logging.properties";
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            InputStream input = null;
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
3338ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson                    input = new FileInputStream(configFile);
3348ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson                } catch (IOException exception) {
3358ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson                    // fall back to using the built-in logging.properties file
3368ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson                    input = LogManager.class.getResourceAsStream("logging.properties");
3378ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson                    if (input == null) {
3388ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson                        throw exception;
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
3418ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson                readConfiguration(new BufferedInputStream(input));
3428ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson            } finally {
3438ced42eaddbe441db51cf5538f15ec746c180936Jesse Wilson                IoUtils.closeQuietly(input);
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // use SystemClassLoader to load class from system classpath
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static Object getInstanceByClass(final String className) {
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
3518454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass(className);
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return clazz.newInstance();
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
3558454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes                Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return clazz.newInstance();
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (Exception innerE) {
3588454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes                System.err.println("Loading class '" + className + "' failed");
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                System.err.println(innerE);
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // actual initialization process from a given input stream
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private synchronized void readConfigurationImpl(InputStream ins)
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        reset();
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        props.load(ins);
3709a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson
371c99250a4d619670f2a9410df121eff04fdc9e87cJesse Wilson        // The RI treats the root logger as special. For compatibility, always
372c99250a4d619670f2a9410df121eff04fdc9e87cJesse Wilson        // update the root logger's handlers.
373b501914f9448cc0c5852922d217ae11a29c63467Jesse Wilson        Logger root = loggers.get("");
374b501914f9448cc0c5852922d217ae11a29c63467Jesse Wilson        if (root != null) {
375b501914f9448cc0c5852922d217ae11a29c63467Jesse Wilson            root.setManager(this);
376b501914f9448cc0c5852922d217ae11a29c63467Jesse Wilson        }
377b501914f9448cc0c5852922d217ae11a29c63467Jesse Wilson
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // parse property "config" and apply setting
3798454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        String configs = props.getProperty("config");
380b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (configs != null) {
3818454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            StringTokenizer st = new StringTokenizer(configs, " ");
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (st.hasMoreTokens()) {
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String configerName = st.nextToken();
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                getInstanceByClass(configerName);
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
3879a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // set levels for logger
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Collection<Logger> allLoggers = loggers.values();
3909a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson        for (Logger logger : allLoggers) {
3918454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes            String property = props.getProperty(logger.getName() + ".level");
392b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes            if (property != null) {
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.setLevel(Level.parse(property));
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        listeners.firePropertyChange(null, null, null);
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Re-initialize the properties and configuration from the given
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code InputStream}
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Notice : No {@code PropertyChangeEvent} are fired.
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </p>
4059a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param ins
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the input stream
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if any IO related problems happened.
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void readConfiguration(InputStream ins) throws IOException {
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkAccess();
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readConfigurationImpl(ins);
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Reset configuration.
418ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes     *
419ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes     * <p>All handlers are closed and removed from any named loggers. All loggers'
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * level is set to null, except the root logger's level is set to
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code Level.INFO}.
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
423b501914f9448cc0c5852922d217ae11a29c63467Jesse Wilson    public synchronized void reset() {
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkAccess();
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        props = new Properties();
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Enumeration<String> names = getLoggerNames();
4279a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson        while (names.hasMoreElements()) {
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String name = names.nextElement();
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Logger logger = getLogger(name);
4309a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson            if (logger != null) {
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                logger.reset();
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
4348454d3c5b9778ae359d11cd98ed81c589e951d0aElliott Hughes        Logger root = loggers.get("");
435b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (root != null) {
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            root.setLevel(Level.INFO);
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Add a {@code PropertyChangeListener}, which will be invoked when
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the properties are reread.
4439a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param l
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code PropertyChangeListener} to be added.
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void addPropertyChangeListener(PropertyChangeListener l) {
4489a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson        if (l == null) {
44986acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("l == null");
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkAccess();
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        listeners.addPropertyChangeListener(l);
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Remove a {@code PropertyChangeListener}, do nothing if the given
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * listener is not found.
4589a0fbe99031759393563ee69ac4640f66f182686Jesse Wilson     *
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param l
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code PropertyChangeListener} to be removed.
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void removePropertyChangeListener(PropertyChangeListener l) {
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkAccess();
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        listeners.removePropertyChangeListener(l);
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
466d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson
467d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    /**
468d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * Returns a named logger associated with the supplied resource bundle.
469d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     *
470d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * @param resourceBundleName the resource bundle to associate, or null for
471d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     *      no associated resource bundle.
472d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     */
473d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    synchronized Logger getOrCreate(String name, String resourceBundleName) {
474d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        Logger result = getLogger(name);
475d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        if (result == null) {
476d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson            result = new Logger(name, resourceBundleName);
477d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson            addLogger(result);
478d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        }
479d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        return result;
480d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    }
481d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson
482d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson
483d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    /**
484d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * Sets the parent of this logger in the namespace. Callers must first
485d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * {@link #checkAccess() check security}.
486d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     *
487d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * @param newParent
488d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     *            the parent logger to set.
489d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     */
490d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    synchronized void setParent(Logger logger, Logger newParent) {
491d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        logger.parent = newParent;
492d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson
493d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        if (logger.levelObjVal == null) {
494d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson            setLevelRecursively(logger, null);
495d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        }
496d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        newParent.children.add(logger);
497fb0ec0e650bf8be35acb0d47da0311a7c446aa33Elliott Hughes        logger.updateDalvikLogHandler();
498d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    }
499d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson
500d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    /**
501d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * Sets the level on {@code logger} to {@code newLevel}. Any child loggers
502d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * currently inheriting their level from {@code logger} will be updated
503d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * recursively.
504d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     *
505d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     * @param newLevel the new minimum logging threshold. If null, the logger's
506d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     *      parent level will be used; or {@code Level.INFO} for loggers with no
507d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     *      parent.
508d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson     */
509d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    synchronized void setLevelRecursively(Logger logger, Level newLevel) {
510d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        int previous = logger.levelIntVal;
511d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        logger.levelObjVal = newLevel;
512d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson
513d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        if (newLevel == null) {
514d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson            logger.levelIntVal = logger.parent != null
515d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson                    ? logger.parent.levelIntVal
516d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson                    : Level.INFO.intValue();
517d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        } else {
518d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson            logger.levelIntVal = newLevel.intValue();
519d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        }
520d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson
521d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        if (previous != logger.levelIntVal) {
522d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson            for (Logger child : logger.children) {
523d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson                if (child.levelObjVal == null) {
524d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson                    setLevelRecursively(child, null);
525d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson                }
526d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson            }
527d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson        }
528d9b5d1b899226673e746ad4d9f517244d968e5baJesse Wilson    }
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
530