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