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