1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 28 package java.util.logging; 29 30 import dalvik.system.VMStack; 31 import java.lang.ref.WeakReference; 32 import java.security.AccessController; 33 import java.security.PrivilegedAction; 34 import java.util.ArrayList; 35 import java.util.Iterator; 36 import java.util.Locale; 37 import java.util.MissingResourceException; 38 import java.util.ResourceBundle; 39 import java.util.concurrent.CopyOnWriteArrayList; 40 import java.util.function.Supplier; 41 import sun.reflect.CallerSensitive; 42 43 /** 44 * A Logger object is used to log messages for a specific 45 * system or application component. Loggers are normally named, 46 * using a hierarchical dot-separated namespace. Logger names 47 * can be arbitrary strings, but they should normally be based on 48 * the package name or class name of the logged component, such 49 * as java.net or javax.swing. In addition it is possible to create 50 * "anonymous" Loggers that are not stored in the Logger namespace. 51 * <p> 52 * Logger objects may be obtained by calls on one of the getLogger 53 * factory methods. These will either create a new Logger or 54 * return a suitable existing Logger. It is important to note that 55 * the Logger returned by one of the {@code getLogger} factory methods 56 * may be garbage collected at any time if a strong reference to the 57 * Logger is not kept. 58 * <p> 59 * Logging messages will be forwarded to registered Handler 60 * objects, which can forward the messages to a variety of 61 * destinations, including consoles, files, OS logs, etc. 62 * <p> 63 * Each Logger keeps track of a "parent" Logger, which is its 64 * nearest existing ancestor in the Logger namespace. 65 * <p> 66 * Each Logger has a "Level" associated with it. This reflects 67 * a minimum Level that this logger cares about. If a Logger's 68 * level is set to <tt>null</tt>, then its effective level is inherited 69 * from its parent, which may in turn obtain it recursively from its 70 * parent, and so on up the tree. 71 * <p> 72 * The log level can be configured based on the properties from the 73 * logging configuration file, as described in the description 74 * of the LogManager class. However it may also be dynamically changed 75 * by calls on the Logger.setLevel method. If a logger's level is 76 * changed the change may also affect child loggers, since any child 77 * logger that has <tt>null</tt> as its level will inherit its 78 * effective level from its parent. 79 * <p> 80 * On each logging call the Logger initially performs a cheap 81 * check of the request level (e.g., SEVERE or FINE) against the 82 * effective log level of the logger. If the request level is 83 * lower than the log level, the logging call returns immediately. 84 * <p> 85 * After passing this initial (cheap) test, the Logger will allocate 86 * a LogRecord to describe the logging message. It will then call a 87 * Filter (if present) to do a more detailed check on whether the 88 * record should be published. If that passes it will then publish 89 * the LogRecord to its output Handlers. By default, loggers also 90 * publish to their parent's Handlers, recursively up the tree. 91 * <p> 92 * Each Logger may have a {@code ResourceBundle} associated with it. 93 * The {@code ResourceBundle} may be specified by name, using the 94 * {@link #getLogger(java.lang.String, java.lang.String)} factory 95 * method, or by value - using the {@link 96 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method. 97 * This bundle will be used for localizing logging messages. 98 * If a Logger does not have its own {@code ResourceBundle} or resource bundle 99 * name, then it will inherit the {@code ResourceBundle} or resource bundle name 100 * from its parent, recursively up the tree. 101 * <p> 102 * Most of the logger output methods take a "msg" argument. This 103 * msg argument may be either a raw value or a localization key. 104 * During formatting, if the logger has (or inherits) a localization 105 * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for 106 * the msg string, then the msg string is replaced by the localized value. 107 * Otherwise the original msg string is used. Typically, formatters use 108 * java.text.MessageFormat style formatting to format parameters, so 109 * for example a format string "{0} {1}" would format two parameters 110 * as strings. 111 * <p> 112 * A set of methods alternatively take a "msgSupplier" instead of a "msg" 113 * argument. These methods take a {@link Supplier}{@code <String>} function 114 * which is invoked to construct the desired log message only when the message 115 * actually is to be logged based on the effective log level thus eliminating 116 * unnecessary message construction. For example, if the developer wants to 117 * log system health status for diagnosis, with the String-accepting version, 118 * the code would look like: 119 <pre><code> 120 121 class DiagnosisMessages { 122 static String systemHealthStatus() { 123 // collect system health information 124 ... 125 } 126 } 127 ... 128 logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus()); 129 </code></pre> 130 * With the above code, the health status is collected unnecessarily even when 131 * the log level FINER is disabled. With the Supplier-accepting version as 132 * below, the status will only be collected when the log level FINER is 133 * enabled. 134 <pre><code> 135 136 logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus); 137 </code></pre> 138 * <p> 139 * When looking for a {@code ResourceBundle}, the logger will first look at 140 * whether a bundle was specified using {@link 141 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then 142 * only whether a resource bundle name was specified through the {@link 143 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method. 144 * If no {@code ResourceBundle} or no resource bundle name is found, 145 * then it will use the nearest {@code ResourceBundle} or resource bundle 146 * name inherited from its parent tree.<br> 147 * When a {@code ResourceBundle} was inherited or specified through the 148 * {@link 149 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then 150 * that {@code ResourceBundle} will be used. Otherwise if the logger only 151 * has or inherited a resource bundle name, then that resource bundle name 152 * will be mapped to a {@code ResourceBundle} object, using the default Locale 153 * at the time of logging. 154 * <br id="ResourceBundleMapping">When mapping resource bundle names to 155 * {@code ResourceBundle} objects, the logger will first try to use the 156 * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class 157 * loader} to map the given resource bundle name to a {@code ResourceBundle}. 158 * If the thread context class loader is {@code null}, it will try the 159 * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader} 160 * instead. If the {@code ResourceBundle} is still not found, it will use the 161 * class loader of the first caller of the {@link 162 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method. 163 * <p> 164 * Formatting (including localization) is the responsibility of 165 * the output Handler, which will typically call a Formatter. 166 * <p> 167 * Note that formatting need not occur synchronously. It may be delayed 168 * until a LogRecord is actually written to an external sink. 169 * <p> 170 * The logging methods are grouped in five main categories: 171 * <ul> 172 * <li><p> 173 * There are a set of "log" methods that take a log level, a message 174 * string, and optionally some parameters to the message string. 175 * <li><p> 176 * There are a set of "logp" methods (for "log precise") that are 177 * like the "log" methods, but also take an explicit source class name 178 * and method name. 179 * <li><p> 180 * There are a set of "logrb" method (for "log with resource bundle") 181 * that are like the "logp" method, but also take an explicit resource 182 * bundle object for use in localizing the log message. 183 * <li><p> 184 * There are convenience methods for tracing method entries (the 185 * "entering" methods), method returns (the "exiting" methods) and 186 * throwing exceptions (the "throwing" methods). 187 * <li><p> 188 * Finally, there are a set of convenience methods for use in the 189 * very simplest cases, when a developer simply wants to log a 190 * simple string at a given log level. These methods are named 191 * after the standard Level names ("severe", "warning", "info", etc.) 192 * and take a single argument, a message string. 193 * </ul> 194 * <p> 195 * For the methods that do not take an explicit source name and 196 * method name, the Logging framework will make a "best effort" 197 * to determine which class and method called into the logging method. 198 * However, it is important to realize that this automatically inferred 199 * information may only be approximate (or may even be quite wrong!). 200 * Virtual machines are allowed to do extensive optimizations when 201 * JITing and may entirely remove stack frames, making it impossible 202 * to reliably locate the calling class and method. 203 * <P> 204 * All methods on Logger are multi-thread safe. 205 * <p> 206 * <b>Subclassing Information:</b> Note that a LogManager class may 207 * provide its own implementation of named Loggers for any point in 208 * the namespace. Therefore, any subclasses of Logger (unless they 209 * are implemented in conjunction with a new LogManager class) should 210 * take care to obtain a Logger instance from the LogManager class and 211 * should delegate operations such as "isLoggable" and "log(LogRecord)" 212 * to that instance. Note that in order to intercept all logging 213 * output, subclasses need only override the log(LogRecord) method. 214 * All the other logging methods are implemented as calls on this 215 * log(LogRecord) method. 216 * 217 * @since 1.4 218 */ 219 public class Logger { 220 private static final Handler emptyHandlers[] = new Handler[0]; 221 private static final int offValue = Level.OFF.intValue(); 222 223 static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging"; 224 225 // This class is immutable and it is important that it remains so. 226 private static final class LoggerBundle { 227 final String resourceBundleName; // Base name of the bundle. 228 final ResourceBundle userBundle; // Bundle set through setResourceBundle. LoggerBundle(String resourceBundleName, ResourceBundle bundle)229 private LoggerBundle(String resourceBundleName, ResourceBundle bundle) { 230 this.resourceBundleName = resourceBundleName; 231 this.userBundle = bundle; 232 } isSystemBundle()233 boolean isSystemBundle() { 234 return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName); 235 } get(String name, ResourceBundle bundle)236 static LoggerBundle get(String name, ResourceBundle bundle) { 237 if (name == null && bundle == null) { 238 return NO_RESOURCE_BUNDLE; 239 } else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) { 240 return SYSTEM_BUNDLE; 241 } else { 242 return new LoggerBundle(name, bundle); 243 } 244 } 245 } 246 247 // This instance will be shared by all loggers created by the system 248 // code 249 private static final LoggerBundle SYSTEM_BUNDLE = 250 new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null); 251 252 // This instance indicates that no resource bundle has been specified yet, 253 // and it will be shared by all loggers which have no resource bundle. 254 private static final LoggerBundle NO_RESOURCE_BUNDLE = 255 new LoggerBundle(null, null); 256 257 private volatile LogManager manager; 258 private String name; 259 private final CopyOnWriteArrayList<Handler> handlers = 260 new CopyOnWriteArrayList<>(); 261 private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE; 262 private volatile boolean useParentHandlers = true; 263 private volatile Filter filter; 264 private boolean anonymous; 265 266 // Cache to speed up behavior of findResourceBundle: 267 private ResourceBundle catalog; // Cached resource bundle 268 private String catalogName; // name associated with catalog 269 private Locale catalogLocale; // locale associated with catalog 270 271 // The fields relating to parent-child relationships and levels 272 // are managed under a separate lock, the treeLock. 273 private static final Object treeLock = new Object(); 274 // We keep weak references from parents to children, but strong 275 // references from children to parents. 276 private volatile Logger parent; // our nearest parent. 277 private ArrayList<LogManager.LoggerWeakRef> kids; // WeakReferences to loggers that have us as parent 278 private volatile Level levelObject; 279 private volatile int levelValue; // current effective level value 280 private WeakReference<ClassLoader> callersClassLoaderRef; 281 private final boolean isSystemLogger; 282 283 /** 284 * GLOBAL_LOGGER_NAME is a name for the global logger. 285 * 286 * @since 1.6 287 */ 288 public static final String GLOBAL_LOGGER_NAME = "global"; 289 290 /** 291 * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME. 292 * 293 * @return global logger object 294 * @since 1.7 295 */ getGlobal()296 public static final Logger getGlobal() { 297 // In order to break a cyclic dependence between the LogManager 298 // and Logger static initializers causing deadlocks, the global 299 // logger is created with a special constructor that does not 300 // initialize its log manager. 301 // 302 // If an application calls Logger.getGlobal() before any logger 303 // has been initialized, it is therefore possible that the 304 // LogManager class has not been initialized yet, and therefore 305 // Logger.global.manager will be null. 306 // 307 // In order to finish the initialization of the global logger, we 308 // will therefore call LogManager.getLogManager() here. 309 // 310 // To prevent race conditions we also need to call 311 // LogManager.getLogManager() unconditionally here. 312 // Indeed we cannot rely on the observed value of global.manager, 313 // because global.manager will become not null somewhere during 314 // the initialization of LogManager. 315 // If two threads are calling getGlobal() concurrently, one thread 316 // will see global.manager null and call LogManager.getLogManager(), 317 // but the other thread could come in at a time when global.manager 318 // is already set although ensureLogManagerInitialized is not finished 319 // yet... 320 // Calling LogManager.getLogManager() unconditionally will fix that. 321 322 LogManager.getLogManager(); 323 324 // Now the global LogManager should be initialized, 325 // and the global logger should have been added to 326 // it, unless we were called within the constructor of a LogManager 327 // subclass installed as LogManager, in which case global.manager 328 // would still be null, and global will be lazily initialized later on. 329 330 return global; 331 } 332 333 /** 334 * The "global" Logger object is provided as a convenience to developers 335 * who are making casual use of the Logging package. Developers 336 * who are making serious use of the logging package (for example 337 * in products) should create and use their own Logger objects, 338 * with appropriate names, so that logging can be controlled on a 339 * suitable per-Logger granularity. Developers also need to keep a 340 * strong reference to their Logger objects to prevent them from 341 * being garbage collected. 342 * <p> 343 * @deprecated Initialization of this field is prone to deadlocks. 344 * The field must be initialized by the Logger class initialization 345 * which may cause deadlocks with the LogManager class initialization. 346 * In such cases two class initialization wait for each other to complete. 347 * The preferred way to get the global logger object is via the call 348 * <code>Logger.getGlobal()</code>. 349 * For compatibility with old JDK versions where the 350 * <code>Logger.getGlobal()</code> is not available use the call 351 * <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code> 352 * or <code>Logger.getLogger("global")</code>. 353 */ 354 @Deprecated 355 public static final Logger global = new Logger(GLOBAL_LOGGER_NAME); 356 357 /** 358 * Protected method to construct a logger for a named subsystem. 359 * <p> 360 * The logger will be initially configured with a null Level 361 * and with useParentHandlers set to true. 362 * 363 * @param name A name for the logger. This should 364 * be a dot-separated name and should normally 365 * be based on the package name or class name 366 * of the subsystem, such as java.net 367 * or javax.swing. It may be null for anonymous Loggers. 368 * @param resourceBundleName name of ResourceBundle to be used for localizing 369 * messages for this logger. May be null if none 370 * of the messages require localization. 371 * @throws MissingResourceException if the resourceBundleName is non-null and 372 * no corresponding resource can be found. 373 */ Logger(String name, String resourceBundleName)374 protected Logger(String name, String resourceBundleName) { 375 this(name, resourceBundleName, null, LogManager.getLogManager(), false); 376 } 377 Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager, boolean isSystemLogger)378 Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager, boolean isSystemLogger) { 379 this.manager = manager; 380 this.isSystemLogger = isSystemLogger; 381 setupResourceInfo(resourceBundleName, caller); 382 this.name = name; 383 levelValue = Level.INFO.intValue(); 384 } 385 setCallersClassLoaderRef(Class<?> caller)386 private void setCallersClassLoaderRef(Class<?> caller) { 387 ClassLoader callersClassLoader = ((caller != null) 388 ? caller.getClassLoader() 389 : null); 390 if (callersClassLoader != null) { 391 this.callersClassLoaderRef = new WeakReference<>(callersClassLoader); 392 } 393 } 394 getCallersClassLoader()395 private ClassLoader getCallersClassLoader() { 396 return (callersClassLoaderRef != null) 397 ? callersClassLoaderRef.get() 398 : null; 399 } 400 401 // This constructor is used only to create the global Logger. 402 // It is needed to break a cyclic dependence between the LogManager 403 // and Logger static initializers causing deadlocks. Logger(String name)404 private Logger(String name) { 405 // The manager field is not initialized here. 406 this.name = name; 407 this.isSystemLogger = true; 408 levelValue = Level.INFO.intValue(); 409 } 410 411 // It is called from LoggerContext.addLocalLogger() when the logger 412 // is actually added to a LogManager. setLogManager(LogManager manager)413 void setLogManager(LogManager manager) { 414 this.manager = manager; 415 } 416 checkPermission()417 private void checkPermission() throws SecurityException { 418 if (!anonymous) { 419 if (manager == null) { 420 // Complete initialization of the global Logger. 421 manager = LogManager.getLogManager(); 422 } 423 manager.checkPermission(); 424 } 425 } 426 427 // Until all JDK code converted to call sun.util.logging.PlatformLogger 428 // (see 7054233), we need to determine if Logger.getLogger is to add 429 // a system logger or user logger. 430 // 431 // As an interim solution, if the immediate caller whose caller loader is 432 // null, we assume it's a system logger and add it to the system context. 433 // These system loggers only set the resource bundle to the given 434 // resource bundle name (rather than the default system resource bundle). 435 private static class SystemLoggerHelper { 436 static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck"); getBooleanProperty(final String key)437 private static boolean getBooleanProperty(final String key) { 438 String s = AccessController.doPrivileged(new PrivilegedAction<String>() { 439 @Override 440 public String run() { 441 return System.getProperty(key); 442 } 443 }); 444 return Boolean.parseBoolean(s); 445 } 446 } 447 demandLogger(String name, String resourceBundleName, Class<?> caller)448 private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { 449 LogManager manager = LogManager.getLogManager(); 450 SecurityManager sm = System.getSecurityManager(); 451 if (sm != null && !SystemLoggerHelper.disableCallerCheck) { 452 if (caller.getClassLoader() == null) { 453 return manager.demandSystemLogger(name, resourceBundleName); 454 } 455 } 456 return manager.demandLogger(name, resourceBundleName, caller); 457 // ends up calling new Logger(name, resourceBundleName, caller) 458 // iff the logger doesn't exist already 459 } 460 461 /** 462 * Find or create a logger for a named subsystem. If a logger has 463 * already been created with the given name it is returned. Otherwise 464 * a new logger is created. 465 * <p> 466 * If a new logger is created its log level will be configured 467 * based on the LogManager configuration and it will configured 468 * to also send logging output to its parent's Handlers. It will 469 * be registered in the LogManager global namespace. 470 * <p> 471 * Note: The LogManager may only retain a weak reference to the newly 472 * created Logger. It is important to understand that a previously 473 * created Logger with the given name may be garbage collected at any 474 * time if there is no strong reference to the Logger. In particular, 475 * this means that two back-to-back calls like 476 * {@code getLogger("MyLogger").log(...)} may use different Logger 477 * objects named "MyLogger" if there is no strong reference to the 478 * Logger named "MyLogger" elsewhere in the program. 479 * 480 * @param name A name for the logger. This should 481 * be a dot-separated name and should normally 482 * be based on the package name or class name 483 * of the subsystem, such as java.net 484 * or javax.swing 485 * @return a suitable Logger 486 * @throws NullPointerException if the name is null. 487 */ 488 489 // Synchronization is not required here. All synchronization for 490 // adding a new Logger object is handled by LogManager.addLogger(). 491 @CallerSensitive getLogger(String name)492 public static Logger getLogger(String name) { 493 // This method is intentionally not a wrapper around a call 494 // to getLogger(name, resourceBundleName). If it were then 495 // this sequence: 496 // 497 // getLogger("Foo", "resourceBundleForFoo"); 498 // getLogger("Foo"); 499 // 500 // would throw an IllegalArgumentException in the second call 501 // because the wrapper would result in an attempt to replace 502 // the existing "resourceBundleForFoo" with null. 503 // 504 // Android-changed: Use VMStack.getStackClass1. 505 return demandLogger(name, null, VMStack.getStackClass1()); 506 } 507 508 /** 509 * Find or create a logger for a named subsystem. If a logger has 510 * already been created with the given name it is returned. Otherwise 511 * a new logger is created. 512 * <p> 513 * If a new logger is created its log level will be configured 514 * based on the LogManager and it will configured to also send logging 515 * output to its parent's Handlers. It will be registered in 516 * the LogManager global namespace. 517 * <p> 518 * Note: The LogManager may only retain a weak reference to the newly 519 * created Logger. It is important to understand that a previously 520 * created Logger with the given name may be garbage collected at any 521 * time if there is no strong reference to the Logger. In particular, 522 * this means that two back-to-back calls like 523 * {@code getLogger("MyLogger", ...).log(...)} may use different Logger 524 * objects named "MyLogger" if there is no strong reference to the 525 * Logger named "MyLogger" elsewhere in the program. 526 * <p> 527 * If the named Logger already exists and does not yet have a 528 * localization resource bundle then the given resource bundle 529 * name is used. If the named Logger already exists and has 530 * a different resource bundle name then an IllegalArgumentException 531 * is thrown. 532 * <p> 533 * @param name A name for the logger. This should 534 * be a dot-separated name and should normally 535 * be based on the package name or class name 536 * of the subsystem, such as java.net 537 * or javax.swing 538 * @param resourceBundleName name of ResourceBundle to be used for localizing 539 * messages for this logger. May be {@code null} 540 * if none of the messages require localization. 541 * @return a suitable Logger 542 * @throws MissingResourceException if the resourceBundleName is non-null and 543 * no corresponding resource can be found. 544 * @throws IllegalArgumentException if the Logger already exists and uses 545 * a different resource bundle name; or if 546 * {@code resourceBundleName} is {@code null} but the named 547 * logger has a resource bundle set. 548 * @throws NullPointerException if the name is null. 549 */ 550 551 // Synchronization is not required here. All synchronization for 552 // adding a new Logger object is handled by LogManager.addLogger(). 553 @CallerSensitive getLogger(String name, String resourceBundleName)554 public static Logger getLogger(String name, String resourceBundleName) { 555 // Android-changed: Use VMStack.getStackClass1. 556 Class<?> callerClass = VMStack.getStackClass1(); 557 Logger result = demandLogger(name, resourceBundleName, callerClass); 558 559 // MissingResourceException or IllegalArgumentException can be 560 // thrown by setupResourceInfo(). 561 // We have to set the callers ClassLoader here in case demandLogger 562 // above found a previously created Logger. This can happen, for 563 // example, if Logger.getLogger(name) is called and subsequently 564 // Logger.getLogger(name, resourceBundleName) is called. In this case 565 // we won't necessarily have the correct classloader saved away, so 566 // we need to set it here, too. 567 568 result.setupResourceInfo(resourceBundleName, callerClass); 569 return result; 570 } 571 572 // package-private 573 // Add a platform logger to the system context. 574 // i.e. caller of sun.util.logging.PlatformLogger.getLogger getPlatformLogger(String name)575 static Logger getPlatformLogger(String name) { 576 LogManager manager = LogManager.getLogManager(); 577 578 // all loggers in the system context will default to 579 // the system logger's resource bundle 580 Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME); 581 return result; 582 } 583 584 /** 585 * Create an anonymous Logger. The newly created Logger is not 586 * registered in the LogManager namespace. There will be no 587 * access checks on updates to the logger. 588 * <p> 589 * This factory method is primarily intended for use from applets. 590 * Because the resulting Logger is anonymous it can be kept private 591 * by the creating class. This removes the need for normal security 592 * checks, which in turn allows untrusted applet code to update 593 * the control state of the Logger. For example an applet can do 594 * a setLevel or an addHandler on an anonymous Logger. 595 * <p> 596 * Even although the new logger is anonymous, it is configured 597 * to have the root logger ("") as its parent. This means that 598 * by default it inherits its effective level and handlers 599 * from the root logger. Changing its parent via the 600 * {@link #setParent(java.util.logging.Logger) setParent} method 601 * will still require the security permission specified by that method. 602 * <p> 603 * 604 * @return a newly created private Logger 605 */ getAnonymousLogger()606 public static Logger getAnonymousLogger() { 607 return getAnonymousLogger(null); 608 } 609 610 /** 611 * Create an anonymous Logger. The newly created Logger is not 612 * registered in the LogManager namespace. There will be no 613 * access checks on updates to the logger. 614 * <p> 615 * This factory method is primarily intended for use from applets. 616 * Because the resulting Logger is anonymous it can be kept private 617 * by the creating class. This removes the need for normal security 618 * checks, which in turn allows untrusted applet code to update 619 * the control state of the Logger. For example an applet can do 620 * a setLevel or an addHandler on an anonymous Logger. 621 * <p> 622 * Even although the new logger is anonymous, it is configured 623 * to have the root logger ("") as its parent. This means that 624 * by default it inherits its effective level and handlers 625 * from the root logger. Changing its parent via the 626 * {@link #setParent(java.util.logging.Logger) setParent} method 627 * will still require the security permission specified by that method. 628 * <p> 629 * @param resourceBundleName name of ResourceBundle to be used for localizing 630 * messages for this logger. 631 * May be null if none of the messages require localization. 632 * @return a newly created private Logger 633 * @throws MissingResourceException if the resourceBundleName is non-null and 634 * no corresponding resource can be found. 635 */ 636 637 // Synchronization is not required here. All synchronization for 638 // adding a new anonymous Logger object is handled by doSetParent(). 639 @CallerSensitive getAnonymousLogger(String resourceBundleName)640 public static Logger getAnonymousLogger(String resourceBundleName) { 641 LogManager manager = LogManager.getLogManager(); 642 // cleanup some Loggers that have been GC'ed 643 manager.drainLoggerRefQueueBounded(); 644 // Android-changed: Use VMStack.getStackClass1. 645 Logger result = new Logger(null, resourceBundleName, 646 VMStack.getStackClass1(), manager, false); 647 result.anonymous = true; 648 Logger root = manager.getLogger(""); 649 result.doSetParent(root); 650 return result; 651 } 652 653 /** 654 * Retrieve the localization resource bundle for this 655 * logger. 656 * This method will return a {@code ResourceBundle} that was either 657 * set by the {@link 658 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or 659 * <a href="#ResourceBundleMapping">mapped from the 660 * the resource bundle name</a> set via the {@link 661 * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory 662 * method for the current default locale. 663 * <br>Note that if the result is {@code null}, then the Logger will use a resource 664 * bundle or resource bundle name inherited from its parent. 665 * 666 * @return localization bundle (may be {@code null}) 667 */ getResourceBundle()668 public ResourceBundle getResourceBundle() { 669 return findResourceBundle(getResourceBundleName(), true); 670 } 671 672 /** 673 * Retrieve the localization resource bundle name for this 674 * logger. 675 * This is either the name specified through the {@link 676 * #getLogger(java.lang.String, java.lang.String) getLogger} factory method, 677 * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the 678 * ResourceBundle set through {@link 679 * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method. 680 * <br>Note that if the result is {@code null}, then the Logger will use a resource 681 * bundle or resource bundle name inherited from its parent. 682 * 683 * @return localization bundle name (may be {@code null}) 684 */ getResourceBundleName()685 public String getResourceBundleName() { 686 return loggerBundle.resourceBundleName; 687 } 688 689 /** 690 * Set a filter to control output on this Logger. 691 * <P> 692 * After passing the initial "level" check, the Logger will 693 * call this Filter to check if a log record should really 694 * be published. 695 * 696 * @param newFilter a filter object (may be null) 697 * @throws SecurityException if a security manager exists, 698 * this logger is not anonymous, and the caller 699 * does not have LoggingPermission("control"). 700 */ setFilter(Filter newFilter)701 public void setFilter(Filter newFilter) throws SecurityException { 702 checkPermission(); 703 filter = newFilter; 704 } 705 706 /** 707 * Get the current filter for this Logger. 708 * 709 * @return a filter object (may be null) 710 */ getFilter()711 public Filter getFilter() { 712 return filter; 713 } 714 715 /** 716 * Log a LogRecord. 717 * <p> 718 * All the other logging methods in this class call through 719 * this method to actually perform any logging. Subclasses can 720 * override this single method to capture all log activity. 721 * 722 * @param record the LogRecord to be published 723 */ log(LogRecord record)724 public void log(LogRecord record) { 725 if (!isLoggable(record.getLevel())) { 726 return; 727 } 728 Filter theFilter = filter; 729 if (theFilter != null && !theFilter.isLoggable(record)) { 730 return; 731 } 732 733 // Post the LogRecord to all our Handlers, and then to 734 // our parents' handlers, all the way up the tree. 735 736 Logger logger = this; 737 while (logger != null) { 738 final Handler[] loggerHandlers = isSystemLogger 739 ? logger.accessCheckedHandlers() 740 : logger.getHandlers(); 741 742 for (Handler handler : loggerHandlers) { 743 handler.publish(record); 744 } 745 746 final boolean useParentHdls = isSystemLogger 747 ? logger.useParentHandlers 748 : logger.getUseParentHandlers(); 749 750 if (!useParentHdls) { 751 break; 752 } 753 754 logger = isSystemLogger ? logger.parent : logger.getParent(); 755 } 756 } 757 758 // private support method for logging. 759 // We fill in the logger name, resource bundle name, and 760 // resource bundle and then call "void log(LogRecord)". doLog(LogRecord lr)761 private void doLog(LogRecord lr) { 762 lr.setLoggerName(name); 763 final LoggerBundle lb = getEffectiveLoggerBundle(); 764 final ResourceBundle bundle = lb.userBundle; 765 final String ebname = lb.resourceBundleName; 766 if (ebname != null && bundle != null) { 767 lr.setResourceBundleName(ebname); 768 lr.setResourceBundle(bundle); 769 } 770 log(lr); 771 } 772 773 774 //================================================================ 775 // Start of convenience methods WITHOUT className and methodName 776 //================================================================ 777 778 /** 779 * Log a message, with no arguments. 780 * <p> 781 * If the logger is currently enabled for the given message 782 * level then the given message is forwarded to all the 783 * registered output Handler objects. 784 * <p> 785 * @param level One of the message level identifiers, e.g., SEVERE 786 * @param msg The string message (or a key in the message catalog) 787 */ log(Level level, String msg)788 public void log(Level level, String msg) { 789 if (!isLoggable(level)) { 790 return; 791 } 792 LogRecord lr = new LogRecord(level, msg); 793 doLog(lr); 794 } 795 796 /** 797 * Log a message, which is only to be constructed if the logging level 798 * is such that the message will actually be logged. 799 * <p> 800 * If the logger is currently enabled for the given message 801 * level then the message is constructed by invoking the provided 802 * supplier function and forwarded to all the registered output 803 * Handler objects. 804 * <p> 805 * @param level One of the message level identifiers, e.g., SEVERE 806 * @param msgSupplier A function, which when called, produces the 807 * desired log message 808 * @since 1.8 809 */ log(Level level, Supplier<String> msgSupplier)810 public void log(Level level, Supplier<String> msgSupplier) { 811 if (!isLoggable(level)) { 812 return; 813 } 814 LogRecord lr = new LogRecord(level, msgSupplier.get()); 815 doLog(lr); 816 } 817 818 /** 819 * Log a message, with one object parameter. 820 * <p> 821 * If the logger is currently enabled for the given message 822 * level then a corresponding LogRecord is created and forwarded 823 * to all the registered output Handler objects. 824 * <p> 825 * @param level One of the message level identifiers, e.g., SEVERE 826 * @param msg The string message (or a key in the message catalog) 827 * @param param1 parameter to the message 828 */ log(Level level, String msg, Object param1)829 public void log(Level level, String msg, Object param1) { 830 if (!isLoggable(level)) { 831 return; 832 } 833 LogRecord lr = new LogRecord(level, msg); 834 Object params[] = { param1 }; 835 lr.setParameters(params); 836 doLog(lr); 837 } 838 839 /** 840 * Log a message, with an array of object arguments. 841 * <p> 842 * If the logger is currently enabled for the given message 843 * level then a corresponding LogRecord is created and forwarded 844 * to all the registered output Handler objects. 845 * <p> 846 * @param level One of the message level identifiers, e.g., SEVERE 847 * @param msg The string message (or a key in the message catalog) 848 * @param params array of parameters to the message 849 */ log(Level level, String msg, Object params[])850 public void log(Level level, String msg, Object params[]) { 851 if (!isLoggable(level)) { 852 return; 853 } 854 LogRecord lr = new LogRecord(level, msg); 855 lr.setParameters(params); 856 doLog(lr); 857 } 858 859 /** 860 * Log a message, with associated Throwable information. 861 * <p> 862 * If the logger is currently enabled for the given message 863 * level then the given arguments are stored in a LogRecord 864 * which is forwarded to all registered output handlers. 865 * <p> 866 * Note that the thrown argument is stored in the LogRecord thrown 867 * property, rather than the LogRecord parameters property. Thus it is 868 * processed specially by output Formatters and is not treated 869 * as a formatting parameter to the LogRecord message property. 870 * <p> 871 * @param level One of the message level identifiers, e.g., SEVERE 872 * @param msg The string message (or a key in the message catalog) 873 * @param thrown Throwable associated with log message. 874 */ log(Level level, String msg, Throwable thrown)875 public void log(Level level, String msg, Throwable thrown) { 876 if (!isLoggable(level)) { 877 return; 878 } 879 LogRecord lr = new LogRecord(level, msg); 880 lr.setThrown(thrown); 881 doLog(lr); 882 } 883 884 /** 885 * Log a lazily constructed message, with associated Throwable information. 886 * <p> 887 * If the logger is currently enabled for the given message level then the 888 * message is constructed by invoking the provided supplier function. The 889 * message and the given {@link Throwable} are then stored in a {@link 890 * LogRecord} which is forwarded to all registered output handlers. 891 * <p> 892 * Note that the thrown argument is stored in the LogRecord thrown 893 * property, rather than the LogRecord parameters property. Thus it is 894 * processed specially by output Formatters and is not treated 895 * as a formatting parameter to the LogRecord message property. 896 * <p> 897 * @param level One of the message level identifiers, e.g., SEVERE 898 * @param thrown Throwable associated with log message. 899 * @param msgSupplier A function, which when called, produces the 900 * desired log message 901 * @since 1.8 902 */ log(Level level, Throwable thrown, Supplier<String> msgSupplier)903 public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) { 904 if (!isLoggable(level)) { 905 return; 906 } 907 LogRecord lr = new LogRecord(level, msgSupplier.get()); 908 lr.setThrown(thrown); 909 doLog(lr); 910 } 911 912 //================================================================ 913 // Start of convenience methods WITH className and methodName 914 //================================================================ 915 916 /** 917 * Log a message, specifying source class and method, 918 * with no arguments. 919 * <p> 920 * If the logger is currently enabled for the given message 921 * level then the given message is forwarded to all the 922 * registered output Handler objects. 923 * <p> 924 * @param level One of the message level identifiers, e.g., SEVERE 925 * @param sourceClass name of class that issued the logging request 926 * @param sourceMethod name of method that issued the logging request 927 * @param msg The string message (or a key in the message catalog) 928 */ logp(Level level, String sourceClass, String sourceMethod, String msg)929 public void logp(Level level, String sourceClass, String sourceMethod, String msg) { 930 if (!isLoggable(level)) { 931 return; 932 } 933 LogRecord lr = new LogRecord(level, msg); 934 lr.setSourceClassName(sourceClass); 935 lr.setSourceMethodName(sourceMethod); 936 doLog(lr); 937 } 938 939 /** 940 * Log a lazily constructed message, specifying source class and method, 941 * with no arguments. 942 * <p> 943 * If the logger is currently enabled for the given message 944 * level then the message is constructed by invoking the provided 945 * supplier function and forwarded to all the registered output 946 * Handler objects. 947 * <p> 948 * @param level One of the message level identifiers, e.g., SEVERE 949 * @param sourceClass name of class that issued the logging request 950 * @param sourceMethod name of method that issued the logging request 951 * @param msgSupplier A function, which when called, produces the 952 * desired log message 953 * @since 1.8 954 */ logp(Level level, String sourceClass, String sourceMethod, Supplier<String> msgSupplier)955 public void logp(Level level, String sourceClass, String sourceMethod, 956 Supplier<String> msgSupplier) { 957 if (!isLoggable(level)) { 958 return; 959 } 960 LogRecord lr = new LogRecord(level, msgSupplier.get()); 961 lr.setSourceClassName(sourceClass); 962 lr.setSourceMethodName(sourceMethod); 963 doLog(lr); 964 } 965 966 /** 967 * Log a message, specifying source class and method, 968 * with a single object parameter to the log message. 969 * <p> 970 * If the logger is currently enabled for the given message 971 * level then a corresponding LogRecord is created and forwarded 972 * to all the registered output Handler objects. 973 * <p> 974 * @param level One of the message level identifiers, e.g., SEVERE 975 * @param sourceClass name of class that issued the logging request 976 * @param sourceMethod name of method that issued the logging request 977 * @param msg The string message (or a key in the message catalog) 978 * @param param1 Parameter to the log message. 979 */ logp(Level level, String sourceClass, String sourceMethod, String msg, Object param1)980 public void logp(Level level, String sourceClass, String sourceMethod, 981 String msg, Object param1) { 982 if (!isLoggable(level)) { 983 return; 984 } 985 LogRecord lr = new LogRecord(level, msg); 986 lr.setSourceClassName(sourceClass); 987 lr.setSourceMethodName(sourceMethod); 988 Object params[] = { param1 }; 989 lr.setParameters(params); 990 doLog(lr); 991 } 992 993 /** 994 * Log a message, specifying source class and method, 995 * with an array of object arguments. 996 * <p> 997 * If the logger is currently enabled for the given message 998 * level then a corresponding LogRecord is created and forwarded 999 * to all the registered output Handler objects. 1000 * <p> 1001 * @param level One of the message level identifiers, e.g., SEVERE 1002 * @param sourceClass name of class that issued the logging request 1003 * @param sourceMethod name of method that issued the logging request 1004 * @param msg The string message (or a key in the message catalog) 1005 * @param params Array of parameters to the message 1006 */ logp(Level level, String sourceClass, String sourceMethod, String msg, Object params[])1007 public void logp(Level level, String sourceClass, String sourceMethod, 1008 String msg, Object params[]) { 1009 if (!isLoggable(level)) { 1010 return; 1011 } 1012 LogRecord lr = new LogRecord(level, msg); 1013 lr.setSourceClassName(sourceClass); 1014 lr.setSourceMethodName(sourceMethod); 1015 lr.setParameters(params); 1016 doLog(lr); 1017 } 1018 1019 /** 1020 * Log a message, specifying source class and method, 1021 * with associated Throwable information. 1022 * <p> 1023 * If the logger is currently enabled for the given message 1024 * level then the given arguments are stored in a LogRecord 1025 * which is forwarded to all registered output handlers. 1026 * <p> 1027 * Note that the thrown argument is stored in the LogRecord thrown 1028 * property, rather than the LogRecord parameters property. Thus it is 1029 * processed specially by output Formatters and is not treated 1030 * as a formatting parameter to the LogRecord message property. 1031 * <p> 1032 * @param level One of the message level identifiers, e.g., SEVERE 1033 * @param sourceClass name of class that issued the logging request 1034 * @param sourceMethod name of method that issued the logging request 1035 * @param msg The string message (or a key in the message catalog) 1036 * @param thrown Throwable associated with log message. 1037 */ logp(Level level, String sourceClass, String sourceMethod, String msg, Throwable thrown)1038 public void logp(Level level, String sourceClass, String sourceMethod, 1039 String msg, Throwable thrown) { 1040 if (!isLoggable(level)) { 1041 return; 1042 } 1043 LogRecord lr = new LogRecord(level, msg); 1044 lr.setSourceClassName(sourceClass); 1045 lr.setSourceMethodName(sourceMethod); 1046 lr.setThrown(thrown); 1047 doLog(lr); 1048 } 1049 1050 /** 1051 * Log a lazily constructed message, specifying source class and method, 1052 * with associated Throwable information. 1053 * <p> 1054 * If the logger is currently enabled for the given message level then the 1055 * message is constructed by invoking the provided supplier function. The 1056 * message and the given {@link Throwable} are then stored in a {@link 1057 * LogRecord} which is forwarded to all registered output handlers. 1058 * <p> 1059 * Note that the thrown argument is stored in the LogRecord thrown 1060 * property, rather than the LogRecord parameters property. Thus it is 1061 * processed specially by output Formatters and is not treated 1062 * as a formatting parameter to the LogRecord message property. 1063 * <p> 1064 * @param level One of the message level identifiers, e.g., SEVERE 1065 * @param sourceClass name of class that issued the logging request 1066 * @param sourceMethod name of method that issued the logging request 1067 * @param thrown Throwable associated with log message. 1068 * @param msgSupplier A function, which when called, produces the 1069 * desired log message 1070 * @since 1.8 1071 */ logp(Level level, String sourceClass, String sourceMethod, Throwable thrown, Supplier<String> msgSupplier)1072 public void logp(Level level, String sourceClass, String sourceMethod, 1073 Throwable thrown, Supplier<String> msgSupplier) { 1074 if (!isLoggable(level)) { 1075 return; 1076 } 1077 LogRecord lr = new LogRecord(level, msgSupplier.get()); 1078 lr.setSourceClassName(sourceClass); 1079 lr.setSourceMethodName(sourceMethod); 1080 lr.setThrown(thrown); 1081 doLog(lr); 1082 } 1083 1084 1085 //========================================================================= 1086 // Start of convenience methods WITH className, methodName and bundle name. 1087 //========================================================================= 1088 1089 // Private support method for logging for "logrb" methods. 1090 // We fill in the logger name, resource bundle name, and 1091 // resource bundle and then call "void log(LogRecord)". doLog(LogRecord lr, String rbname)1092 private void doLog(LogRecord lr, String rbname) { 1093 lr.setLoggerName(name); 1094 if (rbname != null) { 1095 lr.setResourceBundleName(rbname); 1096 lr.setResourceBundle(findResourceBundle(rbname, false)); 1097 } 1098 log(lr); 1099 } 1100 1101 // Private support method for logging for "logrb" methods. doLog(LogRecord lr, ResourceBundle rb)1102 private void doLog(LogRecord lr, ResourceBundle rb) { 1103 lr.setLoggerName(name); 1104 if (rb != null) { 1105 lr.setResourceBundleName(rb.getBaseBundleName()); 1106 lr.setResourceBundle(rb); 1107 } 1108 log(lr); 1109 } 1110 1111 /** 1112 * Log a message, specifying source class, method, and resource bundle name 1113 * with no arguments. 1114 * <p> 1115 * If the logger is currently enabled for the given message 1116 * level then the given message is forwarded to all the 1117 * registered output Handler objects. 1118 * <p> 1119 * The msg string is localized using the named resource bundle. If the 1120 * resource bundle name is null, or an empty String or invalid 1121 * then the msg string is not localized. 1122 * <p> 1123 * @param level One of the message level identifiers, e.g., SEVERE 1124 * @param sourceClass name of class that issued the logging request 1125 * @param sourceMethod name of method that issued the logging request 1126 * @param bundleName name of resource bundle to localize msg, 1127 * can be null 1128 * @param msg The string message (or a key in the message catalog) 1129 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1130 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1131 * java.lang.Object...)} instead. 1132 */ 1133 @Deprecated logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg)1134 public void logrb(Level level, String sourceClass, String sourceMethod, 1135 String bundleName, String msg) { 1136 if (!isLoggable(level)) { 1137 return; 1138 } 1139 LogRecord lr = new LogRecord(level, msg); 1140 lr.setSourceClassName(sourceClass); 1141 lr.setSourceMethodName(sourceMethod); 1142 doLog(lr, bundleName); 1143 } 1144 1145 /** 1146 * Log a message, specifying source class, method, and resource bundle name, 1147 * with a single object parameter to the log message. 1148 * <p> 1149 * If the logger is currently enabled for the given message 1150 * level then a corresponding LogRecord is created and forwarded 1151 * to all the registered output Handler objects. 1152 * <p> 1153 * The msg string is localized using the named resource bundle. If the 1154 * resource bundle name is null, or an empty String or invalid 1155 * then the msg string is not localized. 1156 * <p> 1157 * @param level One of the message level identifiers, e.g., SEVERE 1158 * @param sourceClass name of class that issued the logging request 1159 * @param sourceMethod name of method that issued the logging request 1160 * @param bundleName name of resource bundle to localize msg, 1161 * can be null 1162 * @param msg The string message (or a key in the message catalog) 1163 * @param param1 Parameter to the log message. 1164 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1165 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1166 * java.lang.Object...)} instead 1167 */ 1168 @Deprecated logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Object param1)1169 public void logrb(Level level, String sourceClass, String sourceMethod, 1170 String bundleName, String msg, Object param1) { 1171 if (!isLoggable(level)) { 1172 return; 1173 } 1174 LogRecord lr = new LogRecord(level, msg); 1175 lr.setSourceClassName(sourceClass); 1176 lr.setSourceMethodName(sourceMethod); 1177 Object params[] = { param1 }; 1178 lr.setParameters(params); 1179 doLog(lr, bundleName); 1180 } 1181 1182 /** 1183 * Log a message, specifying source class, method, and resource bundle name, 1184 * with an array of object arguments. 1185 * <p> 1186 * If the logger is currently enabled for the given message 1187 * level then a corresponding LogRecord is created and forwarded 1188 * to all the registered output Handler objects. 1189 * <p> 1190 * The msg string is localized using the named resource bundle. If the 1191 * resource bundle name is null, or an empty String or invalid 1192 * then the msg string is not localized. 1193 * <p> 1194 * @param level One of the message level identifiers, e.g., SEVERE 1195 * @param sourceClass name of class that issued the logging request 1196 * @param sourceMethod name of method that issued the logging request 1197 * @param bundleName name of resource bundle to localize msg, 1198 * can be null. 1199 * @param msg The string message (or a key in the message catalog) 1200 * @param params Array of parameters to the message 1201 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1202 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1203 * java.lang.Object...)} instead. 1204 */ 1205 @Deprecated logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Object params[])1206 public void logrb(Level level, String sourceClass, String sourceMethod, 1207 String bundleName, String msg, Object params[]) { 1208 if (!isLoggable(level)) { 1209 return; 1210 } 1211 LogRecord lr = new LogRecord(level, msg); 1212 lr.setSourceClassName(sourceClass); 1213 lr.setSourceMethodName(sourceMethod); 1214 lr.setParameters(params); 1215 doLog(lr, bundleName); 1216 } 1217 1218 /** 1219 * Log a message, specifying source class, method, and resource bundle, 1220 * with an optional list of message parameters. 1221 * <p> 1222 * If the logger is currently enabled for the given message 1223 * level then a corresponding LogRecord is created and forwarded 1224 * to all the registered output Handler objects. 1225 * <p> 1226 * The {@code msg} string is localized using the given resource bundle. 1227 * If the resource bundle is {@code null}, then the {@code msg} string is not 1228 * localized. 1229 * <p> 1230 * @param level One of the message level identifiers, e.g., SEVERE 1231 * @param sourceClass Name of the class that issued the logging request 1232 * @param sourceMethod Name of the method that issued the logging request 1233 * @param bundle Resource bundle to localize {@code msg}, 1234 * can be {@code null}. 1235 * @param msg The string message (or a key in the message catalog) 1236 * @param params Parameters to the message (optional, may be none). 1237 * @since 1.8 1238 */ logrb(Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String msg, Object... params)1239 public void logrb(Level level, String sourceClass, String sourceMethod, 1240 ResourceBundle bundle, String msg, Object... params) { 1241 if (!isLoggable(level)) { 1242 return; 1243 } 1244 LogRecord lr = new LogRecord(level, msg); 1245 lr.setSourceClassName(sourceClass); 1246 lr.setSourceMethodName(sourceMethod); 1247 if (params != null && params.length != 0) { 1248 lr.setParameters(params); 1249 } 1250 doLog(lr, bundle); 1251 } 1252 1253 /** 1254 * Log a message, specifying source class, method, and resource bundle name, 1255 * with associated Throwable information. 1256 * <p> 1257 * If the logger is currently enabled for the given message 1258 * level then the given arguments are stored in a LogRecord 1259 * which is forwarded to all registered output handlers. 1260 * <p> 1261 * The msg string is localized using the named resource bundle. If the 1262 * resource bundle name is null, or an empty String or invalid 1263 * then the msg string is not localized. 1264 * <p> 1265 * Note that the thrown argument is stored in the LogRecord thrown 1266 * property, rather than the LogRecord parameters property. Thus it is 1267 * processed specially by output Formatters and is not treated 1268 * as a formatting parameter to the LogRecord message property. 1269 * <p> 1270 * @param level One of the message level identifiers, e.g., SEVERE 1271 * @param sourceClass name of class that issued the logging request 1272 * @param sourceMethod name of method that issued the logging request 1273 * @param bundleName name of resource bundle to localize msg, 1274 * can be null 1275 * @param msg The string message (or a key in the message catalog) 1276 * @param thrown Throwable associated with log message. 1277 * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, 1278 * java.lang.String, java.util.ResourceBundle, java.lang.String, 1279 * java.lang.Throwable)} instead. 1280 */ 1281 @Deprecated logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Throwable thrown)1282 public void logrb(Level level, String sourceClass, String sourceMethod, 1283 String bundleName, String msg, Throwable thrown) { 1284 if (!isLoggable(level)) { 1285 return; 1286 } 1287 LogRecord lr = new LogRecord(level, msg); 1288 lr.setSourceClassName(sourceClass); 1289 lr.setSourceMethodName(sourceMethod); 1290 lr.setThrown(thrown); 1291 doLog(lr, bundleName); 1292 } 1293 1294 /** 1295 * Log a message, specifying source class, method, and resource bundle, 1296 * with associated Throwable information. 1297 * <p> 1298 * If the logger is currently enabled for the given message 1299 * level then the given arguments are stored in a LogRecord 1300 * which is forwarded to all registered output handlers. 1301 * <p> 1302 * The {@code msg} string is localized using the given resource bundle. 1303 * If the resource bundle is {@code null}, then the {@code msg} string is not 1304 * localized. 1305 * <p> 1306 * Note that the thrown argument is stored in the LogRecord thrown 1307 * property, rather than the LogRecord parameters property. Thus it is 1308 * processed specially by output Formatters and is not treated 1309 * as a formatting parameter to the LogRecord message property. 1310 * <p> 1311 * @param level One of the message level identifiers, e.g., SEVERE 1312 * @param sourceClass Name of the class that issued the logging request 1313 * @param sourceMethod Name of the method that issued the logging request 1314 * @param bundle Resource bundle to localize {@code msg}, 1315 * can be {@code null} 1316 * @param msg The string message (or a key in the message catalog) 1317 * @param thrown Throwable associated with the log message. 1318 * @since 1.8 1319 */ logrb(Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String msg, Throwable thrown)1320 public void logrb(Level level, String sourceClass, String sourceMethod, 1321 ResourceBundle bundle, String msg, Throwable thrown) { 1322 if (!isLoggable(level)) { 1323 return; 1324 } 1325 LogRecord lr = new LogRecord(level, msg); 1326 lr.setSourceClassName(sourceClass); 1327 lr.setSourceMethodName(sourceMethod); 1328 lr.setThrown(thrown); 1329 doLog(lr, bundle); 1330 } 1331 1332 //====================================================================== 1333 // Start of convenience methods for logging method entries and returns. 1334 //====================================================================== 1335 1336 /** 1337 * Log a method entry. 1338 * <p> 1339 * This is a convenience method that can be used to log entry 1340 * to a method. A LogRecord with message "ENTRY", log level 1341 * FINER, and the given sourceMethod and sourceClass is logged. 1342 * <p> 1343 * @param sourceClass name of class that issued the logging request 1344 * @param sourceMethod name of method that is being entered 1345 */ entering(String sourceClass, String sourceMethod)1346 public void entering(String sourceClass, String sourceMethod) { 1347 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); 1348 } 1349 1350 /** 1351 * Log a method entry, with one parameter. 1352 * <p> 1353 * This is a convenience method that can be used to log entry 1354 * to a method. A LogRecord with message "ENTRY {0}", log level 1355 * FINER, and the given sourceMethod, sourceClass, and parameter 1356 * is logged. 1357 * <p> 1358 * @param sourceClass name of class that issued the logging request 1359 * @param sourceMethod name of method that is being entered 1360 * @param param1 parameter to the method being entered 1361 */ entering(String sourceClass, String sourceMethod, Object param1)1362 public void entering(String sourceClass, String sourceMethod, Object param1) { 1363 logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1); 1364 } 1365 1366 /** 1367 * Log a method entry, with an array of parameters. 1368 * <p> 1369 * This is a convenience method that can be used to log entry 1370 * to a method. A LogRecord with message "ENTRY" (followed by a 1371 * format {N} indicator for each entry in the parameter array), 1372 * log level FINER, and the given sourceMethod, sourceClass, and 1373 * parameters is logged. 1374 * <p> 1375 * @param sourceClass name of class that issued the logging request 1376 * @param sourceMethod name of method that is being entered 1377 * @param params array of parameters to the method being entered 1378 */ entering(String sourceClass, String sourceMethod, Object params[])1379 public void entering(String sourceClass, String sourceMethod, Object params[]) { 1380 String msg = "ENTRY"; 1381 if (params == null ) { 1382 logp(Level.FINER, sourceClass, sourceMethod, msg); 1383 return; 1384 } 1385 if (!isLoggable(Level.FINER)) return; 1386 for (int i = 0; i < params.length; i++) { 1387 msg = msg + " {" + i + "}"; 1388 } 1389 logp(Level.FINER, sourceClass, sourceMethod, msg, params); 1390 } 1391 1392 /** 1393 * Log a method return. 1394 * <p> 1395 * This is a convenience method that can be used to log returning 1396 * from a method. A LogRecord with message "RETURN", log level 1397 * FINER, and the given sourceMethod and sourceClass is logged. 1398 * <p> 1399 * @param sourceClass name of class that issued the logging request 1400 * @param sourceMethod name of the method 1401 */ exiting(String sourceClass, String sourceMethod)1402 public void exiting(String sourceClass, String sourceMethod) { 1403 logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); 1404 } 1405 1406 1407 /** 1408 * Log a method return, with result object. 1409 * <p> 1410 * This is a convenience method that can be used to log returning 1411 * from a method. A LogRecord with message "RETURN {0}", log level 1412 * FINER, and the gives sourceMethod, sourceClass, and result 1413 * object is logged. 1414 * <p> 1415 * @param sourceClass name of class that issued the logging request 1416 * @param sourceMethod name of the method 1417 * @param result Object that is being returned 1418 */ exiting(String sourceClass, String sourceMethod, Object result)1419 public void exiting(String sourceClass, String sourceMethod, Object result) { 1420 logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); 1421 } 1422 1423 /** 1424 * Log throwing an exception. 1425 * <p> 1426 * This is a convenience method to log that a method is 1427 * terminating by throwing an exception. The logging is done 1428 * using the FINER level. 1429 * <p> 1430 * If the logger is currently enabled for the given message 1431 * level then the given arguments are stored in a LogRecord 1432 * which is forwarded to all registered output handlers. The 1433 * LogRecord's message is set to "THROW". 1434 * <p> 1435 * Note that the thrown argument is stored in the LogRecord thrown 1436 * property, rather than the LogRecord parameters property. Thus it is 1437 * processed specially by output Formatters and is not treated 1438 * as a formatting parameter to the LogRecord message property. 1439 * <p> 1440 * @param sourceClass name of class that issued the logging request 1441 * @param sourceMethod name of the method. 1442 * @param thrown The Throwable that is being thrown. 1443 */ throwing(String sourceClass, String sourceMethod, Throwable thrown)1444 public void throwing(String sourceClass, String sourceMethod, Throwable thrown) { 1445 if (!isLoggable(Level.FINER)) { 1446 return; 1447 } 1448 LogRecord lr = new LogRecord(Level.FINER, "THROW"); 1449 lr.setSourceClassName(sourceClass); 1450 lr.setSourceMethodName(sourceMethod); 1451 lr.setThrown(thrown); 1452 doLog(lr); 1453 } 1454 1455 //======================================================================= 1456 // Start of simple convenience methods using level names as method names 1457 //======================================================================= 1458 1459 /** 1460 * Log a SEVERE message. 1461 * <p> 1462 * If the logger is currently enabled for the SEVERE message 1463 * level then the given message is forwarded to all the 1464 * registered output Handler objects. 1465 * <p> 1466 * @param msg The string message (or a key in the message catalog) 1467 */ severe(String msg)1468 public void severe(String msg) { 1469 log(Level.SEVERE, msg); 1470 } 1471 1472 /** 1473 * Log a WARNING message. 1474 * <p> 1475 * If the logger is currently enabled for the WARNING message 1476 * level then the given message is forwarded to all the 1477 * registered output Handler objects. 1478 * <p> 1479 * @param msg The string message (or a key in the message catalog) 1480 */ warning(String msg)1481 public void warning(String msg) { 1482 log(Level.WARNING, msg); 1483 } 1484 1485 /** 1486 * Log an INFO message. 1487 * <p> 1488 * If the logger is currently enabled for the INFO message 1489 * level then the given message is forwarded to all the 1490 * registered output Handler objects. 1491 * <p> 1492 * @param msg The string message (or a key in the message catalog) 1493 */ info(String msg)1494 public void info(String msg) { 1495 log(Level.INFO, msg); 1496 } 1497 1498 /** 1499 * Log a CONFIG message. 1500 * <p> 1501 * If the logger is currently enabled for the CONFIG message 1502 * level then the given message is forwarded to all the 1503 * registered output Handler objects. 1504 * <p> 1505 * @param msg The string message (or a key in the message catalog) 1506 */ config(String msg)1507 public void config(String msg) { 1508 log(Level.CONFIG, msg); 1509 } 1510 1511 /** 1512 * Log a FINE message. 1513 * <p> 1514 * If the logger is currently enabled for the FINE message 1515 * level then the given message is forwarded to all the 1516 * registered output Handler objects. 1517 * <p> 1518 * @param msg The string message (or a key in the message catalog) 1519 */ fine(String msg)1520 public void fine(String msg) { 1521 log(Level.FINE, msg); 1522 } 1523 1524 /** 1525 * Log a FINER message. 1526 * <p> 1527 * If the logger is currently enabled for the FINER message 1528 * level then the given message is forwarded to all the 1529 * registered output Handler objects. 1530 * <p> 1531 * @param msg The string message (or a key in the message catalog) 1532 */ finer(String msg)1533 public void finer(String msg) { 1534 log(Level.FINER, msg); 1535 } 1536 1537 /** 1538 * Log a FINEST message. 1539 * <p> 1540 * If the logger is currently enabled for the FINEST message 1541 * level then the given message is forwarded to all the 1542 * registered output Handler objects. 1543 * <p> 1544 * @param msg The string message (or a key in the message catalog) 1545 */ finest(String msg)1546 public void finest(String msg) { 1547 log(Level.FINEST, msg); 1548 } 1549 1550 //======================================================================= 1551 // Start of simple convenience methods using level names as method names 1552 // and use Supplier<String> 1553 //======================================================================= 1554 1555 /** 1556 * Log a SEVERE message, which is only to be constructed if the logging 1557 * level is such that the message will actually be logged. 1558 * <p> 1559 * If the logger is currently enabled for the SEVERE message 1560 * level then the message is constructed by invoking the provided 1561 * supplier function and forwarded to all the registered output 1562 * Handler objects. 1563 * <p> 1564 * @param msgSupplier A function, which when called, produces the 1565 * desired log message 1566 * @since 1.8 1567 */ severe(Supplier<String> msgSupplier)1568 public void severe(Supplier<String> msgSupplier) { 1569 log(Level.SEVERE, msgSupplier); 1570 } 1571 1572 /** 1573 * Log a WARNING message, which is only to be constructed if the logging 1574 * level is such that the message will actually be logged. 1575 * <p> 1576 * If the logger is currently enabled for the WARNING message 1577 * level then the message is constructed by invoking the provided 1578 * supplier function and forwarded to all the registered output 1579 * Handler objects. 1580 * <p> 1581 * @param msgSupplier A function, which when called, produces the 1582 * desired log message 1583 * @since 1.8 1584 */ warning(Supplier<String> msgSupplier)1585 public void warning(Supplier<String> msgSupplier) { 1586 log(Level.WARNING, msgSupplier); 1587 } 1588 1589 /** 1590 * Log a INFO message, which is only to be constructed if the logging 1591 * level is such that the message will actually be logged. 1592 * <p> 1593 * If the logger is currently enabled for the INFO message 1594 * level then the message is constructed by invoking the provided 1595 * supplier function and forwarded to all the registered output 1596 * Handler objects. 1597 * <p> 1598 * @param msgSupplier A function, which when called, produces the 1599 * desired log message 1600 * @since 1.8 1601 */ info(Supplier<String> msgSupplier)1602 public void info(Supplier<String> msgSupplier) { 1603 log(Level.INFO, msgSupplier); 1604 } 1605 1606 /** 1607 * Log a CONFIG message, which is only to be constructed if the logging 1608 * level is such that the message will actually be logged. 1609 * <p> 1610 * If the logger is currently enabled for the CONFIG message 1611 * level then the message is constructed by invoking the provided 1612 * supplier function and forwarded to all the registered output 1613 * Handler objects. 1614 * <p> 1615 * @param msgSupplier A function, which when called, produces the 1616 * desired log message 1617 * @since 1.8 1618 */ config(Supplier<String> msgSupplier)1619 public void config(Supplier<String> msgSupplier) { 1620 log(Level.CONFIG, msgSupplier); 1621 } 1622 1623 /** 1624 * Log a FINE message, which is only to be constructed if the logging 1625 * level is such that the message will actually be logged. 1626 * <p> 1627 * If the logger is currently enabled for the FINE message 1628 * level then the message is constructed by invoking the provided 1629 * supplier function and forwarded to all the registered output 1630 * Handler objects. 1631 * <p> 1632 * @param msgSupplier A function, which when called, produces the 1633 * desired log message 1634 * @since 1.8 1635 */ fine(Supplier<String> msgSupplier)1636 public void fine(Supplier<String> msgSupplier) { 1637 log(Level.FINE, msgSupplier); 1638 } 1639 1640 /** 1641 * Log a FINER message, which is only to be constructed if the logging 1642 * level is such that the message will actually be logged. 1643 * <p> 1644 * If the logger is currently enabled for the FINER message 1645 * level then the message is constructed by invoking the provided 1646 * supplier function and forwarded to all the registered output 1647 * Handler objects. 1648 * <p> 1649 * @param msgSupplier A function, which when called, produces the 1650 * desired log message 1651 * @since 1.8 1652 */ finer(Supplier<String> msgSupplier)1653 public void finer(Supplier<String> msgSupplier) { 1654 log(Level.FINER, msgSupplier); 1655 } 1656 1657 /** 1658 * Log a FINEST message, which is only to be constructed if the logging 1659 * level is such that the message will actually be logged. 1660 * <p> 1661 * If the logger is currently enabled for the FINEST message 1662 * level then the message is constructed by invoking the provided 1663 * supplier function and forwarded to all the registered output 1664 * Handler objects. 1665 * <p> 1666 * @param msgSupplier A function, which when called, produces the 1667 * desired log message 1668 * @since 1.8 1669 */ finest(Supplier<String> msgSupplier)1670 public void finest(Supplier<String> msgSupplier) { 1671 log(Level.FINEST, msgSupplier); 1672 } 1673 1674 //================================================================ 1675 // End of convenience methods 1676 //================================================================ 1677 1678 /** 1679 * Set the log level specifying which message levels will be 1680 * logged by this logger. Message levels lower than this 1681 * value will be discarded. The level value Level.OFF 1682 * can be used to turn off logging. 1683 * <p> 1684 * If the new level is null, it means that this node should 1685 * inherit its level from its nearest ancestor with a specific 1686 * (non-null) level value. 1687 * 1688 * @param newLevel the new value for the log level (may be null) 1689 * @throws SecurityException if a security manager exists, 1690 * this logger is not anonymous, and the caller 1691 * does not have LoggingPermission("control"). 1692 */ setLevel(Level newLevel)1693 public void setLevel(Level newLevel) throws SecurityException { 1694 checkPermission(); 1695 synchronized (treeLock) { 1696 levelObject = newLevel; 1697 updateEffectiveLevel(); 1698 } 1699 } 1700 isLevelInitialized()1701 final boolean isLevelInitialized() { 1702 return levelObject != null; 1703 } 1704 1705 /** 1706 * Get the log Level that has been specified for this Logger. 1707 * The result may be null, which means that this logger's 1708 * effective level will be inherited from its parent. 1709 * 1710 * @return this Logger's level 1711 */ getLevel()1712 public Level getLevel() { 1713 return levelObject; 1714 } 1715 1716 /** 1717 * Check if a message of the given level would actually be logged 1718 * by this logger. This check is based on the Loggers effective level, 1719 * which may be inherited from its parent. 1720 * 1721 * @param level a message logging level 1722 * @return true if the given message level is currently being logged. 1723 */ isLoggable(Level level)1724 public boolean isLoggable(Level level) { 1725 if (level.intValue() < levelValue || levelValue == offValue) { 1726 return false; 1727 } 1728 return true; 1729 } 1730 1731 /** 1732 * Get the name for this logger. 1733 * @return logger name. Will be null for anonymous Loggers. 1734 */ getName()1735 public String getName() { 1736 return name; 1737 } 1738 1739 /** 1740 * Add a log Handler to receive logging messages. 1741 * <p> 1742 * By default, Loggers also send their output to their parent logger. 1743 * Typically the root Logger is configured with a set of Handlers 1744 * that essentially act as default handlers for all loggers. 1745 * 1746 * @param handler a logging Handler 1747 * @throws SecurityException if a security manager exists, 1748 * this logger is not anonymous, and the caller 1749 * does not have LoggingPermission("control"). 1750 */ addHandler(Handler handler)1751 public void addHandler(Handler handler) throws SecurityException { 1752 // Check for null handler 1753 handler.getClass(); 1754 checkPermission(); 1755 handlers.add(handler); 1756 } 1757 1758 /** 1759 * Remove a log Handler. 1760 * <P> 1761 * Returns silently if the given Handler is not found or is null 1762 * 1763 * @param handler a logging Handler 1764 * @throws SecurityException if a security manager exists, 1765 * this logger is not anonymous, and the caller 1766 * does not have LoggingPermission("control"). 1767 */ removeHandler(Handler handler)1768 public void removeHandler(Handler handler) throws SecurityException { 1769 checkPermission(); 1770 if (handler == null) { 1771 return; 1772 } 1773 handlers.remove(handler); 1774 } 1775 1776 /** 1777 * Get the Handlers associated with this logger. 1778 * <p> 1779 * @return an array of all registered Handlers 1780 */ getHandlers()1781 public Handler[] getHandlers() { 1782 return accessCheckedHandlers(); 1783 } 1784 1785 // This method should ideally be marked final - but unfortunately 1786 // it needs to be overridden by LogManager.RootLogger accessCheckedHandlers()1787 Handler[] accessCheckedHandlers() { 1788 return handlers.toArray(emptyHandlers); 1789 } 1790 1791 /** 1792 * Specify whether or not this logger should send its output 1793 * to its parent Logger. This means that any LogRecords will 1794 * also be written to the parent's Handlers, and potentially 1795 * to its parent, recursively up the namespace. 1796 * 1797 * @param useParentHandlers true if output is to be sent to the 1798 * logger's parent. 1799 * @throws SecurityException if a security manager exists, 1800 * this logger is not anonymous, and the caller 1801 * does not have LoggingPermission("control"). 1802 */ setUseParentHandlers(boolean useParentHandlers)1803 public void setUseParentHandlers(boolean useParentHandlers) { 1804 checkPermission(); 1805 this.useParentHandlers = useParentHandlers; 1806 } 1807 1808 /** 1809 * Discover whether or not this logger is sending its output 1810 * to its parent logger. 1811 * 1812 * @return true if output is to be sent to the logger's parent 1813 */ getUseParentHandlers()1814 public boolean getUseParentHandlers() { 1815 return useParentHandlers; 1816 } 1817 findSystemResourceBundle(final Locale locale)1818 private static ResourceBundle findSystemResourceBundle(final Locale locale) { 1819 // the resource bundle is in a restricted package 1820 return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() { 1821 @Override 1822 public ResourceBundle run() { 1823 try { 1824 return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, 1825 locale, 1826 ClassLoader.getSystemClassLoader()); 1827 } catch (MissingResourceException e) { 1828 throw new InternalError(e.toString()); 1829 } 1830 } 1831 }); 1832 } 1833 1834 /** 1835 * Private utility method to map a resource bundle name to an 1836 * actual resource bundle, using a simple one-entry cache. 1837 * Returns null for a null name. 1838 * May also return null if we can't find the resource bundle and 1839 * there is no suitable previous cached value. 1840 * 1841 * @param name the ResourceBundle to locate 1842 * @param userCallersClassLoader if true search using the caller's ClassLoader 1843 * @return ResourceBundle specified by name or null if not found 1844 */ 1845 private synchronized ResourceBundle findResourceBundle(String name, 1846 boolean useCallersClassLoader) { 1847 // For all lookups, we first check the thread context class loader 1848 // if it is set. If not, we use the system classloader. If we 1849 // still haven't found it we use the callersClassLoaderRef if it 1850 // is set and useCallersClassLoader is true. We set 1851 // callersClassLoaderRef initially upon creating the logger with a 1852 // non-null resource bundle name. 1853 1854 // Return a null bundle for a null name. 1855 if (name == null) { 1856 return null; 1857 } 1858 1859 Locale currentLocale = Locale.getDefault(); 1860 final LoggerBundle lb = loggerBundle; 1861 1862 // Normally we should hit on our simple one entry cache. 1863 if (lb.userBundle != null && 1864 name.equals(lb.resourceBundleName)) { 1865 return lb.userBundle; 1866 } else if (catalog != null && currentLocale.equals(catalogLocale) 1867 && name.equals(catalogName)) { 1868 return catalog; 1869 } 1870 1871 if (name.equals(SYSTEM_LOGGER_RB_NAME)) { 1872 catalog = findSystemResourceBundle(currentLocale); 1873 catalogName = name; 1874 catalogLocale = currentLocale; 1875 return catalog; 1876 } 1877 1878 // Use the thread's context ClassLoader. If there isn't one, use the 1879 // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}. 1880 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 1881 if (cl == null) { 1882 cl = ClassLoader.getSystemClassLoader(); 1883 } 1884 try { 1885 catalog = ResourceBundle.getBundle(name, currentLocale, cl); 1886 catalogName = name; 1887 catalogLocale = currentLocale; 1888 return catalog; 1889 } catch (MissingResourceException ex) { 1890 // We can't find the ResourceBundle in the default 1891 // ClassLoader. Drop through. 1892 } 1893 1894 if (useCallersClassLoader) { 1895 // Try with the caller's ClassLoader 1896 ClassLoader callersClassLoader = getCallersClassLoader(); 1897 if (callersClassLoader == null || callersClassLoader == cl) { 1898 return null; 1899 } 1900 1901 try { 1902 catalog = ResourceBundle.getBundle(name, currentLocale, 1903 callersClassLoader); 1904 catalogName = name; 1905 catalogLocale = currentLocale; 1906 return catalog; 1907 } catch (MissingResourceException ex) { 1908 return null; // no luck 1909 } 1910 } else { 1911 return null; 1912 } 1913 } 1914 1915 // Private utility method to initialize our one entry 1916 // resource bundle name cache and the callers ClassLoader 1917 // Note: for consistency reasons, we are careful to check 1918 // that a suitable ResourceBundle exists before setting the 1919 // resourceBundleName field. 1920 // Synchronized to prevent races in setting the fields. 1921 private synchronized void setupResourceInfo(String name, 1922 Class<?> callersClass) { 1923 final LoggerBundle lb = loggerBundle; 1924 if (lb.resourceBundleName != null) { 1925 // this Logger already has a ResourceBundle 1926 1927 if (lb.resourceBundleName.equals(name)) { 1928 // the names match so there is nothing more to do 1929 return; 1930 } 1931 1932 // cannot change ResourceBundles once they are set 1933 throw new IllegalArgumentException( 1934 lb.resourceBundleName + " != " + name); 1935 } 1936 1937 if (name == null) { 1938 return; 1939 } 1940 1941 setCallersClassLoaderRef(callersClass); 1942 if (isSystemLogger && getCallersClassLoader() != null) { 1943 checkPermission(); 1944 } 1945 if (findResourceBundle(name, true) == null) { 1946 // We've failed to find an expected ResourceBundle. 1947 // unset the caller's ClassLoader since we were unable to find the 1948 // the bundle using it 1949 this.callersClassLoaderRef = null; 1950 throw new MissingResourceException("Can't find " + name + " bundle", 1951 name, ""); 1952 } 1953 1954 // if lb.userBundle is not null we won't reach this line. 1955 assert lb.userBundle == null; 1956 loggerBundle = LoggerBundle.get(name, null); 1957 } 1958 1959 /** 1960 * Sets a resource bundle on this logger. 1961 * All messages will be logged using the given resource bundle for its 1962 * specific {@linkplain ResourceBundle#getLocale locale}. 1963 * @param bundle The resource bundle that this logger shall use. 1964 * @throws NullPointerException if the given bundle is {@code null}. 1965 * @throws IllegalArgumentException if the given bundle doesn't have a 1966 * {@linkplain ResourceBundle#getBaseBundleName base name}, 1967 * or if this logger already has a resource bundle set but 1968 * the given bundle has a different base name. 1969 * @throws SecurityException if a security manager exists, 1970 * this logger is not anonymous, and the caller 1971 * does not have LoggingPermission("control"). 1972 * @since 1.8 1973 */ 1974 public void setResourceBundle(ResourceBundle bundle) { 1975 checkPermission(); 1976 1977 // Will throw NPE if bundle is null. 1978 final String baseName = bundle.getBaseBundleName(); 1979 1980 // bundle must have a name 1981 if (baseName == null || baseName.isEmpty()) { 1982 throw new IllegalArgumentException("resource bundle must have a name"); 1983 } 1984 1985 synchronized (this) { 1986 LoggerBundle lb = loggerBundle; 1987 final boolean canReplaceResourceBundle = lb.resourceBundleName == null 1988 || lb.resourceBundleName.equals(baseName); 1989 1990 if (!canReplaceResourceBundle) { 1991 throw new IllegalArgumentException("can't replace resource bundle"); 1992 } 1993 1994 1995 loggerBundle = LoggerBundle.get(baseName, bundle); 1996 } 1997 } 1998 1999 /** 2000 * Return the parent for this Logger. 2001 * <p> 2002 * This method returns the nearest extant parent in the namespace. 2003 * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b" 2004 * has been created but no logger "a.b.c" exists, then a call of 2005 * getParent on the Logger "a.b.c.d" will return the Logger "a.b". 2006 * <p> 2007 * The result will be null if it is called on the root Logger 2008 * in the namespace. 2009 * 2010 * @return nearest existing parent Logger 2011 */ 2012 public Logger getParent() { 2013 // Note: this used to be synchronized on treeLock. However, this only 2014 // provided memory semantics, as there was no guarantee that the caller 2015 // would synchronize on treeLock (in fact, there is no way for external 2016 // callers to so synchronize). Therefore, we have made parent volatile 2017 // instead. 2018 return parent; 2019 } 2020 2021 /** 2022 * Set the parent for this Logger. This method is used by 2023 * the LogManager to update a Logger when the namespace changes. 2024 * <p> 2025 * It should not be called from application code. 2026 * <p> 2027 * @param parent the new parent logger 2028 * @throws SecurityException if a security manager exists and if 2029 * the caller does not have LoggingPermission("control"). 2030 */ 2031 public void setParent(Logger parent) { 2032 if (parent == null) { 2033 throw new NullPointerException(); 2034 } 2035 2036 // check permission for all loggers, including anonymous loggers 2037 if (manager == null) { 2038 manager = LogManager.getLogManager(); 2039 } 2040 manager.checkPermission(); 2041 2042 doSetParent(parent); 2043 } 2044 2045 // Private method to do the work for parenting a child 2046 // Logger onto a parent logger. 2047 private void doSetParent(Logger newParent) { 2048 2049 // System.err.println("doSetParent \"" + getName() + "\" \"" 2050 // + newParent.getName() + "\""); 2051 2052 synchronized (treeLock) { 2053 2054 // Remove ourself from any previous parent. 2055 LogManager.LoggerWeakRef ref = null; 2056 if (parent != null) { 2057 // assert parent.kids != null; 2058 for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) { 2059 ref = iter.next(); 2060 Logger kid = ref.get(); 2061 if (kid == this) { 2062 // ref is used down below to complete the reparenting 2063 iter.remove(); 2064 break; 2065 } else { 2066 ref = null; 2067 } 2068 } 2069 // We have now removed ourself from our parents' kids. 2070 } 2071 2072 // Set our new parent. 2073 parent = newParent; 2074 if (parent.kids == null) { 2075 parent.kids = new ArrayList<>(2); 2076 } 2077 if (ref == null) { 2078 // we didn't have a previous parent 2079 ref = manager.new LoggerWeakRef(this); 2080 } 2081 ref.setParentRef(new WeakReference<>(parent)); 2082 parent.kids.add(ref); 2083 2084 // As a result of the reparenting, the effective level 2085 // may have changed for us and our children. 2086 updateEffectiveLevel(); 2087 2088 } 2089 } 2090 2091 // Package-level method. 2092 // Remove the weak reference for the specified child Logger from the 2093 // kid list. We should only be called from LoggerWeakRef.dispose(). 2094 final void removeChildLogger(LogManager.LoggerWeakRef child) { 2095 synchronized (treeLock) { 2096 for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) { 2097 LogManager.LoggerWeakRef ref = iter.next(); 2098 if (ref == child) { 2099 iter.remove(); 2100 return; 2101 } 2102 } 2103 } 2104 } 2105 2106 // Recalculate the effective level for this node and 2107 // recursively for our children. 2108 2109 private void updateEffectiveLevel() { 2110 // assert Thread.holdsLock(treeLock); 2111 2112 // Figure out our current effective level. 2113 int newLevelValue; 2114 if (levelObject != null) { 2115 newLevelValue = levelObject.intValue(); 2116 } else { 2117 if (parent != null) { 2118 newLevelValue = parent.levelValue; 2119 } else { 2120 // This may happen during initialization. 2121 newLevelValue = Level.INFO.intValue(); 2122 } 2123 } 2124 2125 // If our effective value hasn't changed, we're done. 2126 if (levelValue == newLevelValue) { 2127 return; 2128 } 2129 2130 levelValue = newLevelValue; 2131 2132 // System.err.println("effective level: \"" + getName() + "\" := " + level); 2133 2134 // Recursively update the level on each of our kids. 2135 if (kids != null) { 2136 for (int i = 0; i < kids.size(); i++) { 2137 LogManager.LoggerWeakRef ref = kids.get(i); 2138 Logger kid = ref.get(); 2139 if (kid != null) { 2140 kid.updateEffectiveLevel(); 2141 } 2142 } 2143 } 2144 } 2145 2146 2147 // Private method to get the potentially inherited 2148 // resource bundle and resource bundle name for this Logger. 2149 // This method never returns null. 2150 private LoggerBundle getEffectiveLoggerBundle() { 2151 final LoggerBundle lb = loggerBundle; 2152 if (lb.isSystemBundle()) { 2153 return SYSTEM_BUNDLE; 2154 } 2155 2156 // first take care of this logger 2157 final ResourceBundle b = getResourceBundle(); 2158 if (b != null && b == lb.userBundle) { 2159 return lb; 2160 } else if (b != null) { 2161 // either lb.userBundle is null or getResourceBundle() is 2162 // overriden 2163 final String rbName = getResourceBundleName(); 2164 return LoggerBundle.get(rbName, b); 2165 } 2166 2167 // no resource bundle was specified on this logger, look up the 2168 // parent stack. 2169 Logger target = this.parent; 2170 while (target != null) { 2171 final LoggerBundle trb = target.loggerBundle; 2172 if (trb.isSystemBundle()) { 2173 return SYSTEM_BUNDLE; 2174 } 2175 if (trb.userBundle != null) { 2176 return trb; 2177 } 2178 final String rbName = isSystemLogger 2179 // ancestor of a system logger is expected to be a system logger. 2180 // ignore resource bundle name if it's not. 2181 ? (target.isSystemLogger ? trb.resourceBundleName : null) 2182 : target.getResourceBundleName(); 2183 if (rbName != null) { 2184 return LoggerBundle.get(rbName, 2185 findResourceBundle(rbName, true)); 2186 } 2187 target = isSystemLogger ? target.parent : target.getParent(); 2188 } 2189 return NO_RESOURCE_BUNDLE; 2190 } 2191 2192 } 2193