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 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. 400 * @deprecated The dependency on {@code PropertyChangeListener} creates a 401 * significant impediment to future modularization of the Java 402 * platform. This method will be removed in a future release. 403 * The global {@code LogManager} can detect changes to the 404 * logging configuration by overridding the {@link 405 * #readConfiguration readConfiguration} method. 406 */ 407 @Deprecated 408 public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException { 409 PropertyChangeListener listener = Objects.requireNonNull(l); 410 checkPermission(); 411 synchronized (listenerMap) { 412 // increment the registration count if already registered 413 Integer value = listenerMap.get(listener); 414 value = (value == null) ? 1 : (value + 1); 415 listenerMap.put(listener, value); 416 } 417 } 418 419 /** 420 * Removes an event listener for property change events. 421 * If the same listener instance has been added to the listener table 422 * through multiple invocations of <CODE>addPropertyChangeListener</CODE>, 423 * then an equivalent number of 424 * <CODE>removePropertyChangeListener</CODE> invocations are required to remove 425 * all instances of that listener from the listener table. 426 * <P> 427 * Returns silently if the given listener is not found. 428 * 429 * <p><b>WARNING:</b> This method is omitted from this class in all subset 430 * Profiles of Java SE that do not include the {@code java.beans} package. 431 * </p> 432 * 433 * @param l event listener (can be null) 434 * @exception SecurityException if a security manager exists and if 435 * the caller does not have LoggingPermission("control"). 436 * @deprecated The dependency on {@code PropertyChangeListener} creates a 437 * significant impediment to future modularization of the Java 438 * platform. This method will be removed in a future release. 439 * The global {@code LogManager} can detect changes to the 440 * logging configuration by overridding the {@link 441 * #readConfiguration readConfiguration} method. 442 */ 443 @Deprecated 444 public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException { 445 checkPermission(); 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, unless 774 // the logger's level is already initialized 775 Level level = owner.getLevelProperty(name + ".level", null); 776 if (level != null && !logger.isLevelInitialized()) { 777 doSetLevel(logger, level); 778 } 779 780 // instantiation of the handler is done in the LogManager.addLogger 781 // implementation as a handler class may be only visible to LogManager 782 // subclass for the custom log manager case 783 processParentHandlers(logger, name); 784 785 // Find the new node and its parent. 786 LogNode node = getNode(name); 787 node.loggerRef = ref; 788 Logger parent = null; 789 LogNode nodep = node.parent; 790 while (nodep != null) { 791 LoggerWeakRef nodeRef = nodep.loggerRef; 792 if (nodeRef != null) { 793 parent = nodeRef.get(); 794 if (parent != null) { 795 break; 796 } 797 } 798 nodep = nodep.parent; 799 } 800 801 if (parent != null) { 802 doSetParent(logger, parent); 803 } 804 // Walk over the children and tell them we are their new parent. 805 node.walkAndSetParent(logger); 806 // new LogNode is ready so tell the LoggerWeakRef about it 807 ref.setNode(node); 808 return true; 809 } 810 811 // note: all calls to removeLogger are synchronized on LogManager's 812 // intrinsic lock 813 void removeLogger(String name) { 814 namedLoggers.remove(name); 815 } 816 817 synchronized Enumeration<String> getLoggerNames() { 818 // ensure that this context is properly initialized before 819 // returning logger names. 820 ensureInitialized(); 821 return namedLoggers.keys(); 822 } 823 824 // If logger.getUseParentHandlers() returns 'true' and any of the logger's 825 // parents have levels or handlers defined, make sure they are instantiated. 826 private void processParentHandlers(final Logger logger, final String name) { 827 final LogManager owner = getOwner(); 828 AccessController.doPrivileged(new PrivilegedAction<Void>() { 829 @Override 830 public Void run() { 831 if (logger != owner.rootLogger) { 832 boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true); 833 if (!useParent) { 834 logger.setUseParentHandlers(false); 835 } 836 } 837 return null; 838 } 839 }); 840 841 int ix = 1; 842 for (;;) { 843 int ix2 = name.indexOf(".", ix); 844 if (ix2 < 0) { 845 break; 846 } 847 String pname = name.substring(0, ix2); 848 if (owner.getProperty(pname + ".level") != null || 849 owner.getProperty(pname + ".handlers") != null) { 850 // This pname has a level/handlers definition. 851 // Make sure it exists. 852 demandLogger(pname, null); 853 } 854 ix = ix2+1; 855 } 856 } 857 858 // Gets a node in our tree of logger nodes. 859 // If necessary, create it. 860 LogNode getNode(String name) { 861 if (name == null || name.equals("")) { 862 return root; 863 } 864 LogNode node = root; 865 while (name.length() > 0) { 866 int ix = name.indexOf("."); 867 String head; 868 if (ix > 0) { 869 head = name.substring(0, ix); 870 name = name.substring(ix + 1); 871 } else { 872 head = name; 873 name = ""; 874 } 875 if (node.children == null) { 876 node.children = new HashMap<>(); 877 } 878 LogNode child = node.children.get(head); 879 if (child == null) { 880 child = new LogNode(node, this); 881 node.children.put(head, child); 882 } 883 node = child; 884 } 885 return node; 886 } 887 } 888 889 final class SystemLoggerContext extends LoggerContext { 890 // Add a system logger in the system context's namespace as well as 891 // in the LogManager's namespace if not exist so that there is only 892 // one single logger of the given name. System loggers are visible 893 // to applications unless a logger of the same name has been added. 894 @Override 895 Logger demandLogger(String name, String resourceBundleName) { 896 Logger result = findLogger(name); 897 if (result == null) { 898 // only allocate the new system logger once 899 Logger newLogger = new Logger(name, resourceBundleName, null, getOwner()); 900 do { 901 if (addLocalLogger(newLogger)) { 902 // We successfully added the new Logger that we 903 // created above so return it without refetching. 904 result = newLogger; 905 } else { 906 // We didn't add the new Logger that we created above 907 // because another thread added a Logger with the same 908 // name after our null check above and before our call 909 // to addLogger(). We have to refetch the Logger because 910 // addLogger() returns a boolean instead of the Logger 911 // reference itself. However, if the thread that created 912 // the other Logger is not holding a strong reference to 913 // the other Logger, then it is possible for the other 914 // Logger to be GC'ed after we saw it in addLogger() and 915 // before we can refetch it. If it has been GC'ed then 916 // we'll just loop around and try again. 917 result = findLogger(name); 918 } 919 } while (result == null); 920 } 921 return result; 922 } 923 } 924 925 // Add new per logger handlers. 926 // We need to raise privilege here. All our decisions will 927 // be made based on the logging configuration, which can 928 // only be modified by trusted code. 929 private void loadLoggerHandlers(final Logger logger, final String name, 930 final String handlersPropertyName) 931 { 932 AccessController.doPrivileged(new PrivilegedAction<Object>() { 933 @Override 934 public Object run() { 935 String names[] = parseClassNames(handlersPropertyName); 936 for (int i = 0; i < names.length; i++) { 937 String word = names[i]; 938 try { 939 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word); 940 Handler hdl = (Handler) clz.newInstance(); 941 // Check if there is a property defining the 942 // this handler's level. 943 String levs = getProperty(word + ".level"); 944 if (levs != null) { 945 Level l = Level.findLevel(levs); 946 if (l != null) { 947 hdl.setLevel(l); 948 } else { 949 // Probably a bad level. Drop through. 950 System.err.println("Can't set level for " + word); 951 } 952 } 953 // Add this Handler to the logger 954 logger.addHandler(hdl); 955 } catch (Exception ex) { 956 System.err.println("Can't load log handler \"" + word + "\""); 957 System.err.println("" + ex); 958 ex.printStackTrace(); 959 } 960 } 961 return null; 962 } 963 }); 964 } 965 966 967 // loggerRefQueue holds LoggerWeakRef objects for Logger objects 968 // that have been GC'ed. 969 private final ReferenceQueue<Logger> loggerRefQueue 970 = new ReferenceQueue<>(); 971 972 // Package-level inner class. 973 // Helper class for managing WeakReferences to Logger objects. 974 // 975 // LogManager.namedLoggers 976 // - has weak references to all named Loggers 977 // - namedLoggers keeps the LoggerWeakRef objects for the named 978 // Loggers around until we can deal with the book keeping for 979 // the named Logger that is being GC'ed. 980 // LogManager.LogNode.loggerRef 981 // - has a weak reference to a named Logger 982 // - the LogNode will also keep the LoggerWeakRef objects for 983 // the named Loggers around; currently LogNodes never go away. 984 // Logger.kids 985 // - has a weak reference to each direct child Logger; this 986 // includes anonymous and named Loggers 987 // - anonymous Loggers are always children of the rootLogger 988 // which is a strong reference; rootLogger.kids keeps the 989 // LoggerWeakRef objects for the anonymous Loggers around 990 // until we can deal with the book keeping. 991 // 992 final class LoggerWeakRef extends WeakReference<Logger> { 993 private String name; // for namedLoggers cleanup 994 private LogNode node; // for loggerRef cleanup 995 private WeakReference<Logger> parentRef; // for kids cleanup 996 997 LoggerWeakRef(Logger logger) { 998 super(logger, loggerRefQueue); 999 1000 name = logger.getName(); // save for namedLoggers cleanup 1001 } 1002 1003 // dispose of this LoggerWeakRef object 1004 void dispose() { 1005 if (node != null) { 1006 // if we have a LogNode, then we were a named Logger 1007 // so clear namedLoggers weak ref to us 1008 node.context.removeLogger(name); 1009 name = null; // clear our ref to the Logger's name 1010 1011 node.loggerRef = null; // clear LogNode's weak ref to us 1012 node = null; // clear our ref to LogNode 1013 } 1014 1015 if (parentRef != null) { 1016 // this LoggerWeakRef has or had a parent Logger 1017 Logger parent = parentRef.get(); 1018 if (parent != null) { 1019 // the parent Logger is still there so clear the 1020 // parent Logger's weak ref to us 1021 parent.removeChildLogger(this); 1022 } 1023 parentRef = null; // clear our weak ref to the parent Logger 1024 } 1025 } 1026 1027 // set the node field to the specified value 1028 void setNode(LogNode node) { 1029 this.node = node; 1030 } 1031 1032 // set the parentRef field to the specified value 1033 void setParentRef(WeakReference<Logger> parentRef) { 1034 this.parentRef = parentRef; 1035 } 1036 } 1037 1038 // Package-level method. 1039 // Drain some Logger objects that have been GC'ed. 1040 // 1041 // drainLoggerRefQueueBounded() is called by addLogger() below 1042 // and by Logger.getAnonymousLogger(String) so we'll drain up to 1043 // MAX_ITERATIONS GC'ed Loggers for every Logger we add. 1044 // 1045 // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives 1046 // us about a 50/50 mix in increased weak ref counts versus 1047 // decreased weak ref counts in the AnonLoggerWeakRefLeak test. 1048 // Here are stats for cleaning up sets of 400 anonymous Loggers: 1049 // - test duration 1 minute 1050 // - sample size of 125 sets of 400 1051 // - average: 1.99 ms 1052 // - minimum: 0.57 ms 1053 // - maximum: 25.3 ms 1054 // 1055 // The same config gives us a better decreased weak ref count 1056 // than increased weak ref count in the LoggerWeakRefLeak test. 1057 // Here are stats for cleaning up sets of 400 named Loggers: 1058 // - test duration 2 minutes 1059 // - sample size of 506 sets of 400 1060 // - average: 0.57 ms 1061 // - minimum: 0.02 ms 1062 // - maximum: 10.9 ms 1063 // 1064 private final static int MAX_ITERATIONS = 400; 1065 final synchronized void drainLoggerRefQueueBounded() { 1066 for (int i = 0; i < MAX_ITERATIONS; i++) { 1067 if (loggerRefQueue == null) { 1068 // haven't finished loading LogManager yet 1069 break; 1070 } 1071 1072 LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll(); 1073 if (ref == null) { 1074 break; 1075 } 1076 // a Logger object has been GC'ed so clean it up 1077 ref.dispose(); 1078 } 1079 } 1080 1081 /** 1082 * Add a named logger. This does nothing and returns false if a logger 1083 * with the same name is already registered. 1084 * <p> 1085 * The Logger factory methods call this method to register each 1086 * newly created Logger. 1087 * <p> 1088 * The application should retain its own reference to the Logger 1089 * object to avoid it being garbage collected. The LogManager 1090 * may only retain a weak reference. 1091 * 1092 * @param logger the new logger. 1093 * @return true if the argument logger was registered successfully, 1094 * false if a logger of that name already exists. 1095 * @exception NullPointerException if the logger name is null. 1096 */ 1097 public boolean addLogger(Logger logger) { 1098 final String name = logger.getName(); 1099 if (name == null) { 1100 throw new NullPointerException(); 1101 } 1102 drainLoggerRefQueueBounded(); 1103 LoggerContext cx = getUserContext(); 1104 if (cx.addLocalLogger(logger)) { 1105 // Do we have a per logger handler too? 1106 // Note: this will add a 200ms penalty 1107 loadLoggerHandlers(logger, name, name + ".handlers"); 1108 return true; 1109 } else { 1110 return false; 1111 } 1112 } 1113 1114 // Private method to set a level on a logger. 1115 // If necessary, we raise privilege before doing the call. 1116 private static void doSetLevel(final Logger logger, final Level level) { 1117 SecurityManager sm = System.getSecurityManager(); 1118 if (sm == null) { 1119 // There is no security manager, so things are easy. 1120 logger.setLevel(level); 1121 return; 1122 } 1123 // There is a security manager. Raise privilege before 1124 // calling setLevel. 1125 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1126 @Override 1127 public Object run() { 1128 logger.setLevel(level); 1129 return null; 1130 }}); 1131 } 1132 1133 // Private method to set a parent on a logger. 1134 // If necessary, we raise privilege before doing the setParent call. 1135 private static void doSetParent(final Logger logger, final Logger parent) { 1136 SecurityManager sm = System.getSecurityManager(); 1137 if (sm == null) { 1138 // There is no security manager, so things are easy. 1139 logger.setParent(parent); 1140 return; 1141 } 1142 // There is a security manager. Raise privilege before 1143 // calling setParent. 1144 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1145 @Override 1146 public Object run() { 1147 logger.setParent(parent); 1148 return null; 1149 }}); 1150 } 1151 1152 /** 1153 * Method to find a named logger. 1154 * <p> 1155 * Note that since untrusted code may create loggers with 1156 * arbitrary names this method should not be relied on to 1157 * find Loggers for security sensitive logging. 1158 * It is also important to note that the Logger associated with the 1159 * String {@code name} may be garbage collected at any time if there 1160 * is no strong reference to the Logger. The caller of this method 1161 * must check the return value for null in order to properly handle 1162 * the case where the Logger has been garbage collected. 1163 * <p> 1164 * @param name name of the logger 1165 * @return matching logger or null if none is found 1166 */ 1167 public Logger getLogger(String name) { 1168 return getUserContext().findLogger(name); 1169 } 1170 1171 /** 1172 * Get an enumeration of known logger names. 1173 * <p> 1174 * Note: Loggers may be added dynamically as new classes are loaded. 1175 * This method only reports on the loggers that are currently registered. 1176 * It is also important to note that this method only returns the name 1177 * of a Logger, not a strong reference to the Logger itself. 1178 * The returned String does nothing to prevent the Logger from being 1179 * garbage collected. In particular, if the returned name is passed 1180 * to {@code LogManager.getLogger()}, then the caller must check the 1181 * return value from {@code LogManager.getLogger()} for null to properly 1182 * handle the case where the Logger has been garbage collected in the 1183 * time since its name was returned by this method. 1184 * <p> 1185 * @return enumeration of logger name strings 1186 */ 1187 public Enumeration<String> getLoggerNames() { 1188 return getUserContext().getLoggerNames(); 1189 } 1190 1191 /** 1192 * Reinitialize the logging properties and reread the logging configuration. 1193 * <p> 1194 * The same rules are used for locating the configuration properties 1195 * as are used at startup. So normally the logging properties will 1196 * be re-read from the same file that was used at startup. 1197 * <P> 1198 * Any log level definitions in the new configuration file will be 1199 * applied using Logger.setLevel(), if the target Logger exists. 1200 * <p> 1201 * A PropertyChangeEvent will be fired after the properties are read. 1202 * 1203 * @exception SecurityException if a security manager exists and if 1204 * the caller does not have LoggingPermission("control"). 1205 * @exception IOException if there are IO problems reading the configuration. 1206 */ 1207 public void readConfiguration() throws IOException, SecurityException { 1208 checkPermission(); 1209 1210 // if a configuration class is specified, load it and use it. 1211 String cname = System.getProperty("java.util.logging.config.class"); 1212 if (cname != null) { 1213 try { 1214 // Instantiate the named class. It is its constructor's 1215 // responsibility to initialize the logging configuration, by 1216 // calling readConfiguration(InputStream) with a suitable stream. 1217 try { 1218 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname); 1219 clz.newInstance(); 1220 return; 1221 } catch (ClassNotFoundException ex) { 1222 Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname); 1223 clz.newInstance(); 1224 return; 1225 } 1226 } catch (Exception ex) { 1227 System.err.println("Logging configuration class \"" + cname + "\" failed"); 1228 System.err.println("" + ex); 1229 // keep going and useful config file. 1230 } 1231 } 1232 1233 String fname = System.getProperty("java.util.logging.config.file"); 1234 if (fname == null) { 1235 fname = System.getProperty("java.home"); 1236 if (fname == null) { 1237 throw new Error("Can't find java.home ??"); 1238 } 1239 File f = new File(fname, "lib"); 1240 f = new File(f, "logging.properties"); 1241 fname = f.getCanonicalPath(); 1242 } 1243 try (final InputStream in = new FileInputStream(fname)) { 1244 final BufferedInputStream bin = new BufferedInputStream(in); 1245 readConfiguration(bin); 1246 } 1247 } 1248 1249 /** 1250 * Reset the logging configuration. 1251 * <p> 1252 * For all named loggers, the reset operation removes and closes 1253 * all Handlers and (except for the root logger) sets the level 1254 * to null. The root logger's level is set to Level.INFO. 1255 * 1256 * @exception SecurityException if a security manager exists and if 1257 * the caller does not have LoggingPermission("control"). 1258 */ 1259 1260 public void reset() throws SecurityException { 1261 checkPermission(); 1262 synchronized (this) { 1263 props = new Properties(); 1264 // Since we are doing a reset we no longer want to initialize 1265 // the global handlers, if they haven't been initialized yet. 1266 initializedGlobalHandlers = true; 1267 } 1268 for (LoggerContext cx : contexts()) { 1269 Enumeration<String> enum_ = cx.getLoggerNames(); 1270 while (enum_.hasMoreElements()) { 1271 String name = enum_.nextElement(); 1272 Logger logger = cx.findLogger(name); 1273 if (logger != null) { 1274 resetLogger(logger); 1275 } 1276 } 1277 } 1278 } 1279 1280 // Private method to reset an individual target logger. 1281 private void resetLogger(Logger logger) { 1282 // Close all the Logger's handlers. 1283 Handler[] targets = logger.getHandlers(); 1284 for (int i = 0; i < targets.length; i++) { 1285 Handler h = targets[i]; 1286 logger.removeHandler(h); 1287 try { 1288 h.close(); 1289 } catch (Exception ex) { 1290 // Problems closing a handler? Keep going... 1291 } 1292 } 1293 String name = logger.getName(); 1294 if (name != null && name.equals("")) { 1295 // This is the root logger. 1296 logger.setLevel(defaultLevel); 1297 } else { 1298 logger.setLevel(null); 1299 } 1300 } 1301 1302 // get a list of whitespace separated classnames from a property. 1303 private String[] parseClassNames(String propertyName) { 1304 String hands = getProperty(propertyName); 1305 if (hands == null) { 1306 return new String[0]; 1307 } 1308 hands = hands.trim(); 1309 int ix = 0; 1310 final List<String> result = new ArrayList<>(); 1311 while (ix < hands.length()) { 1312 int end = ix; 1313 while (end < hands.length()) { 1314 if (Character.isWhitespace(hands.charAt(end))) { 1315 break; 1316 } 1317 if (hands.charAt(end) == ',') { 1318 break; 1319 } 1320 end++; 1321 } 1322 String word = hands.substring(ix, end); 1323 ix = end+1; 1324 word = word.trim(); 1325 if (word.length() == 0) { 1326 continue; 1327 } 1328 result.add(word); 1329 } 1330 return result.toArray(new String[result.size()]); 1331 } 1332 1333 /** 1334 * Reinitialize the logging properties and reread the logging configuration 1335 * from the given stream, which should be in java.util.Properties format. 1336 * A PropertyChangeEvent will be fired after the properties are read. 1337 * <p> 1338 * Any log level definitions in the new configuration file will be 1339 * applied using Logger.setLevel(), if the target Logger exists. 1340 * 1341 * @param ins stream to read properties from 1342 * @exception SecurityException if a security manager exists and if 1343 * the caller does not have LoggingPermission("control"). 1344 * @exception IOException if there are problems reading from the stream. 1345 */ 1346 public void readConfiguration(InputStream ins) throws IOException, SecurityException { 1347 checkPermission(); 1348 reset(); 1349 1350 // Load the properties 1351 props.load(ins); 1352 // Instantiate new configuration objects. 1353 String names[] = parseClassNames("config"); 1354 1355 for (int i = 0; i < names.length; i++) { 1356 String word = names[i]; 1357 try { 1358 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word); 1359 clz.newInstance(); 1360 } catch (Exception ex) { 1361 System.err.println("Can't load config class \"" + word + "\""); 1362 System.err.println("" + ex); 1363 // ex.printStackTrace(); 1364 } 1365 } 1366 1367 // Set levels on any pre-existing loggers, based on the new properties. 1368 setLevelsOnExistingLoggers(); 1369 1370 // Notify any interested parties that our properties have changed. 1371 // We first take a copy of the listener map so that we aren't holding any 1372 // locks when calling the listeners. 1373 Map<Object,Integer> listeners = null; 1374 synchronized (listenerMap) { 1375 if (!listenerMap.isEmpty()) 1376 listeners = new HashMap<>(listenerMap); 1377 } 1378 if (listeners != null) { 1379 assert Beans.isBeansPresent(); 1380 Object ev = Beans.newPropertyChangeEvent(LogManager.class, null, null, null); 1381 for (Map.Entry<Object,Integer> entry : listeners.entrySet()) { 1382 Object listener = entry.getKey(); 1383 int count = entry.getValue().intValue(); 1384 for (int i = 0; i < count; i++) { 1385 Beans.invokePropertyChange(listener, ev); 1386 } 1387 } 1388 } 1389 1390 1391 // Note that we need to reinitialize global handles when 1392 // they are first referenced. 1393 synchronized (this) { 1394 initializedGlobalHandlers = false; 1395 } 1396 } 1397 1398 /** 1399 * Get the value of a logging property. 1400 * The method returns null if the property is not found. 1401 * @param name property name 1402 * @return property value 1403 */ 1404 public String getProperty(String name) { 1405 return props.getProperty(name); 1406 } 1407 1408 // Package private method to get a String property. 1409 // If the property is not defined we return the given 1410 // default value. 1411 String getStringProperty(String name, String defaultValue) { 1412 String val = getProperty(name); 1413 if (val == null) { 1414 return defaultValue; 1415 } 1416 return val.trim(); 1417 } 1418 1419 // Package private method to get an integer property. 1420 // If the property is not defined or cannot be parsed 1421 // we return the given default value. 1422 int getIntProperty(String name, int defaultValue) { 1423 String val = getProperty(name); 1424 if (val == null) { 1425 return defaultValue; 1426 } 1427 try { 1428 return Integer.parseInt(val.trim()); 1429 } catch (Exception ex) { 1430 return defaultValue; 1431 } 1432 } 1433 1434 // Package private method to get a boolean property. 1435 // If the property is not defined or cannot be parsed 1436 // we return the given default value. 1437 boolean getBooleanProperty(String name, boolean defaultValue) { 1438 String val = getProperty(name); 1439 if (val == null) { 1440 return defaultValue; 1441 } 1442 val = val.toLowerCase(); 1443 if (val.equals("true") || val.equals("1")) { 1444 return true; 1445 } else if (val.equals("false") || val.equals("0")) { 1446 return false; 1447 } 1448 return defaultValue; 1449 } 1450 1451 // Package private method to get a Level property. 1452 // If the property is not defined or cannot be parsed 1453 // we return the given default value. 1454 Level getLevelProperty(String name, Level defaultValue) { 1455 String val = getProperty(name); 1456 if (val == null) { 1457 return defaultValue; 1458 } 1459 Level l = Level.findLevel(val.trim()); 1460 return l != null ? l : defaultValue; 1461 } 1462 1463 // Package private method to get a filter property. 1464 // We return an instance of the class named by the "name" 1465 // property. If the property is not defined or has problems 1466 // we return the defaultValue. 1467 Filter getFilterProperty(String name, Filter defaultValue) { 1468 String val = getProperty(name); 1469 try { 1470 if (val != null) { 1471 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val); 1472 return (Filter) clz.newInstance(); 1473 } 1474 } catch (Exception ex) { 1475 // We got one of a variety of exceptions in creating the 1476 // class or creating an instance. 1477 // Drop through. 1478 } 1479 // We got an exception. Return the defaultValue. 1480 return defaultValue; 1481 } 1482 1483 1484 // Package private method to get a formatter property. 1485 // We return an instance of the class named by the "name" 1486 // property. If the property is not defined or has problems 1487 // we return the defaultValue. 1488 Formatter getFormatterProperty(String name, Formatter defaultValue) { 1489 String val = getProperty(name); 1490 try { 1491 if (val != null) { 1492 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val); 1493 return (Formatter) clz.newInstance(); 1494 } 1495 } catch (Exception ex) { 1496 // We got one of a variety of exceptions in creating the 1497 // class or creating an instance. 1498 // Drop through. 1499 } 1500 // We got an exception. Return the defaultValue. 1501 return defaultValue; 1502 } 1503 1504 // Private method to load the global handlers. 1505 // We do the real work lazily, when the global handlers 1506 // are first used. 1507 private synchronized void initializeGlobalHandlers() { 1508 if (initializedGlobalHandlers) { 1509 return; 1510 } 1511 1512 initializedGlobalHandlers = true; 1513 1514 if (deathImminent) { 1515 // Aaargh... 1516 // The VM is shutting down and our exit hook has been called. 1517 // Avoid allocating global handlers. 1518 return; 1519 } 1520 loadLoggerHandlers(rootLogger, null, "handlers"); 1521 } 1522 1523 private final Permission controlPermission = new LoggingPermission("control", null); 1524 1525 void checkPermission() { 1526 SecurityManager sm = System.getSecurityManager(); 1527 if (sm != null) 1528 sm.checkPermission(controlPermission); 1529 } 1530 1531 /** 1532 * Check that the current context is trusted to modify the logging 1533 * configuration. This requires LoggingPermission("control"). 1534 * <p> 1535 * If the check fails we throw a SecurityException, otherwise 1536 * we return normally. 1537 * 1538 * @exception SecurityException if a security manager exists and if 1539 * the caller does not have LoggingPermission("control"). 1540 */ 1541 public void checkAccess() throws SecurityException { 1542 checkPermission(); 1543 } 1544 1545 // Nested class to represent a node in our tree of named loggers. 1546 private static class LogNode { 1547 HashMap<String,LogNode> children; 1548 LoggerWeakRef loggerRef; 1549 LogNode parent; 1550 final LoggerContext context; 1551 1552 LogNode(LogNode parent, LoggerContext context) { 1553 this.parent = parent; 1554 this.context = context; 1555 } 1556 1557 // Recursive method to walk the tree below a node and set 1558 // a new parent logger. 1559 void walkAndSetParent(Logger parent) { 1560 if (children == null) { 1561 return; 1562 } 1563 Iterator<LogNode> values = children.values().iterator(); 1564 while (values.hasNext()) { 1565 LogNode node = values.next(); 1566 LoggerWeakRef ref = node.loggerRef; 1567 Logger logger = (ref == null) ? null : ref.get(); 1568 if (logger == null) { 1569 node.walkAndSetParent(parent); 1570 } else { 1571 doSetParent(logger, parent); 1572 } 1573 } 1574 } 1575 } 1576 1577 // We use a subclass of Logger for the root logger, so 1578 // that we only instantiate the global handlers when they 1579 // are first needed. 1580 private final class RootLogger extends Logger { 1581 private RootLogger() { 1582 // We do not call the protected Logger two args constructor here, 1583 // to avoid calling LogManager.getLogManager() from within the 1584 // RootLogger constructor. 1585 super("", null, null, LogManager.this); 1586 setLevel(defaultLevel); 1587 } 1588 1589 @Override 1590 public void log(LogRecord record) { 1591 // Make sure that the global handlers have been instantiated. 1592 initializeGlobalHandlers(); 1593 super.log(record); 1594 } 1595 1596 @Override 1597 public void addHandler(Handler h) { 1598 initializeGlobalHandlers(); 1599 super.addHandler(h); 1600 } 1601 1602 @Override 1603 public void removeHandler(Handler h) { 1604 initializeGlobalHandlers(); 1605 super.removeHandler(h); 1606 } 1607 1608 @Override 1609 public Handler[] getHandlers() { 1610 initializeGlobalHandlers(); 1611 return super.getHandlers(); 1612 } 1613 } 1614 1615 1616 // Private method to be called when the configuration has 1617 // changed to apply any level settings to any pre-existing loggers. 1618 synchronized private void setLevelsOnExistingLoggers() { 1619 Enumeration<?> enum_ = props.propertyNames(); 1620 while (enum_.hasMoreElements()) { 1621 String key = (String)enum_.nextElement(); 1622 if (!key.endsWith(".level")) { 1623 // Not a level definition. 1624 continue; 1625 } 1626 int ix = key.length() - 6; 1627 String name = key.substring(0, ix); 1628 Level level = getLevelProperty(key, null); 1629 if (level == null) { 1630 System.err.println("Bad level value for property: " + key); 1631 continue; 1632 } 1633 for (LoggerContext cx : contexts()) { 1634 Logger l = cx.findLogger(name); 1635 if (l == null) { 1636 continue; 1637 } 1638 l.setLevel(level); 1639 } 1640 } 1641 } 1642 1643 // Management Support 1644 private static LoggingMXBean loggingMXBean = null; 1645 /** 1646 * String representation of the 1647 * {@link javax.management.ObjectName} for the management interface 1648 * for the logging facility. 1649 * 1650 * @see java.lang.management.PlatformLoggingMXBean 1651 * @see java.util.logging.LoggingMXBean 1652 * 1653 * @since 1.5 1654 */ 1655 public final static String LOGGING_MXBEAN_NAME 1656 = "java.util.logging:type=Logging"; 1657 1658 /** 1659 * Returns <tt>LoggingMXBean</tt> for managing loggers. 1660 * An alternative way to manage loggers is through the 1661 * {@link java.lang.management.PlatformLoggingMXBean} interface 1662 * that can be obtained by calling: 1663 * <pre> 1664 * PlatformLoggingMXBean logging = {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class) 1665 * ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class); 1666 * </pre> 1667 * 1668 * @return a {@link LoggingMXBean} object. 1669 * 1670 * @see java.lang.management.PlatformLoggingMXBean 1671 * @since 1.5 1672 */ 1673 public static synchronized LoggingMXBean getLoggingMXBean() { 1674 if (loggingMXBean == null) { 1675 loggingMXBean = new Logging(); 1676 } 1677 return loggingMXBean; 1678 } 1679 1680 /** 1681 * A class that provides access to the java.beans.PropertyChangeListener 1682 * and java.beans.PropertyChangeEvent without creating a static dependency 1683 * on java.beans. This class can be removed once the addPropertyChangeListener 1684 * and removePropertyChangeListener methods are removed. 1685 */ 1686 private static class Beans { 1687 private static final Class<?> propertyChangeListenerClass = 1688 getClass("java.beans.PropertyChangeListener"); 1689 1690 private static final Class<?> propertyChangeEventClass = 1691 getClass("java.beans.PropertyChangeEvent"); 1692 1693 private static final Method propertyChangeMethod = 1694 getMethod(propertyChangeListenerClass, 1695 "propertyChange", 1696 propertyChangeEventClass); 1697 1698 private static final Constructor<?> propertyEventCtor = 1699 getConstructor(propertyChangeEventClass, 1700 Object.class, 1701 String.class, 1702 Object.class, 1703 Object.class); 1704 1705 private static Class<?> getClass(String name) { 1706 try { 1707 return Class.forName(name, true, Beans.class.getClassLoader()); 1708 } catch (ClassNotFoundException e) { 1709 return null; 1710 } 1711 } 1712 private static Constructor<?> getConstructor(Class<?> c, Class<?>... types) { 1713 try { 1714 return (c == null) ? null : c.getDeclaredConstructor(types); 1715 } catch (NoSuchMethodException x) { 1716 throw new AssertionError(x); 1717 } 1718 } 1719 1720 private static Method getMethod(Class<?> c, String name, Class<?>... types) { 1721 try { 1722 return (c == null) ? null : c.getMethod(name, types); 1723 } catch (NoSuchMethodException e) { 1724 throw new AssertionError(e); 1725 } 1726 } 1727 1728 /** 1729 * Returns {@code true} if java.beans is present. 1730 */ 1731 static boolean isBeansPresent() { 1732 return propertyChangeListenerClass != null && 1733 propertyChangeEventClass != null; 1734 } 1735 1736 /** 1737 * Returns a new PropertyChangeEvent with the given source, property 1738 * name, old and new values. 1739 */ 1740 static Object newPropertyChangeEvent(Object source, String prop, 1741 Object oldValue, Object newValue) 1742 { 1743 try { 1744 return propertyEventCtor.newInstance(source, prop, oldValue, newValue); 1745 } catch (InstantiationException | IllegalAccessException x) { 1746 throw new AssertionError(x); 1747 } catch (InvocationTargetException x) { 1748 Throwable cause = x.getCause(); 1749 if (cause instanceof Error) 1750 throw (Error)cause; 1751 if (cause instanceof RuntimeException) 1752 throw (RuntimeException)cause; 1753 throw new AssertionError(x); 1754 } 1755 } 1756 1757 /** 1758 * Invokes the given PropertyChangeListener's propertyChange method 1759 * with the given event. 1760 */ 1761 static void invokePropertyChange(Object listener, Object ev) { 1762 try { 1763 propertyChangeMethod.invoke(listener, ev); 1764 } catch (IllegalAccessException x) { 1765 throw new AssertionError(x); 1766 } catch (InvocationTargetException x) { 1767 Throwable cause = x.getCause(); 1768 if (cause instanceof Error) 1769 throw (Error)cause; 1770 if (cause instanceof RuntimeException) 1771 throw (RuntimeException)cause; 1772 throw new AssertionError(x); 1773 } 1774 } 1775 } 1776 }