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

  36 import sun.misc.JavaAWTAccess;
  37 import sun.misc.ManagedLocalsThread;
  38 import sun.misc.SharedSecrets;
  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 conf/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;.handlers.ensureCloseOnReset". This defines a
 107  * a boolean value. If "&lt;logger&gt;.handlers" is not defined or is empty,
 108  * this property is ignored. Otherwise it defaults to {@code true}. When the
 109  * value is {@code true}, the handlers associated with the logger are guaranteed
 110  * to be closed on {@linkplain #reset} and shutdown. This can be turned off
 111  * by explicitly setting "&lt;logger&gt;.handlers.ensureCloseOnReset=false" in
 112  * the configuration. Note that turning this property off causes the risk of
 113  * introducing a resource leak, as the logger may get garbage collected before
 114  * {@code reset()} is called, thus preventing its handlers from being closed
 115  * on {@code reset()}. In that case it is the responsibility of the application
 116  * to ensure that the handlers are closed before the logger is garbage
 117  * collected.
 118  *
 119  * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
 120  * value. By default every logger calls its parent in addition to
 121  * handling the logging message itself, this often result in messages
 122  * being handled by the root logger as well. When setting this property
 123  * to false a Handler needs to be configured for this logger otherwise
 124  * no logging messages are delivered.
 125  *
 126  * <li>A property "config".  This property is intended to allow
 127  * arbitrary configuration code to be run.  The property defines a
 128  * whitespace or comma separated list of class names.  A new instance will be
 129  * created for each named class.  The default constructor of each class
 130  * may execute arbitrary code to update the logging configuration, such as
 131  * setting logger levels, adding handlers, adding filters, etc.
 132  * </ul>
 133  * <p>
 134  * Note that all classes loaded during LogManager configuration are
 135  * first searched on the system class path before any user class path.
 136  * That includes the LogManager class, any config classes, and any
 137  * handler classes.
 138  * <p>
 139  * Loggers are organized into a naming hierarchy based on their
 140  * dot separated names.  Thus "a.b.c" is a child of "a.b", but
 141  * "a.b1" and a.b2" are peers.
 142  * <p>
 143  * All properties whose names end with ".level" are assumed to define
 144  * log levels for Loggers.  Thus "foo.level" defines a log level for
 145  * the logger called "foo" and (recursively) for any of its children
 146  * in the naming hierarchy.  Log Levels are applied in the order they
 147  * are defined in the properties file.  Thus level settings for child
 148  * nodes in the tree should come after settings for their parents.
 149  * The property name ".level" can be used to set the level for the
 150  * root of the tree.
 151  * <p>
 152  * All methods on the LogManager object are multi-thread safe.
 153  *
 154  * @since 1.4
 155 */
 156 
 157 public class LogManager {
 158     // The global LogManager object
 159     private static final LogManager manager;
 160 
 161     // 'props' is assigned within a lock but accessed without it.
 162     // Declaring it volatile makes sure that another thread will not
 163     // be able to see a partially constructed 'props' object.
 164     // (seeing a partially constructed 'props' object can result in
 165     // NPE being thrown in Hashtable.get(), because it leaves the door
 166     // open for props.getProperties() to be called before the construcor
 167     // of Hashtable is actually completed).
 168     private volatile Properties props = new Properties();
 169     private final static Level defaultLevel = Level.INFO;
 170 
 171     // LoggerContext for system loggers and user loggers
 172     private final LoggerContext systemContext = new SystemLoggerContext();
 173     private final LoggerContext userContext = new LoggerContext();
 174     // non final field - make it volatile to make sure that other threads
 175     // will see the new value once ensureLogManagerInitialized() has finished
 176     // executing.
 177     private volatile Logger rootLogger;
 178     // Have we done the primordial reading of the configuration file?
 179     // (Must be done after a suitable amount of java.lang.System
 180     // initialization has been done)
 181     private volatile boolean readPrimordialConfiguration;
 182     // Have we initialized global (root) handlers yet?
 183     // This gets set to false in readConfiguration
 184     private boolean initializedGlobalHandlers = true;
 185     // True if JVM death is imminent and the exit hook has been called.
 186     private boolean deathImminent;





 187 
 188     // This list contains the loggers for which some handlers have been
 189     // explicitly configured in the configuration file.
 190     // It prevents these loggers from being arbitrarily garbage collected.
 191     private static final class CloseOnReset {
 192         private final Logger logger;
 193         private CloseOnReset(Logger ref) {
 194             this.logger = Objects.requireNonNull(ref);
 195         }
 196         @Override
 197         public boolean equals(Object other) {
 198             return (other instanceof CloseOnReset) && ((CloseOnReset)other).logger == logger;
 199         }
 200         @Override
 201         public int hashCode() {
 202             return System.identityHashCode(logger);
 203         }
 204         public Logger get() {
 205             return logger;
 206         }
 207         public static CloseOnReset create(Logger logger) {
 208             return new CloseOnReset(logger);
 209         }
 210     }
 211     private final CopyOnWriteArrayList<CloseOnReset> closeOnResetLoggers =
 212             new CopyOnWriteArrayList<>();
 213 
 214 
 215     private final Map<Object, Runnable> listeners =
 216             Collections.synchronizedMap(new IdentityHashMap<>());
 217 
 218     static {
 219         manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
 220             @Override
 221             public LogManager run() {
 222                 LogManager mgr = null;
 223                 String cname = null;
 224                 try {
 225                     cname = System.getProperty("java.util.logging.manager");
 226                     if (cname != null) {
 227                         try {
 228                             Class<?> clz = ClassLoader.getSystemClassLoader()
 229                                     .loadClass(cname);
 230                             mgr = (LogManager) clz.newInstance();
 231                         } catch (ClassNotFoundException ex) {
 232                             Class<?> clz = Thread.currentThread()
 233                                     .getContextClassLoader().loadClass(cname);
 234                             mgr = (LogManager) clz.newInstance();
 235                         }
 236                     }
 237                 } catch (Exception ex) {
 238                     System.err.println("Could not load Logmanager \"" + cname + "\"");
 239                     ex.printStackTrace();
 240                 }
 241                 if (mgr == null) {
 242                     mgr = new LogManager();
 243                 }
 244                 return mgr;
 245 
 246             }
 247         });
 248     }
 249 
 250     // This private class is used as a shutdown hook.
 251     // It does a "reset" to close all open handlers.
 252     private class Cleaner extends ManagedLocalsThread {
 253 
 254         private Cleaner() {
 255             /* Set context class loader to null in order to avoid
 256              * keeping a strong reference to an application classloader.
 257              */
 258             this.setContextClassLoader(null);
 259         }
 260 
 261         @Override
 262         public void run() {
 263             // This is to ensure the LogManager.<clinit> is completed
 264             // before synchronized block. Otherwise deadlocks are possible.
 265             LogManager mgr = manager;
 266 
 267             // If the global handlers haven't been initialized yet, we
 268             // don't want to initialize them just so we can close them!
 269             synchronized (LogManager.this) {
 270                 // Note that death is imminent.
 271                 deathImminent = true;
 272                 initializedGlobalHandlers = true;
 273             }
 274 
 275             // Do a reset to close all active handlers.
 276             reset();






 277         }
 278     }
 279 
 280 
 281     /**
 282      * Protected constructor.  This is protected so that container applications
 283      * (such as J2EE containers) can subclass the object.  It is non-public as
 284      * it is intended that there only be one LogManager object, whose value is
 285      * retrieved by calling LogManager.getLogManager.
 286      */
 287     protected LogManager() {
 288         this(checkSubclassPermissions());
 289     }
 290 
 291     private LogManager(Void checked) {
 292 
 293         // Add a shutdown hook to close the global handlers.
 294         try {
 295             Runtime.getRuntime().addShutdownHook(new Cleaner());
 296         } catch (IllegalStateException e) {
 297             // If the VM is already shutting down,
 298             // We do not need to register shutdownHook.
 299         }
 300     }
 301 
 302     private static Void checkSubclassPermissions() {
 303         final SecurityManager sm = System.getSecurityManager();
 304         if (sm != null) {
 305             // These permission will be checked in the LogManager constructor,
 306             // in order to register the Cleaner() thread as a shutdown hook.
 307             // Check them here to avoid the penalty of constructing the object
 308             // etc...
 309             sm.checkPermission(new RuntimePermission("shutdownHooks"));
 310             sm.checkPermission(new RuntimePermission("setContextClassLoader"));
 311         }
 312         return null;
 313     }
 314 
 315     /**
 316      * Lazy initialization: if this instance of manager is the global
 317      * manager then this method will read the initial configuration and
 318      * add the root logger and global logger by calling addLogger().
 319      *
 320      * Note that it is subtly different from what we do in LoggerContext.
 321      * In LoggerContext we're patching up the logger context tree in order to add
 322      * the root and global logger *to the context tree*.
 323      *
 324      * For this to work, addLogger() must have already have been called
 325      * once on the LogManager instance for the default logger being
 326      * added.
 327      *
 328      * This is why ensureLogManagerInitialized() needs to be called before
 329      * any logger is added to any logger context.
 330      *
 331      */
 332     private boolean initializedCalled = false;
 333     private volatile boolean initializationDone = false;
 334     final void ensureLogManagerInitialized() {
 335         final LogManager owner = this;
 336         if (initializationDone || owner != manager) {
 337             // we don't want to do this twice, and we don't want to do
 338             // this on private manager instances.
 339             return;
 340         }
 341 
 342         // Maybe another thread has called ensureLogManagerInitialized()
 343         // before us and is still executing it. If so we will block until
 344         // the log manager has finished initialized, then acquire the monitor,
 345         // notice that initializationDone is now true and return.
 346         // Otherwise - we have come here first! We will acquire the monitor,
 347         // see that initializationDone is still false, and perform the
 348         // initialization.
 349         //
 350         synchronized(this) {
 351             // If initializedCalled is true it means that we're already in
 352             // the process of initializing the LogManager in this thread.
 353             // There has been a recursive call to ensureLogManagerInitialized().
 354             final boolean isRecursiveInitialization = (initializedCalled == true);
 355 
 356             assert initializedCalled || !initializationDone
 357                     : "Initialization can't be done if initialized has not been called!";
 358 
 359             if (isRecursiveInitialization || initializationDone) {
 360                 // If isRecursiveInitialization is true it means that we're
 361                 // already in the process of initializing the LogManager in
 362                 // this thread. There has been a recursive call to
 363                 // ensureLogManagerInitialized(). We should not proceed as
 364                 // it would lead to infinite recursion.
 365                 //
 366                 // If initializationDone is true then it means the manager
 367                 // has finished initializing; just return: we're done.
 368                 return;
 369             }
 370             // Calling addLogger below will in turn call requiresDefaultLogger()
 371             // which will call ensureLogManagerInitialized().
 372             // We use initializedCalled to break the recursion.
 373             initializedCalled = true;
 374             try {
 375                 AccessController.doPrivileged(new PrivilegedAction<Object>() {
 376                     @Override
 377                     public Object run() {
 378                         assert rootLogger == null;
 379                         assert initializedCalled && !initializationDone;
 380 
 381                         // Read configuration.
 382                         owner.readPrimordialConfiguration();
 383 
 384                         // Create and retain Logger for the root of the namespace.
 385                         owner.rootLogger = owner.new RootLogger();
 386                         owner.addLogger(owner.rootLogger);
 387                         if (!owner.rootLogger.isLevelInitialized()) {
 388                             owner.rootLogger.setLevel(defaultLevel);
 389                         }
 390 
 391                         // Adding the global Logger.
 392                         // Do not call Logger.getGlobal() here as this might trigger
 393                         // subtle inter-dependency issues.
 394                         @SuppressWarnings("deprecation")
 395                         final Logger global = Logger.global;
 396 
 397                         // Make sure the global logger will be registered in the
 398                         // global manager
 399                         owner.addLogger(global);
 400                         return null;
 401                     }
 402                 });
 403             } finally {
 404                 initializationDone = true;
 405             }
 406         }
 407     }
 408 
 409     /**
 410      * Returns the global LogManager object.
 411      * @return the global LogManager object
 412      */
 413     public static LogManager getLogManager() {
 414         if (manager != null) {
 415             manager.ensureLogManagerInitialized();
 416         }
 417         return manager;
 418     }
 419 
 420     private void readPrimordialConfiguration() {
 421         if (!readPrimordialConfiguration) {
 422             synchronized (this) {
 423                 if (!readPrimordialConfiguration) {
 424                     // If System.in/out/err are null, it's a good
 425                     // indication that we're still in the
 426                     // bootstrapping phase
 427                     if (System.out == null) {
 428                         return;
 429                     }
 430                     readPrimordialConfiguration = true;
 431 
 432                     try {
 433                         AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
 434                                 @Override
 435                                 public Void run() throws Exception {
 436                                     readConfiguration();
 437 
 438                                     // Platform loggers begin to delegate to java.util.logging.Logger
 439                                     sun.util.logging.PlatformLogger.redirectPlatformLoggers();
 440                                     return null;
 441                                 }
 442                             });
 443                     } catch (Exception ex) {
 444                         assert false : "Exception raised while reading logging configuration: " + ex;
 445                     }
 446                 }
 447             }
 448         }
 449     }
 450 
 451     // LoggerContext maps from AppContext
 452     private WeakHashMap<Object, LoggerContext> contextsMap = null;
 453 
 454     // Returns the LoggerContext for the user code (i.e. application or AppContext).
 455     // Loggers are isolated from each AppContext.
 456     private LoggerContext getUserContext() {
 457         LoggerContext context = null;
 458 
 459         SecurityManager sm = System.getSecurityManager();
 460         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
 461         if (sm != null && javaAwtAccess != null) {
 462             // for each applet, it has its own LoggerContext isolated from others
 463             final Object ecx = javaAwtAccess.getAppletContext();
 464             if (ecx != null) {
 465                 synchronized (javaAwtAccess) {
 466                     // find the AppContext of the applet code
 467                     // will be null if we are in the main app context.
 468                     if (contextsMap == null) {
 469                         contextsMap = new WeakHashMap<>();
 470                     }
 471                     context = contextsMap.get(ecx);
 472                     if (context == null) {
 473                         // Create a new LoggerContext for the applet.
 474                         context = new LoggerContext();
 475                         contextsMap.put(ecx, context);
 476                     }
 477                 }
 478             }
 479         }
 480         // for standalone app, return userContext
 481         return context != null ? context : userContext;
 482     }
 483 
 484     // The system context.
 485     final LoggerContext getSystemContext() {
 486         return systemContext;
 487     }
 488 
 489     private List<LoggerContext> contexts() {
 490         List<LoggerContext> cxs = new ArrayList<>();
 491         cxs.add(getSystemContext());
 492         cxs.add(getUserContext());
 493         return cxs;
 494     }
 495 
 496     // Find or create a specified logger instance. If a logger has
 497     // already been created with the given name it is returned.
 498     // Otherwise a new logger instance is created and registered
 499     // in the LogManager global namespace.
 500     // This method will always return a non-null Logger object.
 501     // Synchronization is not required here. All synchronization for
 502     // adding a new Logger object is handled by addLogger().
 503     //
 504     // This method must delegate to the LogManager implementation to
 505     // add a new Logger or return the one that has been added previously
 506     // as a LogManager subclass may override the addLogger, getLogger,
 507     // readConfiguration, and other methods.
 508     Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
 509         Logger result = getLogger(name);
 510         if (result == null) {
 511             // only allocate the new logger once
 512             Logger newLogger = new Logger(name, resourceBundleName, caller, this, false);
 513             do {
 514                 if (addLogger(newLogger)) {
 515                     // We successfully added the new Logger that we
 516                     // created above so return it without refetching.
 517                     return newLogger;
 518                 }
 519 
 520                 // We didn't add the new Logger that we created above
 521                 // because another thread added a Logger with the same
 522                 // name after our null check above and before our call
 523                 // to addLogger(). We have to refetch the Logger because
 524                 // addLogger() returns a boolean instead of the Logger
 525                 // reference itself. However, if the thread that created
 526                 // the other Logger is not holding a strong reference to
 527                 // the other Logger, then it is possible for the other
 528                 // Logger to be GC'ed after we saw it in addLogger() and
 529                 // before we can refetch it. If it has been GC'ed then
 530                 // we'll just loop around and try again.
 531                 result = getLogger(name);
 532             } while (result == null);
 533         }
 534         return result;
 535     }
 536 
 537     Logger demandSystemLogger(String name, String resourceBundleName) {
 538         // Add a system logger in the system context's namespace
 539         final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
 540 
 541         // Add the system logger to the LogManager's namespace if not exist
 542         // so that there is only one single logger of the given name.
 543         // System loggers are visible to applications unless a logger of
 544         // the same name has been added.
 545         Logger logger;
 546         do {
 547             // First attempt to call addLogger instead of getLogger
 548             // This would avoid potential bug in custom LogManager.getLogger
 549             // implementation that adds a logger if does not exist
 550             if (addLogger(sysLogger)) {
 551                 // successfully added the new system logger
 552                 logger = sysLogger;
 553             } else {
 554                 logger = getLogger(name);
 555             }
 556         } while (logger == null);
 557 
 558         // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
 559         if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) {
 560             // if logger already exists but handlers not set
 561             final Logger l = logger;
 562             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 563                 @Override
 564                 public Void run() {
 565                     for (Handler hdl : l.accessCheckedHandlers()) {
 566                         sysLogger.addHandler(hdl);
 567                     }
 568                     return null;
 569                 }
 570             });
 571         }
 572         return sysLogger;
 573     }
 574 
 575     // LoggerContext maintains the logger namespace per context.
 576     // The default LogManager implementation has one system context and user
 577     // context.  The system context is used to maintain the namespace for
 578     // all system loggers and is queried by the system code.  If a system logger
 579     // doesn't exist in the user context, it'll also be added to the user context.
 580     // The user context is queried by the user code and all other loggers are
 581     // added in the user context.
 582     class LoggerContext {
 583         // Table of named Loggers that maps names to Loggers.
 584         private final ConcurrentHashMap<String,LoggerWeakRef> namedLoggers =
 585                 new ConcurrentHashMap<>();
 586         // Tree of named Loggers
 587         private final LogNode root;
 588         private LoggerContext() {
 589             this.root = new LogNode(null, this);
 590         }
 591 
 592 
 593         // Tells whether default loggers are required in this context.
 594         // If true, the default loggers will be lazily added.
 595         final boolean requiresDefaultLoggers() {
 596             final boolean requiresDefaultLoggers = (getOwner() == manager);
 597             if (requiresDefaultLoggers) {
 598                 getOwner().ensureLogManagerInitialized();
 599             }
 600             return requiresDefaultLoggers;
 601         }
 602 
 603         // This context's LogManager.
 604         final LogManager getOwner() {
 605             return LogManager.this;
 606         }
 607 
 608         // This context owner's root logger, which if not null, and if
 609         // the context requires default loggers, will be added to the context
 610         // logger's tree.
 611         final Logger getRootLogger() {
 612             return getOwner().rootLogger;
 613         }
 614 
 615         // The global logger, which if not null, and if
 616         // the context requires default loggers, will be added to the context
 617         // logger's tree.
 618         final Logger getGlobalLogger() {
 619             @SuppressWarnings("deprecation") // avoids initialization cycles.
 620             final Logger global = Logger.global;
 621             return global;
 622         }
 623 
 624         Logger demandLogger(String name, String resourceBundleName) {
 625             // a LogManager subclass may have its own implementation to add and
 626             // get a Logger.  So delegate to the LogManager to do the work.
 627             final LogManager owner = getOwner();
 628             return owner.demandLogger(name, resourceBundleName, null);
 629         }
 630 
 631 
 632         // Due to subtle deadlock issues getUserContext() no longer
 633         // calls addLocalLogger(rootLogger);
 634         // Therefore - we need to add the default loggers later on.
 635         // Checks that the context is properly initialized
 636         // This is necessary before calling e.g. find(name)
 637         // or getLoggerNames()
 638         //
 639         private void ensureInitialized() {
 640             if (requiresDefaultLoggers()) {
 641                 // Ensure that the root and global loggers are set.
 642                 ensureDefaultLogger(getRootLogger());
 643                 ensureDefaultLogger(getGlobalLogger());
 644             }
 645         }
 646 
 647 
 648         Logger findLogger(String name) {
 649             // Attempt to find logger without locking.
 650             LoggerWeakRef ref = namedLoggers.get(name);
 651             Logger logger = ref == null ? null : ref.get();
 652 
 653             // if logger is not null, then we can return it right away.
 654             // if name is "" or "global" and logger is null
 655             // we need to fall through and check that this context is
 656             // initialized.
 657             // if ref is not null and logger is null we also need to
 658             // fall through.
 659             if (logger != null || (ref == null && !name.isEmpty()
 660                     && !name.equals(Logger.GLOBAL_LOGGER_NAME))) {
 661                 return logger;
 662             }
 663 
 664             // We either found a stale reference, or we were looking for
 665             // "" or "global" and didn't find them.
 666             // Make sure context is initialized (has the default loggers),
 667             // and look up again, cleaning the stale reference if it hasn't
 668             // been cleaned up in between. All this needs to be done inside
 669             // a synchronized block.
 670             synchronized(this) {
 671                 // ensure that this context is properly initialized before
 672                 // looking for loggers.
 673                 ensureInitialized();
 674                 ref = namedLoggers.get(name);
 675                 if (ref == null) {
 676                     return null;
 677                 }
 678                 logger = ref.get();
 679                 if (logger == null) {
 680                     // The namedLoggers map holds stale weak reference
 681                     // to a logger which has been GC-ed.
 682                     ref.dispose();
 683                 }
 684                 return logger;
 685             }
 686         }
 687 
 688         // This method is called before adding a logger to the
 689         // context.
 690         // 'logger' is the context that will be added.
 691         // This method will ensure that the defaults loggers are added
 692         // before adding 'logger'.
 693         //
 694         private void ensureAllDefaultLoggers(Logger logger) {
 695             if (requiresDefaultLoggers()) {
 696                 final String name = logger.getName();
 697                 if (!name.isEmpty()) {
 698                     ensureDefaultLogger(getRootLogger());
 699                     if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
 700                         ensureDefaultLogger(getGlobalLogger());
 701                     }
 702                 }
 703             }
 704         }
 705 
 706         private void ensureDefaultLogger(Logger logger) {
 707             // Used for lazy addition of root logger and global logger
 708             // to a LoggerContext.
 709 
 710             // This check is simple sanity: we do not want that this
 711             // method be called for anything else than Logger.global
 712             // or owner.rootLogger.
 713             if (!requiresDefaultLoggers() || logger == null
 714                     || logger != getGlobalLogger() && logger != LogManager.this.rootLogger ) {
 715 
 716                 // the case where we have a non null logger which is neither
 717                 // Logger.global nor manager.rootLogger indicates a serious
 718                 // issue - as ensureDefaultLogger should never be called
 719                 // with any other loggers than one of these two (or null - if
 720                 // e.g manager.rootLogger is not yet initialized)...
 721                 assert logger == null;
 722 
 723                 return;
 724             }
 725 
 726             // Adds the logger if it's not already there.
 727             if (!namedLoggers.containsKey(logger.getName())) {
 728                 // It is important to prevent addLocalLogger to
 729                 // call ensureAllDefaultLoggers when we're in the process
 730                 // off adding one of those default loggers - as this would
 731                 // immediately cause a stack overflow.
 732                 // Therefore we must pass addDefaultLoggersIfNeeded=false,
 733                 // even if requiresDefaultLoggers is true.
 734                 addLocalLogger(logger, false);
 735             }
 736         }
 737 
 738         boolean addLocalLogger(Logger logger) {
 739             // no need to add default loggers if it's not required
 740             return addLocalLogger(logger, requiresDefaultLoggers());
 741         }
 742 
 743         // Add a logger to this context.  This method will only set its level
 744         // and process parent loggers.  It doesn't set its handlers.
 745         synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
 746             // addDefaultLoggersIfNeeded serves to break recursion when adding
 747             // default loggers. If we're adding one of the default loggers
 748             // (we're being called from ensureDefaultLogger()) then
 749             // addDefaultLoggersIfNeeded will be false: we don't want to
 750             // call ensureAllDefaultLoggers again.
 751             //
 752             // Note: addDefaultLoggersIfNeeded can also be false when
 753             //       requiresDefaultLoggers is false - since calling
 754             //       ensureAllDefaultLoggers would have no effect in this case.
 755             if (addDefaultLoggersIfNeeded) {
 756                 ensureAllDefaultLoggers(logger);
 757             }
 758 
 759             final String name = logger.getName();
 760             if (name == null) {
 761                 throw new NullPointerException();
 762             }
 763             LoggerWeakRef ref = namedLoggers.get(name);
 764             if (ref != null) {
 765                 if (ref.get() == null) {
 766                     // It's possible that the Logger was GC'ed after a
 767                     // drainLoggerRefQueueBounded() call above so allow
 768                     // a new one to be registered.
 769                     ref.dispose();
 770                 } else {
 771                     // We already have a registered logger with the given name.
 772                     return false;
 773                 }
 774             }
 775 
 776             // We're adding a new logger.
 777             // Note that we are creating a weak reference here.
 778             final LogManager owner = getOwner();
 779             logger.setLogManager(owner);
 780             ref = owner.new LoggerWeakRef(logger);
 781 
 782             // Apply any initial level defined for the new logger, unless
 783             // the logger's level is already initialized
 784             Level level = owner.getLevelProperty(name + ".level", null);
 785             if (level != null && !logger.isLevelInitialized()) {
 786                 doSetLevel(logger, level);
 787             }
 788 
 789             // instantiation of the handler is done in the LogManager.addLogger
 790             // implementation as a handler class may be only visible to LogManager
 791             // subclass for the custom log manager case
 792             processParentHandlers(logger, name);
 793 
 794             // Find the new node and its parent.
 795             LogNode node = getNode(name);
 796             node.loggerRef = ref;
 797             Logger parent = null;
 798             LogNode nodep = node.parent;
 799             while (nodep != null) {
 800                 LoggerWeakRef nodeRef = nodep.loggerRef;
 801                 if (nodeRef != null) {
 802                     parent = nodeRef.get();
 803                     if (parent != null) {
 804                         break;
 805                     }
 806                 }
 807                 nodep = nodep.parent;
 808             }
 809 
 810             if (parent != null) {
 811                 doSetParent(logger, parent);
 812             }
 813             // Walk over the children and tell them we are their new parent.
 814             node.walkAndSetParent(logger);
 815             // new LogNode is ready so tell the LoggerWeakRef about it
 816             ref.setNode(node);
 817 
 818             // Do not publish 'ref' in namedLoggers before the logger tree
 819             // is fully updated - because the named logger will be visible as
 820             // soon as it is published in namedLoggers (findLogger takes
 821             // benefit of the ConcurrentHashMap implementation of namedLoggers
 822             // to avoid synchronizing on retrieval when that is possible).
 823             namedLoggers.put(name, ref);
 824             return true;
 825         }
 826 
 827         void removeLoggerRef(String name, LoggerWeakRef ref) {
 828             namedLoggers.remove(name, ref);
 829         }
 830 
 831         synchronized Enumeration<String> getLoggerNames() {
 832             // ensure that this context is properly initialized before
 833             // returning logger names.
 834             ensureInitialized();
 835             return Collections.enumeration(namedLoggers.keySet());
 836         }
 837 
 838         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 839         // parents have levels or handlers defined, make sure they are instantiated.
 840         private void processParentHandlers(final Logger logger, final String name) {
 841             final LogManager owner = getOwner();
 842             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 843                 @Override
 844                 public Void run() {
 845                     if (logger != owner.rootLogger) {
 846                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
 847                         if (!useParent) {
 848                             logger.setUseParentHandlers(false);
 849                         }
 850                     }
 851                     return null;
 852                 }
 853             });
 854 
 855             int ix = 1;
 856             for (;;) {
 857                 int ix2 = name.indexOf('.', ix);
 858                 if (ix2 < 0) {
 859                     break;
 860                 }
 861                 String pname = name.substring(0, ix2);
 862                 if (owner.getProperty(pname + ".level") != null ||
 863                     owner.getProperty(pname + ".handlers") != null) {
 864                     // This pname has a level/handlers definition.
 865                     // Make sure it exists.
 866                     demandLogger(pname, null);
 867                 }
 868                 ix = ix2+1;
 869             }
 870         }
 871 
 872         // Gets a node in our tree of logger nodes.
 873         // If necessary, create it.
 874         LogNode getNode(String name) {
 875             if (name == null || name.equals("")) {
 876                 return root;
 877             }
 878             LogNode node = root;
 879             while (name.length() > 0) {
 880                 int ix = name.indexOf('.');
 881                 String head;
 882                 if (ix > 0) {
 883                     head = name.substring(0, ix);
 884                     name = name.substring(ix + 1);
 885                 } else {
 886                     head = name;
 887                     name = "";
 888                 }
 889                 if (node.children == null) {
 890                     node.children = new HashMap<>();
 891                 }
 892                 LogNode child = node.children.get(head);
 893                 if (child == null) {
 894                     child = new LogNode(node, this);
 895                     node.children.put(head, child);
 896                 }
 897                 node = child;
 898             }
 899             return node;
 900         }
 901     }
 902 
 903     final class SystemLoggerContext extends LoggerContext {
 904         // Add a system logger in the system context's namespace as well as
 905         // in the LogManager's namespace if not exist so that there is only
 906         // one single logger of the given name.  System loggers are visible
 907         // to applications unless a logger of the same name has been added.
 908         @Override
 909         Logger demandLogger(String name, String resourceBundleName) {
 910             Logger result = findLogger(name);
 911             if (result == null) {
 912                 // only allocate the new system logger once
 913                 Logger newLogger = new Logger(name, resourceBundleName, null, getOwner(), true);
 914                 do {
 915                     if (addLocalLogger(newLogger)) {
 916                         // We successfully added the new Logger that we
 917                         // created above so return it without refetching.
 918                         result = newLogger;
 919                     } else {
 920                         // We didn't add the new Logger that we created above
 921                         // because another thread added a Logger with the same
 922                         // name after our null check above and before our call
 923                         // to addLogger(). We have to refetch the Logger because
 924                         // addLogger() returns a boolean instead of the Logger
 925                         // reference itself. However, if the thread that created
 926                         // the other Logger is not holding a strong reference to
 927                         // the other Logger, then it is possible for the other
 928                         // Logger to be GC'ed after we saw it in addLogger() and
 929                         // before we can refetch it. If it has been GC'ed then
 930                         // we'll just loop around and try again.
 931                         result = findLogger(name);
 932                     }
 933                 } while (result == null);
 934             }
 935             return result;
 936         }
 937     }
 938 
 939     // Add new per logger handlers.
 940     // We need to raise privilege here. All our decisions will
 941     // be made based on the logging configuration, which can
 942     // only be modified by trusted code.
 943     private void loadLoggerHandlers(final Logger logger, final String name,
 944                                     final String handlersPropertyName)
 945     {
 946         AccessController.doPrivileged(new PrivilegedAction<Object>() {
 947             @Override
 948             public Object run() {
 949                 String names[] = parseClassNames(handlersPropertyName);
 950                 final boolean ensureCloseOnReset = names.length > 0
 951                     && getBooleanProperty(handlersPropertyName + ".ensureCloseOnReset",true);
 952 
 953                 int count = 0;
 954                 for (String type : names) {
 955                     try {
 956                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(type);
 957                         Handler hdl = (Handler) clz.newInstance();
 958                         // Check if there is a property defining the
 959                         // this handler's level.
 960                         String levs = getProperty(type + ".level");
 961                         if (levs != null) {
 962                             Level l = Level.findLevel(levs);
 963                             if (l != null) {
 964                                 hdl.setLevel(l);
 965                             } else {
 966                                 // Probably a bad level. Drop through.
 967                                 System.err.println("Can't set level for " + type);
 968                             }
 969                         }
 970                         // Add this Handler to the logger
 971                         logger.addHandler(hdl);
 972                         if (++count == 1 && ensureCloseOnReset) {
 973                             // add this logger to the closeOnResetLoggers list.
 974                             closeOnResetLoggers.addIfAbsent(CloseOnReset.create(logger));
 975                         }
 976                     } catch (Exception ex) {
 977                         System.err.println("Can't load log handler \"" + type + "\"");
 978                         System.err.println("" + ex);
 979                         ex.printStackTrace();
 980                     }
 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)) {
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      *
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      *
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      * Any {@linkplain #addConfigurationListener registered configuration
1256      * listener} will be invoked after the properties are read.
1257      *
1258      * @exception  SecurityException  if a security manager exists and if
1259      *             the caller does not have LoggingPermission("control").
1260      * @exception  IOException if there are IO problems reading the configuration.
1261      */
1262     public void readConfiguration() throws IOException, SecurityException {
1263         checkPermission();
1264 
1265         // if a configuration class is specified, load it and use it.
1266         String cname = System.getProperty("java.util.logging.config.class");
1267         if (cname != null) {
1268             try {
1269                 // Instantiate the named class.  It is its constructor's
1270                 // responsibility to initialize the logging configuration, by
1271                 // calling readConfiguration(InputStream) with a suitable stream.
1272                 try {
1273                     Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
1274                     clz.newInstance();
1275                     return;
1276                 } catch (ClassNotFoundException ex) {
1277                     Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
1278                     clz.newInstance();
1279                     return;
1280                 }
1281             } catch (Exception ex) {
1282                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1283                 System.err.println("" + ex);
1284                 // keep going and useful config file.
1285             }
1286         }
1287 
1288         String fname = System.getProperty("java.util.logging.config.file");
1289         if (fname == null) {
1290             fname = System.getProperty("java.home");
1291             if (fname == null) {
1292                 throw new Error("Can't find java.home ??");
1293             }
1294             File f = new File(fname, "conf");
1295             f = new File(f, "logging.properties");
1296             fname = f.getCanonicalPath();
1297         }
1298         try (final InputStream in = new FileInputStream(fname)) {
1299             final BufferedInputStream bin = new BufferedInputStream(in);
1300             readConfiguration(bin);
1301         }
1302     }
1303 
1304     /**
1305      * Reset the logging configuration.
1306      * <p>
1307      * For all named loggers, the reset operation removes and closes
1308      * all Handlers and (except for the root logger) sets the level
1309      * to null.  The root logger's level is set to Level.INFO.
1310      *
1311      * @exception  SecurityException  if a security manager exists and if
1312      *             the caller does not have LoggingPermission("control").
1313      */
1314 
1315     public void reset() throws SecurityException {
1316         checkPermission();

1317         List<CloseOnReset> persistent;
1318         synchronized (this) {









1319             props = new Properties();
1320             // make sure we keep the loggers persistent until reset is done.
1321             // Those are the loggers for which we previously created a
1322             // handler from the configuration, and we need to prevent them
1323             // from being gc'ed until those handlers are closed.
1324             persistent = new ArrayList<>(closeOnResetLoggers);
1325             closeOnResetLoggers.clear();

1326             // Since we are doing a reset we no longer want to initialize
1327             // the global handlers, if they haven't been initialized yet.
1328             initializedGlobalHandlers = true;




1329         }

1330         for (LoggerContext cx : contexts()) {










1331             Enumeration<String> enum_ = cx.getLoggerNames();
1332             while (enum_.hasMoreElements()) {
1333                 String name = enum_.nextElement();
1334                 Logger logger = cx.findLogger(name);
1335                 if (logger != null) {
1336                     resetLogger(logger);
1337                 }
1338             }
1339         }
1340         persistent.clear();
1341     }
1342 
1343     // Private method to reset an individual target logger.
1344     private void resetLogger(Logger logger) {
1345         // Close all the Logger's handlers.
1346         Handler[] targets = logger.getHandlers();
1347         for (Handler h : targets) {
1348             logger.removeHandler(h);
1349             try {
1350                 h.close();
1351             } catch (Exception ex) {
1352                 // Problems closing a handler?  Keep going...
1353             }
1354         }








1355         String name = logger.getName();
1356         if (name != null && name.equals("")) {
1357             // This is the root logger.
1358             logger.setLevel(defaultLevel);
1359         } else {
1360             logger.setLevel(null);
1361         }
1362     }
1363 
1364     // get a list of whitespace separated classnames from a property.
1365     private String[] parseClassNames(String propertyName) {
1366         String hands = getProperty(propertyName);
1367         if (hands == null) {
1368             return new String[0];
1369         }
1370         hands = hands.trim();
1371         int ix = 0;
1372         final List<String> result = new ArrayList<>();
1373         while (ix < hands.length()) {
1374             int end = ix;
1375             while (end < hands.length()) {
1376                 if (Character.isWhitespace(hands.charAt(end))) {
1377                     break;
1378                 }
1379                 if (hands.charAt(end) == ',') {
1380                     break;
1381                 }
1382                 end++;
1383             }
1384             String word = hands.substring(ix, end);
1385             ix = end+1;
1386             word = word.trim();
1387             if (word.length() == 0) {
1388                 continue;
1389             }
1390             result.add(word);
1391         }
1392         return result.toArray(new String[result.size()]);
1393     }
1394 
1395     /**
1396      * Reinitialize the logging properties and reread the logging configuration
1397      * from the given stream, which should be in java.util.Properties format.
1398      * Any {@linkplain #addConfigurationListener registered configuration
1399      * listener} will be invoked after the properties are read.
1400      * <p>
1401      * Any log level definitions in the new configuration file will be
1402      * applied using Logger.setLevel(), if the target Logger exists.
1403      *
1404      * @param ins       stream to read properties from
1405      * @exception  SecurityException  if a security manager exists and if
1406      *             the caller does not have LoggingPermission("control").
1407      * @exception  IOException if there are problems reading from the stream.
1408      */
1409     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1410         checkPermission();


















1411         reset();
1412 
1413         // Load the properties
1414         try {

1415             props.load(ins);
1416         } catch (IllegalArgumentException x) {
1417             // props.load may throw an IllegalArgumentException if the stream
1418             // contains malformed Unicode escape sequences.
1419             // We wrap that in an IOException as readConfiguration is
1420             // specified to throw IOException if there are problems reading
1421             // from the stream.
1422             // Note: new IOException(x.getMessage(), x) allow us to get a more
1423             // concise error message than new IOException(x);
1424             throw new IOException(x.getMessage(), x);
1425         }
1426 
1427         // Instantiate new configuration objects.
1428         String names[] = parseClassNames("config");
1429 
1430         for (String word : names) {
1431             try {
1432                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
1433                 clz.newInstance();
1434             } catch (Exception ex) {
1435                 System.err.println("Can't load config class \"" + word + "\"");
1436                 System.err.println("" + ex);
1437                 // ex.printStackTrace();
1438             }
1439         }
1440 
1441         // Set levels on any pre-existing loggers, based on the new properties.
1442         setLevelsOnExistingLoggers();
1443 
1444         try {
1445             invokeConfigurationListeners();
1446         } finally {
1447             // Note that we need to reinitialize global handles when
1448             // they are first referenced.
1449             synchronized (this) {
1450                 initializedGlobalHandlers = false;








1451             }



1452         }




1453     }
1454 
1455     /**
1456      * Get the value of a logging property.
1457      * The method returns null if the property is not found.
1458      * @param name      property name
1459      * @return          property value
1460      */
1461     public String getProperty(String name) {
1462         return props.getProperty(name);
1463     }
1464 
1465     // Package private method to get a String property.
1466     // If the property is not defined we return the given
1467     // default value.
1468     String getStringProperty(String name, String defaultValue) {
1469         String val = getProperty(name);
1470         if (val == null) {
1471             return defaultValue;
1472         }
1473         return val.trim();
1474     }
1475 
1476     // Package private method to get an integer property.
1477     // If the property is not defined or cannot be parsed
1478     // we return the given default value.
1479     int getIntProperty(String name, int defaultValue) {
1480         String val = getProperty(name);
1481         if (val == null) {
1482             return defaultValue;
1483         }
1484         try {
1485             return Integer.parseInt(val.trim());
1486         } catch (Exception ex) {
1487             return defaultValue;
1488         }
1489     }
1490 
1491     // Package private method to get a long property.
1492     // If the property is not defined or cannot be parsed
1493     // we return the given default value.
1494     long getLongProperty(String name, long defaultValue) {
1495         String val = getProperty(name);
1496         if (val == null) {
1497             return defaultValue;
1498         }
1499         try {
1500             return Long.parseLong(val.trim());
1501         } catch (Exception ex) {
1502             return defaultValue;
1503         }
1504     }
1505 
1506     // Package private method to get a boolean property.
1507     // If the property is not defined or cannot be parsed
1508     // we return the given default value.
1509     boolean getBooleanProperty(String name, boolean defaultValue) {
1510         String val = getProperty(name);
1511         if (val == null) {
1512             return defaultValue;
1513         }
1514         val = val.toLowerCase();
1515         if (val.equals("true") || val.equals("1")) {
1516             return true;
1517         } else if (val.equals("false") || val.equals("0")) {
1518             return false;
1519         }
1520         return defaultValue;
1521     }
1522 
1523     // Package private method to get a Level property.
1524     // If the property is not defined or cannot be parsed
1525     // we return the given default value.
1526     Level getLevelProperty(String name, Level defaultValue) {
1527         String val = getProperty(name);
1528         if (val == null) {
1529             return defaultValue;
1530         }
1531         Level l = Level.findLevel(val.trim());
1532         return l != null ? l : defaultValue;
1533     }
1534 
1535     // Package private method to get a filter property.
1536     // We return an instance of the class named by the "name"
1537     // property. If the property is not defined or has problems
1538     // we return the defaultValue.
1539     Filter getFilterProperty(String name, Filter defaultValue) {
1540         String val = getProperty(name);
1541         try {
1542             if (val != null) {
1543                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
1544                 return (Filter) clz.newInstance();
1545             }
1546         } catch (Exception ex) {
1547             // We got one of a variety of exceptions in creating the
1548             // class or creating an instance.
1549             // Drop through.
1550         }
1551         // We got an exception.  Return the defaultValue.
1552         return defaultValue;
1553     }
1554 
1555 
1556     // Package private method to get a formatter property.
1557     // We return an instance of the class named by the "name"
1558     // property. If the property is not defined or has problems
1559     // we return the defaultValue.
1560     Formatter getFormatterProperty(String name, Formatter defaultValue) {
1561         String val = getProperty(name);
1562         try {
1563             if (val != null) {
1564                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
1565                 return (Formatter) clz.newInstance();
1566             }
1567         } catch (Exception ex) {
1568             // We got one of a variety of exceptions in creating the
1569             // class or creating an instance.
1570             // Drop through.
1571         }
1572         // We got an exception.  Return the defaultValue.
1573         return defaultValue;
1574     }
1575 
1576     // Private method to load the global handlers.
1577     // We do the real work lazily, when the global handlers
1578     // are first used.
1579     private synchronized void initializeGlobalHandlers() {
1580         if (initializedGlobalHandlers) {


1581             return;
1582         }
1583 
1584         initializedGlobalHandlers = true;
1585 
1586         if (deathImminent) {
1587             // Aaargh...
1588             // The VM is shutting down and our exit hook has been called.
1589             // Avoid allocating global handlers.
1590             return;




1591         }





1592         loadLoggerHandlers(rootLogger, null, "handlers");






1593     }
1594 
1595     static final Permission controlPermission = new LoggingPermission("control", null);
1596 
1597     void checkPermission() {
1598         SecurityManager sm = System.getSecurityManager();
1599         if (sm != null)
1600             sm.checkPermission(controlPermission);
1601     }
1602 
1603     /**
1604      * Check that the current context is trusted to modify the logging
1605      * configuration.  This requires LoggingPermission("control").
1606      * <p>
1607      * If the check fails we throw a SecurityException, otherwise
1608      * we return normally.
1609      *
1610      * @exception  SecurityException  if a security manager exists and if
1611      *             the caller does not have LoggingPermission("control").
1612      */
1613     public void checkAccess() throws SecurityException {
1614         checkPermission();
1615     }
1616 
1617     // Nested class to represent a node in our tree of named loggers.
1618     private static class LogNode {
1619         HashMap<String,LogNode> children;
1620         LoggerWeakRef loggerRef;
1621         LogNode parent;
1622         final LoggerContext context;
1623 
1624         LogNode(LogNode parent, LoggerContext context) {
1625             this.parent = parent;
1626             this.context = context;
1627         }
1628 
1629         // Recursive method to walk the tree below a node and set
1630         // a new parent logger.
1631         void walkAndSetParent(Logger parent) {
1632             if (children == null) {
1633                 return;
1634             }
1635             for (LogNode node : children.values()) {
1636                 LoggerWeakRef ref = node.loggerRef;
1637                 Logger logger = (ref == null) ? null : ref.get();
1638                 if (logger == null) {
1639                     node.walkAndSetParent(parent);
1640                 } else {
1641                     doSetParent(logger, parent);
1642                 }
1643             }
1644         }
1645     }
1646 
1647     // We use a subclass of Logger for the root logger, so
1648     // that we only instantiate the global handlers when they
1649     // are first needed.
1650     private final class RootLogger extends Logger {
1651         private RootLogger() {
1652             // We do not call the protected Logger two args constructor here,
1653             // to avoid calling LogManager.getLogManager() from within the
1654             // RootLogger constructor.
1655             super("", null, null, LogManager.this, true);
1656         }
1657 
1658         @Override
1659         public void log(LogRecord record) {
1660             // Make sure that the global handlers have been instantiated.
1661             initializeGlobalHandlers();
1662             super.log(record);
1663         }
1664 
1665         @Override
1666         public void addHandler(Handler h) {
1667             initializeGlobalHandlers();
1668             super.addHandler(h);
1669         }
1670 
1671         @Override
1672         public void removeHandler(Handler h) {
1673             initializeGlobalHandlers();
1674             super.removeHandler(h);
1675         }
1676 
1677         @Override
1678         Handler[] accessCheckedHandlers() {
1679             initializeGlobalHandlers();
1680             return super.accessCheckedHandlers();
1681         }
1682     }
1683 
1684 
1685     // Private method to be called when the configuration has
1686     // changed to apply any level settings to any pre-existing loggers.
1687     synchronized private void setLevelsOnExistingLoggers() {
1688         Enumeration<?> enum_ = props.propertyNames();
1689         while (enum_.hasMoreElements()) {
1690             String key = (String)enum_.nextElement();
1691             if (!key.endsWith(".level")) {
1692                 // Not a level definition.
1693                 continue;
1694             }
1695             int ix = key.length() - 6;
1696             String name = key.substring(0, ix);
1697             Level level = getLevelProperty(key, null);
1698             if (level == null) {
1699                 System.err.println("Bad level value for property: " + key);
1700                 continue;
1701             }
1702             for (LoggerContext cx : contexts()) {
1703                 Logger l = cx.findLogger(name);
1704                 if (l == null) {
1705                     continue;
1706                 }
1707                 l.setLevel(level);
1708             }
1709         }
1710     }
1711 
1712     // Management Support
1713     private static LoggingMXBean loggingMXBean = null;
1714     /**
1715      * String representation of the
1716      * {@link javax.management.ObjectName} for the management interface
1717      * for the logging facility.
1718      *
1719      * @see java.lang.management.PlatformLoggingMXBean
1720      * @see java.util.logging.LoggingMXBean
1721      *
1722      * @since 1.5
1723      */
1724     public final static String LOGGING_MXBEAN_NAME
1725         = "java.util.logging:type=Logging";
1726 
1727     /**
1728      * Returns <tt>LoggingMXBean</tt> for managing loggers.
1729      * An alternative way to manage loggers is through the
1730      * {@link java.lang.management.PlatformLoggingMXBean} interface
1731      * that can be obtained by calling:
1732      * <pre>
1733      *     PlatformLoggingMXBean logging = {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
1734      *         ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class);
1735      * </pre>
1736      *
1737      * @return a {@link LoggingMXBean} object.
1738      *
1739      * @see java.lang.management.PlatformLoggingMXBean
1740      * @since 1.5
1741      */
1742     public static synchronized LoggingMXBean getLoggingMXBean() {
1743         if (loggingMXBean == null) {
1744             loggingMXBean =  new Logging();
1745         }
1746         return loggingMXBean;
1747     }
1748 
1749     /**
1750      * Adds a configuration listener to be invoked each time the logging
1751      * configuration is read.
1752      * If the listener is already registered the method does nothing.
1753      * <p>
1754      * The listener is invoked with privileges that are restricted by the
1755      * calling context of this method.
1756      * The order in which the listeners are invoked is unspecified.
1757      * <p>
1758      * It is recommended that listeners do not throw errors or exceptions.
1759      *
1760      * If a listener terminates with an uncaught error or exception then
1761      * the first exception will be propagated to the caller of
1762      * {@link #readConfiguration()} (or {@link #readConfiguration(java.io.InputStream)})
1763      * after all listeners have been invoked.
1764      *
1765      * @implNote If more than one listener terminates with an uncaught error or
1766      * exception, an implementation may record the additional errors or
1767      * exceptions as {@linkplain Throwable#addSuppressed(java.lang.Throwable)
1768      * suppressed exceptions}.
1769      *
1770      * @param listener A configuration listener that will be invoked after the
1771      *        configuration changed.
1772      * @return This LogManager.
1773      * @throws SecurityException if a security manager exists and if the
1774      * caller does not have LoggingPermission("control").
1775      * @throws NullPointerException if the listener is null.
1776      *
1777      * @since 1.9
1778      */
1779     public LogManager addConfigurationListener(Runnable listener) {
1780         final Runnable r = Objects.requireNonNull(listener);
1781         checkPermission();
1782         final SecurityManager sm = System.getSecurityManager();
1783         final AccessControlContext acc =
1784                 sm == null ? null : AccessController.getContext();
1785         final PrivilegedAction<Void> pa =
1786                 acc == null ? null : () -> { r.run() ; return null; };
1787         final Runnable pr =
1788                 acc == null ? r : () -> AccessController.doPrivileged(pa, acc);
1789         // Will do nothing if already registered.
1790         listeners.putIfAbsent(r, pr);
1791         return this;
1792     }
1793 
1794     /**
1795      * Removes a previously registered configuration listener.
1796      *
1797      * Returns silently if the listener is not found.
1798      *
1799      * @param listener the configuration listener to remove.
1800      * @throws NullPointerException if the listener is null.
1801      * @throws SecurityException if a security manager exists and if the
1802      * caller does not have LoggingPermission("control").
1803      *
1804      * @since 1.9
1805      */
1806     public void removeConfigurationListener(Runnable listener) {
1807         final Runnable key = Objects.requireNonNull(listener);
1808         checkPermission();
1809         listeners.remove(key);
1810     }
1811 
1812     private void invokeConfigurationListeners() {
1813         Throwable t = null;
1814 
1815         // We're using an IdentityHashMap because we want to compare
1816         // keys using identity (==).
1817         // We don't want to loop within a block synchronized on 'listeners'
1818         // to avoid invoking listeners from yet another synchronized block.
1819         // So we're taking a snapshot of the values list to avoid the risk of
1820         // ConcurrentModificationException while looping.
1821         //
1822         for (Runnable c : listeners.values().toArray(new Runnable[0])) {
1823             try {
1824                 c.run();
1825             } catch (ThreadDeath death) {
1826                 throw death;
1827             } catch (Error | RuntimeException x) {
1828                 if (t == null) t = x;
1829                 else t.addSuppressed(x);
1830             }
1831         }
1832         // Listeners are not supposed to throw exceptions, but if that
1833         // happens, we will rethrow the first error or exception that is raised
1834         // after all listeners have been invoked.
1835         if (t instanceof Error) throw (Error)t;
1836         if (t instanceof RuntimeException) throw (RuntimeException)t;
1837     }
1838 
1839 }
--- EOF ---