src/share/classes/java/util/logging/LogManager.java

Print this page




 127  * Loggers are organized into a naming hierarchy based on their
 128  * dot separated names.  Thus "a.b.c" is a child of "a.b", but
 129  * "a.b1" and a.b2" are peers.
 130  * <p>
 131  * All properties whose names end with ".level" are assumed to define
 132  * log levels for Loggers.  Thus "foo.level" defines a log level for
 133  * the logger called "foo" and (recursively) for any of its children
 134  * in the naming hierarchy.  Log Levels are applied in the order they
 135  * are defined in the properties file.  Thus level settings for child
 136  * nodes in the tree should come after settings for their parents.
 137  * The property name ".level" can be used to set the level for the
 138  * root of the tree.
 139  * <p>
 140  * All methods on the LogManager object are multi-thread safe.
 141  *
 142  * @since 1.4
 143 */
 144 
 145 public class LogManager {
 146     // The global LogManager object
 147     private static LogManager manager;
 148 
 149     private Properties props = new Properties();
 150     private final static Level defaultLevel = Level.INFO;
 151 
 152     // The map of the registered listeners. The map value is the registration
 153     // count to allow for cases where the same listener is registered many times.
 154     private final Map<Object,Integer> listenerMap = new HashMap<>();
 155 
 156     // LoggerContext for system loggers and user loggers
 157     private final LoggerContext systemContext = new SystemLoggerContext();
 158     private final LoggerContext userContext = new LoggerContext();
 159     private Logger rootLogger;
 160 


 161     // Have we done the primordial reading of the configuration file?
 162     // (Must be done after a suitable amount of java.lang.System
 163     // initialization has been done)
 164     private volatile boolean readPrimordialConfiguration;
 165     // Have we initialized global (root) handlers yet?
 166     // This gets set to false in readConfiguration
 167     private boolean initializedGlobalHandlers = true;
 168     // True if JVM death is imminent and the exit hook has been called.
 169     private boolean deathImminent;
 170 
 171     static {
 172         AccessController.doPrivileged(new PrivilegedAction<Object>() {
 173                 public Object run() {


 174                     String cname = null;
 175                     try {
 176                         cname = System.getProperty("java.util.logging.manager");
 177                         if (cname != null) {
 178                             try {
 179                                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
 180                                 manager = (LogManager) clz.newInstance();

 181                             } catch (ClassNotFoundException ex) {
 182                                 Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
 183                                 manager = (LogManager) clz.newInstance();

 184                             }
 185                         }
 186                     } catch (Exception ex) {
 187                         System.err.println("Could not load Logmanager \"" + cname + "\"");
 188                         ex.printStackTrace();
 189                     }
 190                     if (manager == null) {
 191                         manager = new LogManager();
 192                     }

 193 
 194                     // Create and retain Logger for the root of the namespace.
 195                     manager.rootLogger = manager.new RootLogger();
 196                     // since by design the global manager's userContext and
 197                     // systemContext don't have their requiresDefaultLoggers
 198                     // flag set - we make sure to add the root logger to
 199                     // the global manager's default contexts here.
 200                     manager.addLogger(manager.rootLogger);
 201                     manager.systemContext.addLocalLogger(manager.rootLogger, false);
 202                     manager.userContext.addLocalLogger(manager.rootLogger, false);
 203 
 204                     // Adding the global Logger. Doing so in the Logger.<clinit>
 205                     // would deadlock with the LogManager.<clinit>.
 206                     // Do not call Logger.getGlobal() here as this might trigger
 207                     // the deadlock too.
 208                     @SuppressWarnings("deprecation")
 209                     final Logger global = Logger.global;
 210                     global.setLogManager(manager);
 211 
 212                     // Make sure the global logger will be registered in the
 213                     // global manager's default contexts.
 214                     manager.addLogger(global);
 215                     manager.systemContext.addLocalLogger(global, false);
 216                     manager.userContext.addLocalLogger(global, false);
 217 
 218                     // We don't call readConfiguration() here, as we may be running
 219                     // very early in the JVM startup sequence.  Instead readConfiguration
 220                     // will be called lazily in getLogManager().
 221                     return null;
 222                 }
 223             });
 224     }
 225 
 226 
 227     // This private class is used as a shutdown hook.
 228     // It does a "reset" to close all open handlers.
 229     private class Cleaner extends Thread {
 230 
 231         private Cleaner() {
 232             /* Set context class loader to null in order to avoid
 233              * keeping a strong reference to an application classloader.
 234              */
 235             this.setContextClassLoader(null);
 236         }
 237 

 238         public void run() {
 239             // This is to ensure the LogManager.<clinit> is completed
 240             // before synchronized block. Otherwise deadlocks are possible.
 241             LogManager mgr = manager;
 242 
 243             // If the global handlers haven't been initialized yet, we
 244             // don't want to initialize them just so we can close them!
 245             synchronized (LogManager.this) {
 246                 // Note that death is imminent.
 247                 deathImminent = true;
 248                 initializedGlobalHandlers = true;
 249             }
 250 
 251             // Do a reset to close all active handlers.
 252             reset();
 253         }
 254     }
 255 
 256 
 257     /**
 258      * Protected constructor.  This is protected so that container applications
 259      * (such as J2EE containers) can subclass the object.  It is non-public as
 260      * it is intended that there only be one LogManager object, whose value is
 261      * retrieved by calling LogManager.getLogManager.
 262      */
 263     protected LogManager() {
 264         // Add a shutdown hook to close the global handlers.
 265         try {
 266             Runtime.getRuntime().addShutdownHook(new Cleaner());
 267         } catch (IllegalStateException e) {
 268             // If the VM is already shutting down,
 269             // We do not need to register shutdownHook.
 270         }
 271     }
 272 
 273     /**



























































































 274      * Returns the global LogManager object.
 275      * @return the global LogManager object
 276      */
 277     public static LogManager getLogManager() {
 278         if (manager != null) {
 279             manager.readPrimordialConfiguration();
 280         }
 281         return manager;
 282     }
 283 
 284     private void readPrimordialConfiguration() {
 285         if (!readPrimordialConfiguration) {
 286             synchronized (this) {
 287                 if (!readPrimordialConfiguration) {
 288                     // If System.in/out/err are null, it's a good
 289                     // indication that we're still in the
 290                     // bootstrapping phase
 291                     if (System.out == null) {
 292                         return;
 293                     }
 294                     readPrimordialConfiguration = true;
 295 
 296                     try {
 297                         AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {

 298                                 public Void run() throws Exception {
 299                                     readConfiguration();
 300 
 301                                     // Platform loggers begin to delegate to java.util.logging.Logger
 302                                     sun.util.logging.PlatformLogger.redirectPlatformLoggers();
 303                                     return null;
 304                                 }
 305                             });
 306                     } catch (Exception ex) {
 307                         // System.err.println("Can't read logging configuration:");
 308                         // ex.printStackTrace();
 309                     }
 310                 }
 311             }
 312         }
 313     }
 314 
 315     /**
 316      * Adds an event listener to be invoked when the logging
 317      * properties are re-read. Adding multiple instances of
 318      * the same event Listener results in multiple entries
 319      * in the property event listener table.
 320      *
 321      * <p><b>WARNING:</b> This method is omitted from this class in all subset
 322      * Profiles of Java SE that do not include the {@code java.beans} package.
 323      * </p>
 324      *
 325      * @param l  event listener
 326      * @exception  SecurityException  if a security manager exists and if
 327      *             the caller does not have LoggingPermission("control").
 328      * @exception NullPointerException if the PropertyChangeListener is null.


 375         if (l != null) {
 376             PropertyChangeListener listener = l;
 377             synchronized (listenerMap) {
 378                 Integer value = listenerMap.get(listener);
 379                 if (value != null) {
 380                     // remove from map if registration count is 1, otherwise
 381                     // just decrement its count
 382                     int i = value.intValue();
 383                     if (i == 1) {
 384                         listenerMap.remove(listener);
 385                     } else {
 386                         assert i > 1;
 387                         listenerMap.put(listener, i - 1);
 388                     }
 389                 }
 390             }
 391         }
 392     }
 393 
 394     // LoggerContext maps from AppContext
 395     private static WeakHashMap<Object, LoggerContext> contextsMap = null;
 396 
 397     // Returns the LoggerContext for the user code (i.e. application or AppContext).
 398     // Loggers are isolated from each AppContext.
 399     private LoggerContext getUserContext() {
 400         LoggerContext context = null;
 401 
 402         SecurityManager sm = System.getSecurityManager();
 403         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
 404         if (sm != null && javaAwtAccess != null) {
 405             // for each applet, it has its own LoggerContext isolated from others
 406             synchronized (javaAwtAccess) {
 407                 // find the AppContext of the applet code
 408                 // will be null if we are in the main app context.
 409                 final Object ecx = javaAwtAccess.getAppletContext();
 410                 if (ecx != null) {
 411                     if (contextsMap == null) {
 412                         contextsMap = new WeakHashMap<>();
 413                     }
 414                     context = contextsMap.get(ecx);
 415                     if (context == null) {
 416                         // Create a new LoggerContext for the applet.
 417                         // The new logger context has its requiresDefaultLoggers
 418                         // flag set to true - so that these loggers will be
 419                         // lazily added when the context is firt accessed.
 420                         context = new LoggerContext(true);
 421                         contextsMap.put(ecx, context);
 422                     }
 423                 }
 424             }
 425         }
 426         // for standalone app, return userContext
 427         return context != null ? context : userContext;
 428     }
 429 





 430     private List<LoggerContext> contexts() {
 431         List<LoggerContext> cxs = new ArrayList<>();
 432         cxs.add(systemContext);
 433         cxs.add(getUserContext());
 434         return cxs;
 435     }
 436 
 437     // Find or create a specified logger instance. If a logger has
 438     // already been created with the given name it is returned.
 439     // Otherwise a new logger instance is created and registered
 440     // in the LogManager global namespace.
 441     // This method will always return a non-null Logger object.
 442     // Synchronization is not required here. All synchronization for
 443     // adding a new Logger object is handled by addLogger().
 444     //
 445     // This method must delegate to the LogManager implementation to
 446     // add a new Logger or return the one that has been added previously
 447     // as a LogManager subclass may override the addLogger, getLogger,
 448     // readConfiguration, and other methods.
 449     Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
 450         Logger result = getLogger(name);
 451         if (result == null) {
 452             // only allocate the new logger once
 453             Logger newLogger = new Logger(name, resourceBundleName, caller);
 454             do {
 455                 if (addLogger(newLogger)) {
 456                     // We successfully added the new Logger that we
 457                     // created above so return it without refetching.
 458                     return newLogger;
 459                 }
 460 
 461                 // We didn't add the new Logger that we created above
 462                 // because another thread added a Logger with the same
 463                 // name after our null check above and before our call
 464                 // to addLogger(). We have to refetch the Logger because
 465                 // addLogger() returns a boolean instead of the Logger
 466                 // reference itself. However, if the thread that created
 467                 // the other Logger is not holding a strong reference to
 468                 // the other Logger, then it is possible for the other
 469                 // Logger to be GC'ed after we saw it in addLogger() and
 470                 // before we can refetch it. If it has been GC'ed then
 471                 // we'll just loop around and try again.
 472                 result = getLogger(name);
 473             } while (result == null);
 474         }
 475         return result;
 476     }
 477 
 478     Logger demandSystemLogger(String name, String resourceBundleName) {
 479         // Add a system logger in the system context's namespace
 480         final Logger sysLogger = systemContext.demandLogger(name, resourceBundleName);
 481 
 482         // Add the system logger to the LogManager's namespace if not exist
 483         // so that there is only one single logger of the given name.
 484         // System loggers are visible to applications unless a logger of
 485         // the same name has been added.
 486         Logger logger;
 487         do {
 488             // First attempt to call addLogger instead of getLogger
 489             // This would avoid potential bug in custom LogManager.getLogger
 490             // implementation that adds a logger if does not exist
 491             if (addLogger(sysLogger)) {
 492                 // successfully added the new system logger
 493                 logger = sysLogger;
 494             } else {
 495                 logger = getLogger(name);
 496             }
 497         } while (logger == null);
 498 
 499         // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
 500         if (logger != sysLogger && sysLogger.getHandlers().length == 0) {
 501             // if logger already exists but handlers not set
 502             final Logger l = logger;
 503             AccessController.doPrivileged(new PrivilegedAction<Void>() {

 504                 public Void run() {
 505                     for (Handler hdl : l.getHandlers()) {
 506                         sysLogger.addHandler(hdl);
 507                     }
 508                     return null;
 509                 }
 510             });
 511         }
 512         return sysLogger;
 513     }
 514 
 515     // LoggerContext maintains the logger namespace per context.
 516     // The default LogManager implementation has one system context and user
 517     // context.  The system context is used to maintain the namespace for
 518     // all system loggers and is queried by the system code.  If a system logger
 519     // doesn't exist in the user context, it'll also be added to the user context.
 520     // The user context is queried by the user code and all other loggers are
 521     // added in the user context.
 522     static class LoggerContext {
 523         // Table of named Loggers that maps names to Loggers.
 524         private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
 525         // Tree of named Loggers
 526         private final LogNode root;
 527         private final boolean requiresDefaultLoggers;
 528         private LoggerContext() {
 529             this(false);
 530         }
 531         private LoggerContext(boolean requiresDefaultLoggers) {
 532             this.root = new LogNode(null, this);
 533             this.requiresDefaultLoggers = requiresDefaultLoggers;































 534         }
 535 
 536         Logger demandLogger(String name, String resourceBundleName) {
 537             // a LogManager subclass may have its own implementation to add and
 538             // get a Logger.  So delegate to the LogManager to do the work.
 539             return manager.demandLogger(name, resourceBundleName, null);

 540         }
 541 
 542 
 543         // Due to subtle deadlock issues getUserContext() no longer
 544         // calls addLocalLogger(rootLogger);
 545         // Therefore - we need to add the default loggers later on.
 546         // Checks that the context is properly initialized
 547         // This is necessary before calling e.g. find(name)
 548         // or getLoggerNames()
 549         //
 550         private void ensureInitialized() {
 551             if (requiresDefaultLoggers) {
 552                 // Ensure that the root and global loggers are set.
 553                 ensureDefaultLogger(manager.rootLogger);
 554                 ensureDefaultLogger(Logger.global);
 555             }
 556         }
 557 
 558 
 559         synchronized Logger findLogger(String name) {
 560             // ensure that this context is properly initialized before
 561             // looking for loggers.
 562             ensureInitialized();
 563             LoggerWeakRef ref = namedLoggers.get(name);
 564             if (ref == null) {
 565                 return null;
 566             }
 567             Logger logger = ref.get();
 568             if (logger == null) {
 569                 // Hashtable holds stale weak reference
 570                 // to a logger which has been GC-ed.
 571                 removeLogger(name);
 572             }
 573             return logger;
 574         }
 575 
 576         // This method is called before adding a logger to the
 577         // context.
 578         // 'logger' is the context that will be added.
 579         // This method will ensure that the defaults loggers are added
 580         // before adding 'logger'.
 581         //
 582         private void ensureAllDefaultLoggers(Logger logger) {
 583             if (requiresDefaultLoggers) {
 584                 final String name = logger.getName();
 585                 if (!name.isEmpty()) {
 586                     ensureDefaultLogger(manager.rootLogger);
 587                 }
 588                 if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
 589                     ensureDefaultLogger(Logger.global);

 590                 }
 591             }
 592         }
 593 
 594         private void ensureDefaultLogger(Logger logger) {
 595             // Used for lazy addition of root logger and global logger
 596             // to a LoggerContext.
 597 
 598             // This check is simple sanity: we do not want that this
 599             // method be called for anything else than Logger.global
 600             // or owner.rootLogger.
 601             if (!requiresDefaultLoggers || logger == null
 602                     || logger != Logger.global && logger != manager.rootLogger) {
 603 
 604                 // the case where we have a non null logger which is neither
 605                 // Logger.global nor manager.rootLogger indicates a serious
 606                 // issue - as ensureDefaultLogger should never be called
 607                 // with any other loggers than one of these two (or null - if
 608                 // e.g manager.rootLogger is not yet initialized)...
 609                 assert logger == null;
 610 
 611                 return;
 612             }
 613 
 614             // Adds the logger if it's not already there.
 615             if (!namedLoggers.containsKey(logger.getName())) {
 616                 // It is important to prevent addLocalLogger to
 617                 // call ensureAllDefaultLoggers when we're in the process
 618                 // off adding one of those default loggers - as this would
 619                 // immediately cause a stack overflow.
 620                 // Therefore we must pass addDefaultLoggersIfNeeded=false,
 621                 // even if requiresDefaultLoggers is true.
 622                 addLocalLogger(logger, false);
 623             }
 624         }
 625 
 626         boolean addLocalLogger(Logger logger) {
 627             // no need to add default loggers if it's not required
 628             return addLocalLogger(logger, requiresDefaultLoggers);
 629         }
 630 
 631         // Add a logger to this context.  This method will only set its level
 632         // and process parent loggers.  It doesn't set its handlers.
 633         synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
 634             // addDefaultLoggersIfNeeded serves to break recursion when adding
 635             // default loggers. If we're adding one of the default loggers
 636             // (we're being called from ensureDefaultLogger()) then
 637             // addDefaultLoggersIfNeeded will be false: we don't want to
 638             // call ensureAllDefaultLoggers again.
 639             //
 640             // Note: addDefaultLoggersIfNeeded can also be false when
 641             //       requiresDefaultLoggers is false - since calling
 642             //       ensureAllDefaultLoggers would have no effect in this case.
 643             if (addDefaultLoggersIfNeeded) {
 644                 ensureAllDefaultLoggers(logger);
 645             }
 646 
 647             final String name = logger.getName();
 648             if (name == null) {
 649                 throw new NullPointerException();
 650             }
 651             LoggerWeakRef ref = namedLoggers.get(name);
 652             if (ref != null) {
 653                 if (ref.get() == null) {
 654                     // It's possible that the Logger was GC'ed after a
 655                     // drainLoggerRefQueueBounded() call above so allow
 656                     // a new one to be registered.
 657                     removeLogger(name);
 658                 } else {
 659                     // We already have a registered logger with the given name.
 660                     return false;
 661                 }
 662             }
 663 
 664             // We're adding a new logger.
 665             // Note that we are creating a weak reference here.
 666             ref = manager.new LoggerWeakRef(logger);


 667             namedLoggers.put(name, ref);
 668 
 669             // Apply any initial level defined for the new logger.
 670             Level level = manager.getLevelProperty(name + ".level", null);
 671             if (level != null) {
 672                 doSetLevel(logger, level);
 673             }
 674 
 675             // instantiation of the handler is done in the LogManager.addLogger
 676             // implementation as a handler class may be only visible to LogManager
 677             // subclass for the custom log manager case
 678             processParentHandlers(logger, name);
 679 
 680             // Find the new node and its parent.
 681             LogNode node = getNode(name);
 682             node.loggerRef = ref;
 683             Logger parent = null;
 684             LogNode nodep = node.parent;
 685             while (nodep != null) {
 686                 LoggerWeakRef nodeRef = nodep.loggerRef;
 687                 if (nodeRef != null) {
 688                     parent = nodeRef.get();
 689                     if (parent != null) {
 690                         break;


 702             ref.setNode(node);
 703             return true;
 704         }
 705 
 706         // note: all calls to removeLogger are synchronized on LogManager's
 707         // intrinsic lock
 708         void removeLogger(String name) {
 709             namedLoggers.remove(name);
 710         }
 711 
 712         synchronized Enumeration<String> getLoggerNames() {
 713             // ensure that this context is properly initialized before
 714             // returning logger names.
 715             ensureInitialized();
 716             return namedLoggers.keys();
 717         }
 718 
 719         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 720         // parents have levels or handlers defined, make sure they are instantiated.
 721         private void processParentHandlers(final Logger logger, final String name) {

 722             AccessController.doPrivileged(new PrivilegedAction<Void>() {

 723                 public Void run() {
 724                     if (logger != manager.rootLogger) {
 725                         boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true);
 726                         if (!useParent) {
 727                             logger.setUseParentHandlers(false);
 728                         }
 729                     }
 730                     return null;
 731                 }
 732             });
 733 
 734             int ix = 1;
 735             for (;;) {
 736                 int ix2 = name.indexOf(".", ix);
 737                 if (ix2 < 0) {
 738                     break;
 739                 }
 740                 String pname = name.substring(0, ix2);
 741                 if (manager.getProperty(pname + ".level") != null ||
 742                     manager.getProperty(pname + ".handlers") != null) {
 743                     // This pname has a level/handlers definition.
 744                     // Make sure it exists.
 745                     demandLogger(pname, null);
 746                 }
 747                 ix = ix2+1;
 748             }
 749         }
 750 
 751         // Gets a node in our tree of logger nodes.
 752         // If necessary, create it.
 753         LogNode getNode(String name) {
 754             if (name == null || name.equals("")) {
 755                 return root;
 756             }
 757             LogNode node = root;
 758             while (name.length() > 0) {
 759                 int ix = name.indexOf(".");
 760                 String head;
 761                 if (ix > 0) {
 762                     head = name.substring(0, ix);
 763                     name = name.substring(ix + 1);
 764                 } else {
 765                     head = name;
 766                     name = "";
 767                 }
 768                 if (node.children == null) {
 769                     node.children = new HashMap<>();
 770                 }
 771                 LogNode child = node.children.get(head);
 772                 if (child == null) {
 773                     child = new LogNode(node, this);
 774                     node.children.put(head, child);
 775                 }
 776                 node = child;
 777             }
 778             return node;
 779         }
 780     }
 781 
 782     static class SystemLoggerContext extends LoggerContext {
 783         // Add a system logger in the system context's namespace as well as
 784         // in the LogManager's namespace if not exist so that there is only
 785         // one single logger of the given name.  System loggers are visible
 786         // to applications unless a logger of the same name has been added.

 787         Logger demandLogger(String name, String resourceBundleName) {
 788             Logger result = findLogger(name);
 789             if (result == null) {
 790                 // only allocate the new system logger once
 791                 Logger newLogger = new Logger(name, resourceBundleName);
 792                 do {
 793                     if (addLocalLogger(newLogger)) {
 794                         // We successfully added the new Logger that we
 795                         // created above so return it without refetching.
 796                         result = newLogger;
 797                     } else {
 798                         // We didn't add the new Logger that we created above
 799                         // because another thread added a Logger with the same
 800                         // name after our null check above and before our call
 801                         // to addLogger(). We have to refetch the Logger because
 802                         // addLogger() returns a boolean instead of the Logger
 803                         // reference itself. However, if the thread that created
 804                         // the other Logger is not holding a strong reference to
 805                         // the other Logger, then it is possible for the other
 806                         // Logger to be GC'ed after we saw it in addLogger() and
 807                         // before we can refetch it. If it has been GC'ed then
 808                         // we'll just loop around and try again.
 809                         result = findLogger(name);
 810                     }
 811                 } while (result == null);
 812             }
 813             return result;
 814         }
 815     }
 816 
 817     // Add new per logger handlers.
 818     // We need to raise privilege here. All our decisions will
 819     // be made based on the logging configuration, which can
 820     // only be modified by trusted code.
 821     private void loadLoggerHandlers(final Logger logger, final String name,
 822                                     final String handlersPropertyName)
 823     {
 824         AccessController.doPrivileged(new PrivilegedAction<Object>() {

 825             public Object run() {
 826                 String names[] = parseClassNames(handlersPropertyName);
 827                 for (int i = 0; i < names.length; i++) {
 828                     String word = names[i];
 829                     try {
 830                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
 831                         Handler hdl = (Handler) clz.newInstance();
 832                         // Check if there is a property defining the
 833                         // this handler's level.
 834                         String levs = getProperty(word + ".level");
 835                         if (levs != null) {
 836                             Level l = Level.findLevel(levs);
 837                             if (l != null) {
 838                                 hdl.setLevel(l);
 839                             } else {
 840                                 // Probably a bad level. Drop through.
 841                                 System.err.println("Can't set level for " + word);
 842                             }
 843                         }
 844                         // Add this Handler to the logger


 997             // Note: this will add a 200ms penalty
 998             loadLoggerHandlers(logger, name, name + ".handlers");
 999             return true;
1000         } else {
1001             return false;
1002         }
1003     }
1004 
1005     // Private method to set a level on a logger.
1006     // If necessary, we raise privilege before doing the call.
1007     private static void doSetLevel(final Logger logger, final Level level) {
1008         SecurityManager sm = System.getSecurityManager();
1009         if (sm == null) {
1010             // There is no security manager, so things are easy.
1011             logger.setLevel(level);
1012             return;
1013         }
1014         // There is a security manager.  Raise privilege before
1015         // calling setLevel.
1016         AccessController.doPrivileged(new PrivilegedAction<Object>() {

1017             public Object run() {
1018                 logger.setLevel(level);
1019                 return null;
1020             }});
1021     }
1022 
1023     // Private method to set a parent on a logger.
1024     // If necessary, we raise privilege before doing the setParent call.
1025     private static void doSetParent(final Logger logger, final Logger parent) {
1026         SecurityManager sm = System.getSecurityManager();
1027         if (sm == null) {
1028             // There is no security manager, so things are easy.
1029             logger.setParent(parent);
1030             return;
1031         }
1032         // There is a security manager.  Raise privilege before
1033         // calling setParent.
1034         AccessController.doPrivileged(new PrivilegedAction<Object>() {

1035             public Object run() {
1036                 logger.setParent(parent);
1037                 return null;
1038             }});
1039     }
1040 
1041     /**
1042      * Method to find a named logger.
1043      * <p>
1044      * Note that since untrusted code may create loggers with
1045      * arbitrary names this method should not be relied on to
1046      * find Loggers for security sensitive logging.
1047      * It is also important to note that the Logger associated with the
1048      * String {@code name} may be garbage collected at any time if there
1049      * is no strong reference to the Logger. The caller of this method
1050      * must check the return value for null in order to properly handle
1051      * the case where the Logger has been garbage collected.
1052      * <p>
1053      * @param name name of the logger
1054      * @return  matching logger or null if none is found


1112                     clz.newInstance();
1113                     return;
1114                 }
1115             } catch (Exception ex) {
1116                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1117                 System.err.println("" + ex);
1118                 // keep going and useful config file.
1119             }
1120         }
1121 
1122         String fname = System.getProperty("java.util.logging.config.file");
1123         if (fname == null) {
1124             fname = System.getProperty("java.home");
1125             if (fname == null) {
1126                 throw new Error("Can't find java.home ??");
1127             }
1128             File f = new File(fname, "lib");
1129             f = new File(f, "logging.properties");
1130             fname = f.getCanonicalPath();
1131         }
1132         InputStream in = new FileInputStream(fname);
1133         BufferedInputStream bin = new BufferedInputStream(in);
1134         try {
1135             readConfiguration(bin);
1136         } finally {
1137             if (in != null) {
1138                 in.close();
1139             }
1140         }
1141     }
1142 
1143     /**
1144      * Reset the logging configuration.
1145      * <p>
1146      * For all named loggers, the reset operation removes and closes
1147      * all Handlers and (except for the root logger) sets the level
1148      * to null.  The root logger's level is set to Level.INFO.
1149      *
1150      * @exception  SecurityException  if a security manager exists and if
1151      *             the caller does not have LoggingPermission("control").
1152      */
1153 
1154     public void reset() throws SecurityException {
1155         checkPermission();
1156         synchronized (this) {
1157             props = new Properties();
1158             // Since we are doing a reset we no longer want to initialize
1159             // the global handlers, if they haven't been initialized yet.


1184                 // Problems closing a handler?  Keep going...
1185             }
1186         }
1187         String name = logger.getName();
1188         if (name != null && name.equals("")) {
1189             // This is the root logger.
1190             logger.setLevel(defaultLevel);
1191         } else {
1192             logger.setLevel(null);
1193         }
1194     }
1195 
1196     // get a list of whitespace separated classnames from a property.
1197     private String[] parseClassNames(String propertyName) {
1198         String hands = getProperty(propertyName);
1199         if (hands == null) {
1200             return new String[0];
1201         }
1202         hands = hands.trim();
1203         int ix = 0;
1204         Vector<String> result = new Vector<>();
1205         while (ix < hands.length()) {
1206             int end = ix;
1207             while (end < hands.length()) {
1208                 if (Character.isWhitespace(hands.charAt(end))) {
1209                     break;
1210                 }
1211                 if (hands.charAt(end) == ',') {
1212                     break;
1213                 }
1214                 end++;
1215             }
1216             String word = hands.substring(ix, end);
1217             ix = end+1;
1218             word = word.trim();
1219             if (word.length() == 0) {
1220                 continue;
1221             }
1222             result.add(word);
1223         }
1224         return result.toArray(new String[result.size()]);


1454             if (children == null) {
1455                 return;
1456             }
1457             Iterator<LogNode> values = children.values().iterator();
1458             while (values.hasNext()) {
1459                 LogNode node = values.next();
1460                 LoggerWeakRef ref = node.loggerRef;
1461                 Logger logger = (ref == null) ? null : ref.get();
1462                 if (logger == null) {
1463                     node.walkAndSetParent(parent);
1464                 } else {
1465                     doSetParent(logger, parent);
1466                 }
1467             }
1468         }
1469     }
1470 
1471     // We use a subclass of Logger for the root logger, so
1472     // that we only instantiate the global handlers when they
1473     // are first needed.
1474     private class RootLogger extends Logger {
1475         private RootLogger() {
1476             super("", null);



1477             setLevel(defaultLevel);
1478         }
1479 

1480         public void log(LogRecord record) {
1481             // Make sure that the global handlers have been instantiated.
1482             initializeGlobalHandlers();
1483             super.log(record);
1484         }
1485 

1486         public void addHandler(Handler h) {
1487             initializeGlobalHandlers();
1488             super.addHandler(h);
1489         }
1490 

1491         public void removeHandler(Handler h) {
1492             initializeGlobalHandlers();
1493             super.removeHandler(h);
1494         }
1495 

1496         public Handler[] getHandlers() {
1497             initializeGlobalHandlers();
1498             return super.getHandlers();
1499         }
1500     }
1501 
1502 
1503     // Private method to be called when the configuration has
1504     // changed to apply any level settings to any pre-existing loggers.
1505     synchronized private void setLevelsOnExistingLoggers() {
1506         Enumeration<?> enum_ = props.propertyNames();
1507         while (enum_.hasMoreElements()) {
1508             String key = (String)enum_.nextElement();
1509             if (!key.endsWith(".level")) {
1510                 // Not a level definition.
1511                 continue;
1512             }
1513             int ix = key.length() - 6;
1514             String name = key.substring(0, ix);
1515             Level level = getLevelProperty(key, null);




 127  * Loggers are organized into a naming hierarchy based on their
 128  * dot separated names.  Thus "a.b.c" is a child of "a.b", but
 129  * "a.b1" and a.b2" are peers.
 130  * <p>
 131  * All properties whose names end with ".level" are assumed to define
 132  * log levels for Loggers.  Thus "foo.level" defines a log level for
 133  * the logger called "foo" and (recursively) for any of its children
 134  * in the naming hierarchy.  Log Levels are applied in the order they
 135  * are defined in the properties file.  Thus level settings for child
 136  * nodes in the tree should come after settings for their parents.
 137  * The property name ".level" can be used to set the level for the
 138  * root of the tree.
 139  * <p>
 140  * All methods on the LogManager object are multi-thread safe.
 141  *
 142  * @since 1.4
 143 */
 144 
 145 public class LogManager {
 146     // The global LogManager object
 147     private static final LogManager manager;
 148 
 149     private Properties props = new Properties();
 150     private final static Level defaultLevel = Level.INFO;
 151 
 152     // The map of the registered listeners. The map value is the registration
 153     // count to allow for cases where the same listener is registered many times.
 154     private final Map<Object,Integer> listenerMap = new HashMap<>();
 155 
 156     // LoggerContext for system loggers and user loggers
 157     private final LoggerContext systemContext = new SystemLoggerContext();
 158     private final LoggerContext userContext = new LoggerContext();
 159     // non final field - make it volatile to make sure that other threads
 160     // will see the new value once ensureLogManagerInitialized() has finished
 161     // executing.
 162     private volatile Logger rootLogger;
 163     // Have we done the primordial reading of the configuration file?
 164     // (Must be done after a suitable amount of java.lang.System
 165     // initialization has been done)
 166     private volatile boolean readPrimordialConfiguration;
 167     // Have we initialized global (root) handlers yet?
 168     // This gets set to false in readConfiguration
 169     private boolean initializedGlobalHandlers = true;
 170     // True if JVM death is imminent and the exit hook has been called.
 171     private boolean deathImminent;
 172 
 173     static {
 174         manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
 175             @Override
 176             public LogManager run() {
 177                 LogManager mgr = null;
 178                 String cname = null;
 179                 try {
 180                     cname = System.getProperty("java.util.logging.manager");
 181                     if (cname != null) {
 182                         try {
 183                             Class<?> clz = ClassLoader.getSystemClassLoader()
 184                                     .loadClass(cname);
 185                             mgr = (LogManager) clz.newInstance();
 186                         } catch (ClassNotFoundException ex) {
 187                             Class<?> clz = Thread.currentThread()
 188                                     .getContextClassLoader().loadClass(cname);
 189                             mgr = (LogManager) clz.newInstance();
 190                         }
 191                     }
 192                 } catch (Exception ex) {
 193                     System.err.println("Could not load Logmanager \"" + cname + "\"");
 194                     ex.printStackTrace();
 195                 }
 196                 if (mgr == null) {
 197                     mgr = new LogManager();
 198                 }
 199                 return mgr;
 200 




























 201             }
 202         });
 203     }
 204 
 205 
 206     // This private class is used as a shutdown hook.
 207     // It does a "reset" to close all open handlers.
 208     private class Cleaner extends Thread {
 209 
 210         private Cleaner() {
 211             /* Set context class loader to null in order to avoid
 212              * keeping a strong reference to an application classloader.
 213              */
 214             this.setContextClassLoader(null);
 215         }
 216 
 217         @Override
 218         public void run() {
 219             // This is to ensure the LogManager.<clinit> is completed
 220             // before synchronized block. Otherwise deadlocks are possible.
 221             LogManager mgr = manager;
 222 
 223             // If the global handlers haven't been initialized yet, we
 224             // don't want to initialize them just so we can close them!
 225             synchronized (LogManager.this) {
 226                 // Note that death is imminent.
 227                 deathImminent = true;
 228                 initializedGlobalHandlers = true;
 229             }
 230 
 231             // Do a reset to close all active handlers.
 232             reset();
 233         }
 234     }
 235 
 236 
 237     /**
 238      * Protected constructor.  This is protected so that container applications
 239      * (such as J2EE containers) can subclass the object.  It is non-public as
 240      * it is intended that there only be one LogManager object, whose value is
 241      * retrieved by calling LogManager.getLogManager.
 242      */
 243     protected LogManager() {
 244         // Add a shutdown hook to close the global handlers.
 245         try {
 246             Runtime.getRuntime().addShutdownHook(new Cleaner());
 247         } catch (IllegalStateException e) {
 248             // If the VM is already shutting down,
 249             // We do not need to register shutdownHook.
 250         }
 251     }
 252 
 253     /**
 254      * Lazy initialization: if this instance of manager is the global
 255      * manager then this method will read the initial configuration and
 256      * add the root logger and global logger by calling addLogger().
 257      *
 258      * Note that it is subtly different from what we do in LoggerContext.
 259      * In LoggerContext we're patching up the logger context tree in order to add
 260      * the root and global logger *to the context tree*.
 261      *
 262      * For this to work, addLogger() must have already have been called
 263      * once on the LogManager instance for the default logger being
 264      * added.
 265      *
 266      * This is why ensureLogManagerInitialized() needs to be called before
 267      * any logger is added to any logger context.
 268      *
 269      */
 270     private boolean initializedCalled = false;
 271     private volatile boolean initializationDone = false;
 272     final void ensureLogManagerInitialized() {
 273         final LogManager owner = this;
 274         if (initializationDone || owner != manager) {
 275             // we don't want to do this twice, and we don't want to do
 276             // this on private manager instances.
 277             return;
 278         }
 279 
 280         // Maybe another thread has called ensureLogManagerInitialized()
 281         // before us and is still executing it. If so we will block until
 282         // the log manager has finished initialized, then acquire the monitor,
 283         // notice that initializationDone is now true and return.
 284         // Otherwise - we have come here first! We will acquire the monitor,
 285         // see that initializationDone is still false, and perform the
 286         // initialization.
 287         //
 288         synchronized(this) {
 289             // If initializedCalled is true it means that we're already in
 290             // the process of initializing the LogManager in this thread.
 291             // There has been a recursive call to ensureLogManagerInitialized().
 292             final boolean isRecursiveInitialization = (initializedCalled == true);
 293 
 294             assert initializedCalled || !initializationDone
 295                     : "Initialization can't be done if initialized has not been called!";
 296 
 297             if (isRecursiveInitialization || initializationDone) {
 298                 // If isRecursiveInitialization is true it means that we're
 299                 // already in the process of initializing the LogManager in
 300                 // this thread. There has been a recursive call to
 301                 // ensureLogManagerInitialized(). We should not proceed as
 302                 // it would lead to infinite recursion.
 303                 //
 304                 // If initializationDone is true then it means the manager
 305                 // has finished initializing; just return: we're done.
 306                 return;
 307             }
 308             // Calling addLogger below will in turn call requiresDefaultLogger()
 309             // which will call ensureLogManagerInitialized().
 310             // We use initializedCalled to break the recursion.
 311             initializedCalled = true;
 312             try {
 313                 AccessController.doPrivileged(new PrivilegedAction<Object>() {
 314                     @Override
 315                     public Object run() {
 316                         assert rootLogger == null;
 317                         assert initializedCalled && !initializationDone;
 318 
 319                         // Read configuration.
 320                         owner.readPrimordialConfiguration();
 321 
 322                         // Create and retain Logger for the root of the namespace.
 323                         owner.rootLogger = owner.new RootLogger();
 324                         owner.addLogger(owner.rootLogger);
 325 
 326                         // Adding the global Logger.
 327                         // Do not call Logger.getGlobal() here as this might trigger
 328                         // subtle inter-dependency issues.
 329                         @SuppressWarnings("deprecation")
 330                         final Logger global = Logger.global;
 331 
 332                         // Make sure the global logger will be registered in the
 333                         // global manager
 334                         owner.addLogger(global);
 335                         return null;
 336                     }
 337                 });
 338             } finally {
 339                 initializationDone = true;
 340             }
 341         }
 342     }
 343 
 344     /**
 345      * Returns the global LogManager object.
 346      * @return the global LogManager object
 347      */
 348     public static LogManager getLogManager() {
 349         if (manager != null) {
 350             manager.ensureLogManagerInitialized();
 351         }
 352         return manager;
 353     }
 354 
 355     private void readPrimordialConfiguration() {
 356         if (!readPrimordialConfiguration) {
 357             synchronized (this) {
 358                 if (!readPrimordialConfiguration) {
 359                     // If System.in/out/err are null, it's a good
 360                     // indication that we're still in the
 361                     // bootstrapping phase
 362                     if (System.out == null) {
 363                         return;
 364                     }
 365                     readPrimordialConfiguration = true;
 366 
 367                     try {
 368                         AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
 369                                 @Override
 370                                 public Void run() throws Exception {
 371                                     readConfiguration();
 372 
 373                                     // Platform loggers begin to delegate to java.util.logging.Logger
 374                                     sun.util.logging.PlatformLogger.redirectPlatformLoggers();
 375                                     return null;
 376                                 }
 377                             });
 378                     } catch (Exception ex) {
 379                         assert false : "Exception raised while reading logging configuration: " + ex;

 380                     }
 381                 }
 382             }
 383         }
 384     }
 385 
 386     /**
 387      * Adds an event listener to be invoked when the logging
 388      * properties are re-read. Adding multiple instances of
 389      * the same event Listener results in multiple entries
 390      * in the property event listener table.
 391      *
 392      * <p><b>WARNING:</b> This method is omitted from this class in all subset
 393      * Profiles of Java SE that do not include the {@code java.beans} package.
 394      * </p>
 395      *
 396      * @param l  event listener
 397      * @exception  SecurityException  if a security manager exists and if
 398      *             the caller does not have LoggingPermission("control").
 399      * @exception NullPointerException if the PropertyChangeListener is null.


 446         if (l != null) {
 447             PropertyChangeListener listener = l;
 448             synchronized (listenerMap) {
 449                 Integer value = listenerMap.get(listener);
 450                 if (value != null) {
 451                     // remove from map if registration count is 1, otherwise
 452                     // just decrement its count
 453                     int i = value.intValue();
 454                     if (i == 1) {
 455                         listenerMap.remove(listener);
 456                     } else {
 457                         assert i > 1;
 458                         listenerMap.put(listener, i - 1);
 459                     }
 460                 }
 461             }
 462         }
 463     }
 464 
 465     // LoggerContext maps from AppContext
 466     private WeakHashMap<Object, LoggerContext> contextsMap = null;
 467 
 468     // Returns the LoggerContext for the user code (i.e. application or AppContext).
 469     // Loggers are isolated from each AppContext.
 470     private LoggerContext getUserContext() {
 471         LoggerContext context = null;
 472 
 473         SecurityManager sm = System.getSecurityManager();
 474         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
 475         if (sm != null && javaAwtAccess != null) {
 476             // for each applet, it has its own LoggerContext isolated from others
 477             synchronized (javaAwtAccess) {
 478                 // find the AppContext of the applet code
 479                 // will be null if we are in the main app context.
 480                 final Object ecx = javaAwtAccess.getAppletContext();
 481                 if (ecx != null) {
 482                     if (contextsMap == null) {
 483                         contextsMap = new WeakHashMap<>();
 484                     }
 485                     context = contextsMap.get(ecx);
 486                     if (context == null) {
 487                         // Create a new LoggerContext for the applet.
 488                         context = new LoggerContext();



 489                         contextsMap.put(ecx, context);
 490                     }
 491                 }
 492             }
 493         }
 494         // for standalone app, return userContext
 495         return context != null ? context : userContext;
 496     }
 497 
 498     // The system context.
 499     final LoggerContext getSystemContext() {
 500         return systemContext;
 501     }
 502 
 503     private List<LoggerContext> contexts() {
 504         List<LoggerContext> cxs = new ArrayList<>();
 505         cxs.add(getSystemContext());
 506         cxs.add(getUserContext());
 507         return cxs;
 508     }
 509 
 510     // Find or create a specified logger instance. If a logger has
 511     // already been created with the given name it is returned.
 512     // Otherwise a new logger instance is created and registered
 513     // in the LogManager global namespace.
 514     // This method will always return a non-null Logger object.
 515     // Synchronization is not required here. All synchronization for
 516     // adding a new Logger object is handled by addLogger().
 517     //
 518     // This method must delegate to the LogManager implementation to
 519     // add a new Logger or return the one that has been added previously
 520     // as a LogManager subclass may override the addLogger, getLogger,
 521     // readConfiguration, and other methods.
 522     Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
 523         Logger result = getLogger(name);
 524         if (result == null) {
 525             // only allocate the new logger once
 526             Logger newLogger = new Logger(name, resourceBundleName, caller, this);
 527             do {
 528                 if (addLogger(newLogger)) {
 529                     // We successfully added the new Logger that we
 530                     // created above so return it without refetching.
 531                     return newLogger;
 532                 }
 533 
 534                 // We didn't add the new Logger that we created above
 535                 // because another thread added a Logger with the same
 536                 // name after our null check above and before our call
 537                 // to addLogger(). We have to refetch the Logger because
 538                 // addLogger() returns a boolean instead of the Logger
 539                 // reference itself. However, if the thread that created
 540                 // the other Logger is not holding a strong reference to
 541                 // the other Logger, then it is possible for the other
 542                 // Logger to be GC'ed after we saw it in addLogger() and
 543                 // before we can refetch it. If it has been GC'ed then
 544                 // we'll just loop around and try again.
 545                 result = getLogger(name);
 546             } while (result == null);
 547         }
 548         return result;
 549     }
 550 
 551     Logger demandSystemLogger(String name, String resourceBundleName) {
 552         // Add a system logger in the system context's namespace
 553         final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
 554 
 555         // Add the system logger to the LogManager's namespace if not exist
 556         // so that there is only one single logger of the given name.
 557         // System loggers are visible to applications unless a logger of
 558         // the same name has been added.
 559         Logger logger;
 560         do {
 561             // First attempt to call addLogger instead of getLogger
 562             // This would avoid potential bug in custom LogManager.getLogger
 563             // implementation that adds a logger if does not exist
 564             if (addLogger(sysLogger)) {
 565                 // successfully added the new system logger
 566                 logger = sysLogger;
 567             } else {
 568                 logger = getLogger(name);
 569             }
 570         } while (logger == null);
 571 
 572         // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
 573         if (logger != sysLogger && sysLogger.getHandlers().length == 0) {
 574             // if logger already exists but handlers not set
 575             final Logger l = logger;
 576             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 577                 @Override
 578                 public Void run() {
 579                     for (Handler hdl : l.getHandlers()) {
 580                         sysLogger.addHandler(hdl);
 581                     }
 582                     return null;
 583                 }
 584             });
 585         }
 586         return sysLogger;
 587     }
 588 
 589     // LoggerContext maintains the logger namespace per context.
 590     // The default LogManager implementation has one system context and user
 591     // context.  The system context is used to maintain the namespace for
 592     // all system loggers and is queried by the system code.  If a system logger
 593     // doesn't exist in the user context, it'll also be added to the user context.
 594     // The user context is queried by the user code and all other loggers are
 595     // added in the user context.
 596     class LoggerContext {
 597         // Table of named Loggers that maps names to Loggers.
 598         private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
 599         // Tree of named Loggers
 600         private final LogNode root;

 601         private LoggerContext() {



 602             this.root = new LogNode(null, this);
 603         }
 604 
 605 
 606         // Tells whether default loggers are required in this context.
 607         // If true, the default loggers will be lazily added.
 608         final boolean requiresDefaultLoggers() {
 609             final boolean requiresDefaultLoggers = (getOwner() == manager);
 610             if (requiresDefaultLoggers) {
 611                 getOwner().ensureLogManagerInitialized();
 612             }
 613             return requiresDefaultLoggers;
 614         }
 615 
 616         // This context's LogManager.
 617         final LogManager getOwner() {
 618             return LogManager.this;
 619         }
 620 
 621         // This context owner's root logger, which if not null, and if
 622         // the context requires default loggers, will be added to the context
 623         // logger's tree.
 624         final Logger getRootLogger() {
 625             return getOwner().rootLogger;
 626         }
 627 
 628         // The global logger, which if not null, and if
 629         // the context requires default loggers, will be added to the context
 630         // logger's tree.
 631         final Logger getGlobalLogger() {
 632             @SuppressWarnings("deprecated") // avoids initialization cycles.
 633             final Logger global = Logger.global;
 634             return global;
 635         }
 636 
 637         Logger demandLogger(String name, String resourceBundleName) {
 638             // a LogManager subclass may have its own implementation to add and
 639             // get a Logger.  So delegate to the LogManager to do the work.
 640             final LogManager owner = getOwner();
 641             return owner.demandLogger(name, resourceBundleName, null);
 642         }
 643 
 644 
 645         // Due to subtle deadlock issues getUserContext() no longer
 646         // calls addLocalLogger(rootLogger);
 647         // Therefore - we need to add the default loggers later on.
 648         // Checks that the context is properly initialized
 649         // This is necessary before calling e.g. find(name)
 650         // or getLoggerNames()
 651         //
 652         private void ensureInitialized() {
 653             if (requiresDefaultLoggers()) {
 654                 // Ensure that the root and global loggers are set.
 655                 ensureDefaultLogger(getRootLogger());
 656                 ensureDefaultLogger(getGlobalLogger());
 657             }
 658         }
 659 
 660 
 661         synchronized Logger findLogger(String name) {
 662             // ensure that this context is properly initialized before
 663             // looking for loggers.
 664             ensureInitialized();
 665             LoggerWeakRef ref = namedLoggers.get(name);
 666             if (ref == null) {
 667                 return null;
 668             }
 669             Logger logger = ref.get();
 670             if (logger == null) {
 671                 // Hashtable holds stale weak reference
 672                 // to a logger which has been GC-ed.
 673                 removeLogger(name);
 674             }
 675             return logger;
 676         }
 677 
 678         // This method is called before adding a logger to the
 679         // context.
 680         // 'logger' is the context that will be added.
 681         // This method will ensure that the defaults loggers are added
 682         // before adding 'logger'.
 683         //
 684         private void ensureAllDefaultLoggers(Logger logger) {
 685             if (requiresDefaultLoggers()) {
 686                 final String name = logger.getName();
 687                 if (!name.isEmpty()) {
 688                     ensureDefaultLogger(getRootLogger());

 689                     if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
 690                         ensureDefaultLogger(getGlobalLogger());
 691                     }
 692                 }
 693             }
 694         }
 695 
 696         private void ensureDefaultLogger(Logger logger) {
 697             // Used for lazy addition of root logger and global logger
 698             // to a LoggerContext.
 699 
 700             // This check is simple sanity: we do not want that this
 701             // method be called for anything else than Logger.global
 702             // or owner.rootLogger.
 703             if (!requiresDefaultLoggers() || logger == null
 704                     || logger != Logger.global && logger != LogManager.this.rootLogger) {
 705 
 706                 // the case where we have a non null logger which is neither
 707                 // Logger.global nor manager.rootLogger indicates a serious
 708                 // issue - as ensureDefaultLogger should never be called
 709                 // with any other loggers than one of these two (or null - if
 710                 // e.g manager.rootLogger is not yet initialized)...
 711                 assert logger == null;
 712 
 713                 return;
 714             }
 715 
 716             // Adds the logger if it's not already there.
 717             if (!namedLoggers.containsKey(logger.getName())) {
 718                 // It is important to prevent addLocalLogger to
 719                 // call ensureAllDefaultLoggers when we're in the process
 720                 // off adding one of those default loggers - as this would
 721                 // immediately cause a stack overflow.
 722                 // Therefore we must pass addDefaultLoggersIfNeeded=false,
 723                 // even if requiresDefaultLoggers is true.
 724                 addLocalLogger(logger, false);
 725             }
 726         }
 727 
 728         boolean addLocalLogger(Logger logger) {
 729             // no need to add default loggers if it's not required
 730             return addLocalLogger(logger, requiresDefaultLoggers());
 731         }
 732 
 733         // Add a logger to this context.  This method will only set its level
 734         // and process parent loggers.  It doesn't set its handlers.
 735         synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
 736             // addDefaultLoggersIfNeeded serves to break recursion when adding
 737             // default loggers. If we're adding one of the default loggers
 738             // (we're being called from ensureDefaultLogger()) then
 739             // addDefaultLoggersIfNeeded will be false: we don't want to
 740             // call ensureAllDefaultLoggers again.
 741             //
 742             // Note: addDefaultLoggersIfNeeded can also be false when
 743             //       requiresDefaultLoggers is false - since calling
 744             //       ensureAllDefaultLoggers would have no effect in this case.
 745             if (addDefaultLoggersIfNeeded) {
 746                 ensureAllDefaultLoggers(logger);
 747             }
 748 
 749             final String name = logger.getName();
 750             if (name == null) {
 751                 throw new NullPointerException();
 752             }
 753             LoggerWeakRef ref = namedLoggers.get(name);
 754             if (ref != null) {
 755                 if (ref.get() == null) {
 756                     // It's possible that the Logger was GC'ed after a
 757                     // drainLoggerRefQueueBounded() call above so allow
 758                     // a new one to be registered.
 759                     removeLogger(name);
 760                 } else {
 761                     // We already have a registered logger with the given name.
 762                     return false;
 763                 }
 764             }
 765 
 766             // We're adding a new logger.
 767             // Note that we are creating a weak reference here.
 768             final LogManager owner = getOwner();
 769             logger.setLogManager(owner);
 770             ref = owner.new LoggerWeakRef(logger);
 771             namedLoggers.put(name, ref);
 772 
 773             // Apply any initial level defined for the new logger.
 774             Level level = owner.getLevelProperty(name + ".level", null);
 775             if (level != null) {
 776                 doSetLevel(logger, level);
 777             }
 778 
 779             // instantiation of the handler is done in the LogManager.addLogger
 780             // implementation as a handler class may be only visible to LogManager
 781             // subclass for the custom log manager case
 782             processParentHandlers(logger, name);
 783 
 784             // Find the new node and its parent.
 785             LogNode node = getNode(name);
 786             node.loggerRef = ref;
 787             Logger parent = null;
 788             LogNode nodep = node.parent;
 789             while (nodep != null) {
 790                 LoggerWeakRef nodeRef = nodep.loggerRef;
 791                 if (nodeRef != null) {
 792                     parent = nodeRef.get();
 793                     if (parent != null) {
 794                         break;


 806             ref.setNode(node);
 807             return true;
 808         }
 809 
 810         // note: all calls to removeLogger are synchronized on LogManager's
 811         // intrinsic lock
 812         void removeLogger(String name) {
 813             namedLoggers.remove(name);
 814         }
 815 
 816         synchronized Enumeration<String> getLoggerNames() {
 817             // ensure that this context is properly initialized before
 818             // returning logger names.
 819             ensureInitialized();
 820             return namedLoggers.keys();
 821         }
 822 
 823         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
 824         // parents have levels or handlers defined, make sure they are instantiated.
 825         private void processParentHandlers(final Logger logger, final String name) {
 826             final LogManager owner = getOwner();
 827             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 828                 @Override
 829                 public Void run() {
 830                     if (logger != owner.rootLogger) {
 831                         boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
 832                         if (!useParent) {
 833                             logger.setUseParentHandlers(false);
 834                         }
 835                     }
 836                     return null;
 837                 }
 838             });
 839 
 840             int ix = 1;
 841             for (;;) {
 842                 int ix2 = name.indexOf(".", ix);
 843                 if (ix2 < 0) {
 844                     break;
 845                 }
 846                 String pname = name.substring(0, ix2);
 847                 if (owner.getProperty(pname + ".level") != null ||
 848                     owner.getProperty(pname + ".handlers") != null) {
 849                     // This pname has a level/handlers definition.
 850                     // Make sure it exists.
 851                     demandLogger(pname, null);
 852                 }
 853                 ix = ix2+1;
 854             }
 855         }
 856 
 857         // Gets a node in our tree of logger nodes.
 858         // If necessary, create it.
 859         LogNode getNode(String name) {
 860             if (name == null || name.equals("")) {
 861                 return root;
 862             }
 863             LogNode node = root;
 864             while (name.length() > 0) {
 865                 int ix = name.indexOf(".");
 866                 String head;
 867                 if (ix > 0) {
 868                     head = name.substring(0, ix);
 869                     name = name.substring(ix + 1);
 870                 } else {
 871                     head = name;
 872                     name = "";
 873                 }
 874                 if (node.children == null) {
 875                     node.children = new HashMap<>();
 876                 }
 877                 LogNode child = node.children.get(head);
 878                 if (child == null) {
 879                     child = new LogNode(node, this);
 880                     node.children.put(head, child);
 881                 }
 882                 node = child;
 883             }
 884             return node;
 885         }
 886     }
 887 
 888     final class SystemLoggerContext extends LoggerContext {
 889         // Add a system logger in the system context's namespace as well as
 890         // in the LogManager's namespace if not exist so that there is only
 891         // one single logger of the given name.  System loggers are visible
 892         // to applications unless a logger of the same name has been added.
 893         @Override
 894         Logger demandLogger(String name, String resourceBundleName) {
 895             Logger result = findLogger(name);
 896             if (result == null) {
 897                 // only allocate the new system logger once
 898                 Logger newLogger = new Logger(name, resourceBundleName, null, getOwner());
 899                 do {
 900                     if (addLocalLogger(newLogger)) {
 901                         // We successfully added the new Logger that we
 902                         // created above so return it without refetching.
 903                         result = newLogger;
 904                     } else {
 905                         // We didn't add the new Logger that we created above
 906                         // because another thread added a Logger with the same
 907                         // name after our null check above and before our call
 908                         // to addLogger(). We have to refetch the Logger because
 909                         // addLogger() returns a boolean instead of the Logger
 910                         // reference itself. However, if the thread that created
 911                         // the other Logger is not holding a strong reference to
 912                         // the other Logger, then it is possible for the other
 913                         // Logger to be GC'ed after we saw it in addLogger() and
 914                         // before we can refetch it. If it has been GC'ed then
 915                         // we'll just loop around and try again.
 916                         result = findLogger(name);
 917                     }
 918                 } while (result == null);
 919             }
 920             return result;
 921         }
 922     }
 923 
 924     // Add new per logger handlers.
 925     // We need to raise privilege here. All our decisions will
 926     // be made based on the logging configuration, which can
 927     // only be modified by trusted code.
 928     private void loadLoggerHandlers(final Logger logger, final String name,
 929                                     final String handlersPropertyName)
 930     {
 931         AccessController.doPrivileged(new PrivilegedAction<Object>() {
 932             @Override
 933             public Object run() {
 934                 String names[] = parseClassNames(handlersPropertyName);
 935                 for (int i = 0; i < names.length; i++) {
 936                     String word = names[i];
 937                     try {
 938                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
 939                         Handler hdl = (Handler) clz.newInstance();
 940                         // Check if there is a property defining the
 941                         // this handler's level.
 942                         String levs = getProperty(word + ".level");
 943                         if (levs != null) {
 944                             Level l = Level.findLevel(levs);
 945                             if (l != null) {
 946                                 hdl.setLevel(l);
 947                             } else {
 948                                 // Probably a bad level. Drop through.
 949                                 System.err.println("Can't set level for " + word);
 950                             }
 951                         }
 952                         // Add this Handler to the logger


1105             // Note: this will add a 200ms penalty
1106             loadLoggerHandlers(logger, name, name + ".handlers");
1107             return true;
1108         } else {
1109             return false;
1110         }
1111     }
1112 
1113     // Private method to set a level on a logger.
1114     // If necessary, we raise privilege before doing the call.
1115     private static void doSetLevel(final Logger logger, final Level level) {
1116         SecurityManager sm = System.getSecurityManager();
1117         if (sm == null) {
1118             // There is no security manager, so things are easy.
1119             logger.setLevel(level);
1120             return;
1121         }
1122         // There is a security manager.  Raise privilege before
1123         // calling setLevel.
1124         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1125             @Override
1126             public Object run() {
1127                 logger.setLevel(level);
1128                 return null;
1129             }});
1130     }
1131 
1132     // Private method to set a parent on a logger.
1133     // If necessary, we raise privilege before doing the setParent call.
1134     private static void doSetParent(final Logger logger, final Logger parent) {
1135         SecurityManager sm = System.getSecurityManager();
1136         if (sm == null) {
1137             // There is no security manager, so things are easy.
1138             logger.setParent(parent);
1139             return;
1140         }
1141         // There is a security manager.  Raise privilege before
1142         // calling setParent.
1143         AccessController.doPrivileged(new PrivilegedAction<Object>() {
1144             @Override
1145             public Object run() {
1146                 logger.setParent(parent);
1147                 return null;
1148             }});
1149     }
1150 
1151     /**
1152      * Method to find a named logger.
1153      * <p>
1154      * Note that since untrusted code may create loggers with
1155      * arbitrary names this method should not be relied on to
1156      * find Loggers for security sensitive logging.
1157      * It is also important to note that the Logger associated with the
1158      * String {@code name} may be garbage collected at any time if there
1159      * is no strong reference to the Logger. The caller of this method
1160      * must check the return value for null in order to properly handle
1161      * the case where the Logger has been garbage collected.
1162      * <p>
1163      * @param name name of the logger
1164      * @return  matching logger or null if none is found


1222                     clz.newInstance();
1223                     return;
1224                 }
1225             } catch (Exception ex) {
1226                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1227                 System.err.println("" + ex);
1228                 // keep going and useful config file.
1229             }
1230         }
1231 
1232         String fname = System.getProperty("java.util.logging.config.file");
1233         if (fname == null) {
1234             fname = System.getProperty("java.home");
1235             if (fname == null) {
1236                 throw new Error("Can't find java.home ??");
1237             }
1238             File f = new File(fname, "lib");
1239             f = new File(f, "logging.properties");
1240             fname = f.getCanonicalPath();
1241         }
1242         try (final InputStream in = new FileInputStream(fname)) {
1243             final BufferedInputStream bin = new BufferedInputStream(in);

1244             readConfiguration(bin);




1245         }
1246     }
1247 
1248     /**
1249      * Reset the logging configuration.
1250      * <p>
1251      * For all named loggers, the reset operation removes and closes
1252      * all Handlers and (except for the root logger) sets the level
1253      * to null.  The root logger's level is set to Level.INFO.
1254      *
1255      * @exception  SecurityException  if a security manager exists and if
1256      *             the caller does not have LoggingPermission("control").
1257      */
1258 
1259     public void reset() throws SecurityException {
1260         checkPermission();
1261         synchronized (this) {
1262             props = new Properties();
1263             // Since we are doing a reset we no longer want to initialize
1264             // the global handlers, if they haven't been initialized yet.


1289                 // Problems closing a handler?  Keep going...
1290             }
1291         }
1292         String name = logger.getName();
1293         if (name != null && name.equals("")) {
1294             // This is the root logger.
1295             logger.setLevel(defaultLevel);
1296         } else {
1297             logger.setLevel(null);
1298         }
1299     }
1300 
1301     // get a list of whitespace separated classnames from a property.
1302     private String[] parseClassNames(String propertyName) {
1303         String hands = getProperty(propertyName);
1304         if (hands == null) {
1305             return new String[0];
1306         }
1307         hands = hands.trim();
1308         int ix = 0;
1309         final List<String> result = new ArrayList<>();
1310         while (ix < hands.length()) {
1311             int end = ix;
1312             while (end < hands.length()) {
1313                 if (Character.isWhitespace(hands.charAt(end))) {
1314                     break;
1315                 }
1316                 if (hands.charAt(end) == ',') {
1317                     break;
1318                 }
1319                 end++;
1320             }
1321             String word = hands.substring(ix, end);
1322             ix = end+1;
1323             word = word.trim();
1324             if (word.length() == 0) {
1325                 continue;
1326             }
1327             result.add(word);
1328         }
1329         return result.toArray(new String[result.size()]);


1559             if (children == null) {
1560                 return;
1561             }
1562             Iterator<LogNode> values = children.values().iterator();
1563             while (values.hasNext()) {
1564                 LogNode node = values.next();
1565                 LoggerWeakRef ref = node.loggerRef;
1566                 Logger logger = (ref == null) ? null : ref.get();
1567                 if (logger == null) {
1568                     node.walkAndSetParent(parent);
1569                 } else {
1570                     doSetParent(logger, parent);
1571                 }
1572             }
1573         }
1574     }
1575 
1576     // We use a subclass of Logger for the root logger, so
1577     // that we only instantiate the global handlers when they
1578     // are first needed.
1579     private final class RootLogger extends Logger {
1580         private RootLogger() {
1581             // We do not call the protected Logger two args constructor here,
1582             // to avoid calling LogManager.getLogManager() from within the
1583             // RootLogger constructor.
1584             super("", null, null, LogManager.this);
1585             setLevel(defaultLevel);
1586         }
1587 
1588         @Override
1589         public void log(LogRecord record) {
1590             // Make sure that the global handlers have been instantiated.
1591             initializeGlobalHandlers();
1592             super.log(record);
1593         }
1594 
1595         @Override
1596         public void addHandler(Handler h) {
1597             initializeGlobalHandlers();
1598             super.addHandler(h);
1599         }
1600 
1601         @Override
1602         public void removeHandler(Handler h) {
1603             initializeGlobalHandlers();
1604             super.removeHandler(h);
1605         }
1606 
1607         @Override
1608         public Handler[] getHandlers() {
1609             initializeGlobalHandlers();
1610             return super.getHandlers();
1611         }
1612     }
1613 
1614 
1615     // Private method to be called when the configuration has
1616     // changed to apply any level settings to any pre-existing loggers.
1617     synchronized private void setLevelsOnExistingLoggers() {
1618         Enumeration<?> enum_ = props.propertyNames();
1619         while (enum_.hasMoreElements()) {
1620             String key = (String)enum_.nextElement();
1621             if (!key.endsWith(".level")) {
1622                 // Not a level definition.
1623                 continue;
1624             }
1625             int ix = key.length() - 6;
1626             String name = key.substring(0, ix);
1627             Level level = getLevelProperty(key, null);