< prev index next >

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

Print this page




  23  * questions.
  24  */
  25 
  26 
  27 package java.util.logging;
  28 
  29 import java.lang.ref.WeakReference;
  30 import java.lang.reflect.Module;
  31 import java.security.AccessController;
  32 import java.security.PrivilegedAction;
  33 import java.util.ArrayList;
  34 import java.util.Iterator;
  35 import java.util.Locale;
  36 import java.util.MissingResourceException;
  37 import java.util.Objects;
  38 import java.util.ResourceBundle;
  39 import java.util.concurrent.CopyOnWriteArrayList;
  40 import java.util.function.Supplier;
  41 import sun.reflect.CallerSensitive;
  42 import sun.reflect.Reflection;

  43 
  44 /**
  45  * A Logger object is used to log messages for a specific
  46  * system or application component.  Loggers are normally named,
  47  * using a hierarchical dot-separated namespace.  Logger names
  48  * can be arbitrary strings, but they should normally be based on
  49  * the package name or class name of the logged component, such
  50  * as java.net or javax.swing.  In addition it is possible to create
  51  * "anonymous" Loggers that are not stored in the Logger namespace.
  52  * <p>
  53  * Logger objects may be obtained by calls on one of the getLogger
  54  * factory methods.  These will either create a new Logger or
  55  * return a suitable existing Logger. It is important to note that
  56  * the Logger returned by one of the {@code getLogger} factory methods
  57  * may be garbage collected at any time if a strong reference to the
  58  * Logger is not kept.
  59  * <p>
  60  * Logging messages will be forwarded to registered Handler
  61  * objects, which can forward the messages to a variety of
  62  * destinations, including consoles, files, OS logs, etc.


 362      * Protected method to construct a logger for a named subsystem.
 363      * <p>
 364      * The logger will be initially configured with a null Level
 365      * and with useParentHandlers set to true.
 366      *
 367      * @param   name    A name for the logger.  This should
 368      *                          be a dot-separated name and should normally
 369      *                          be based on the package name or class name
 370      *                          of the subsystem, such as java.net
 371      *                          or javax.swing.  It may be null for anonymous Loggers.
 372      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
 373      *                          messages for this logger.  May be null if none
 374      *                          of the messages require localization.
 375      * @throws MissingResourceException if the resourceBundleName is non-null and
 376      *             no corresponding resource can be found.
 377      */
 378     protected Logger(String name, String resourceBundleName) {
 379         this(name, resourceBundleName, null, LogManager.getLogManager(), false);
 380     }
 381 
 382     Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager, boolean isSystemLogger) {

 383         this.manager = manager;
 384         this.isSystemLogger = isSystemLogger;
 385         setupResourceInfo(resourceBundleName, caller);
 386         this.name = name;
 387         levelValue = Level.INFO.intValue();
 388     }
 389 
 390     private void setCallerModuleRef(Class<?> caller) {
 391         Module callerModule = ((caller != null)
 392                                         ? caller.getModule()
 393                                         : null);
 394         if (callerModule != null) {
 395             this.callerModuleRef = new WeakReference<>(callerModule);
 396         }
 397     }
 398 
 399     private Module getCallerModule() {
 400         return (callerModuleRef != null)
 401                 ? callerModuleRef.get()
 402                 : null;
 403     }
 404 
 405     // This constructor is used only to create the global Logger.
 406     // It is needed to break a cyclic dependence between the LogManager
 407     // and Logger static initializers causing deadlocks.
 408     private Logger(String name) {
 409         // The manager field is not initialized here.
 410         this.name = name;
 411         this.isSystemLogger = true;
 412         levelValue = Level.INFO.intValue();
 413     }


 601         // We have to set the callers ClassLoader here in case demandLogger
 602         // above found a previously created Logger.  This can happen, for
 603         // example, if Logger.getLogger(name) is called and subsequently
 604         // Logger.getLogger(name, resourceBundleName) is called.  In this case
 605         // we won't necessarily have the correct classloader saved away, so
 606         // we need to set it here, too.
 607 
 608         result.setupResourceInfo(resourceBundleName, callerClass);
 609         return result;
 610     }
 611 
 612     // package-private
 613     // Add a platform logger to the system context.
 614     // i.e. caller of sun.util.logging.PlatformLogger.getLogger
 615     static Logger getPlatformLogger(String name) {
 616         LogManager manager = LogManager.getLogManager();
 617 
 618         // all loggers in the system context will default to
 619         // the system logger's resource bundle - therefore the caller won't
 620         // be needed and can be null.
 621         Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME, null);
 622         return result;
 623     }
 624 
 625     /**
 626      * Create an anonymous Logger.  The newly created Logger is not
 627      * registered in the LogManager namespace.  There will be no
 628      * access checks on updates to the logger.
 629      * <p>
 630      * This factory method is primarily intended for use from applets.
 631      * Because the resulting Logger is anonymous it can be kept private
 632      * by the creating class.  This removes the need for normal security
 633      * checks, which in turn allows untrusted applet code to update
 634      * the control state of the Logger.  For example an applet can do
 635      * a setLevel or an addHandler on an anonymous Logger.
 636      * <p>
 637      * Even although the new logger is anonymous, it is configured
 638      * to have the root logger ("") as its parent.  This means that
 639      * by default it inherits its effective level and handlers
 640      * from the root logger. Changing its parent via the
 641      * {@link #setParent(java.util.logging.Logger) setParent} method


 664      * by default it inherits its effective level and handlers
 665      * from the root logger.  Changing its parent via the
 666      * {@link #setParent(java.util.logging.Logger) setParent} method
 667      * will still require the security permission specified by that method.
 668      *
 669      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
 670      *                          messages for this logger.
 671      *          May be null if none of the messages require localization.
 672      * @return a newly created private Logger
 673      * @throws MissingResourceException if the resourceBundleName is non-null and
 674      *             no corresponding resource can be found.
 675      */
 676 
 677     // Synchronization is not required here. All synchronization for
 678     // adding a new anonymous Logger object is handled by doSetParent().
 679     @CallerSensitive
 680     public static Logger getAnonymousLogger(String resourceBundleName) {
 681         LogManager manager = LogManager.getLogManager();
 682         // cleanup some Loggers that have been GC'ed
 683         manager.drainLoggerRefQueueBounded();


 684         Logger result = new Logger(null, resourceBundleName,
 685                                    Reflection.getCallerClass(), manager, false);
 686         result.anonymous = true;
 687         Logger root = manager.getLogger("");
 688         result.doSetParent(root);
 689         return result;
 690     }
 691 
 692     /**
 693      * Retrieve the localization resource bundle for this
 694      * logger.
 695      * This method will return a {@code ResourceBundle} that was either
 696      * set by the {@link
 697      * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or
 698      * <a href="#ResourceBundleMapping">mapped from the
 699      * the resource bundle name</a> set via the {@link
 700      * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory
 701      * method for the current default locale.
 702      * <br>Note that if the result is {@code null}, then the Logger will use a resource
 703      * bundle or resource bundle name inherited from its parent.
 704      *
 705      * @return localization bundle (may be {@code null})


2029                 }
2030             }
2031         } else {
2032             // we should have:
2033             //  useCallersModule && callerModule != null && callerModule.isNamed();
2034             // Try with the caller's module
2035             try {
2036                 // Use the caller's module
2037                 PrivilegedAction<ResourceBundle> pa = () ->
2038                     ResourceBundle.getBundle(name, currentLocale, callerModule);
2039                 catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION);
2040                 catalogName = name;
2041                 catalogLocale = currentLocale;
2042                 return catalog;
2043             } catch (MissingResourceException ex) {
2044                 return null; // no luck
2045             }
2046         }
2047     }
2048 





2049     // Private utility method to initialize our one entry
2050     // resource bundle name cache and the callers Module
2051     // Note: for consistency reasons, we are careful to check
2052     // that a suitable ResourceBundle exists before setting the
2053     // resourceBundleName field.
2054     // Synchronized to prevent races in setting the fields.
2055     private synchronized void setupResourceInfo(String name,
2056                                                 Class<?> callerClass) {
2057         final LoggerBundle lb = loggerBundle;
2058         if (lb.resourceBundleName != null) {
2059             // this Logger already has a ResourceBundle
2060 
2061             if (lb.resourceBundleName.equals(name)) {
2062                 // the names match so there is nothing more to do
2063                 return;
2064             }
2065 
2066             // cannot change ResourceBundles once they are set
2067             throw new IllegalArgumentException(
2068                 lb.resourceBundleName + " != " + name);
2069         }
2070 
2071         if (name == null) {
2072             return;
2073         }
2074 
2075         setCallerModuleRef(callerClass);
2076         if (isSystemLogger && (callerClass != null && callerClass.getClassLoader() != null)) {

2077             checkPermission();
2078         }
2079 
2080         if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
2081             loggerBundle = SYSTEM_BUNDLE;
2082         } else {
2083             ResourceBundle bundle = findResourceBundle(name, true);
2084             if (bundle == null) {
2085                 // We've failed to find an expected ResourceBundle.
2086                 // unset the caller's module since we were unable to find the
2087                 // the bundle using it
2088                 this.callerModuleRef = null;
2089                 throw new MissingResourceException("Can't find " + name + " bundle from ",
2090                         name, "");
2091             }
2092 
2093             loggerBundle = LoggerBundle.get(name, null);
2094         }
2095     }
2096 




  23  * questions.
  24  */
  25 
  26 
  27 package java.util.logging;
  28 
  29 import java.lang.ref.WeakReference;
  30 import java.lang.reflect.Module;
  31 import java.security.AccessController;
  32 import java.security.PrivilegedAction;
  33 import java.util.ArrayList;
  34 import java.util.Iterator;
  35 import java.util.Locale;
  36 import java.util.MissingResourceException;
  37 import java.util.Objects;
  38 import java.util.ResourceBundle;
  39 import java.util.concurrent.CopyOnWriteArrayList;
  40 import java.util.function.Supplier;
  41 import sun.reflect.CallerSensitive;
  42 import sun.reflect.Reflection;
  43 import static jdk.internal.logger.DefaultLoggerFinder.isSystem;
  44 
  45 /**
  46  * A Logger object is used to log messages for a specific
  47  * system or application component.  Loggers are normally named,
  48  * using a hierarchical dot-separated namespace.  Logger names
  49  * can be arbitrary strings, but they should normally be based on
  50  * the package name or class name of the logged component, such
  51  * as java.net or javax.swing.  In addition it is possible to create
  52  * "anonymous" Loggers that are not stored in the Logger namespace.
  53  * <p>
  54  * Logger objects may be obtained by calls on one of the getLogger
  55  * factory methods.  These will either create a new Logger or
  56  * return a suitable existing Logger. It is important to note that
  57  * the Logger returned by one of the {@code getLogger} factory methods
  58  * may be garbage collected at any time if a strong reference to the
  59  * Logger is not kept.
  60  * <p>
  61  * Logging messages will be forwarded to registered Handler
  62  * objects, which can forward the messages to a variety of
  63  * destinations, including consoles, files, OS logs, etc.


 363      * Protected method to construct a logger for a named subsystem.
 364      * <p>
 365      * The logger will be initially configured with a null Level
 366      * and with useParentHandlers set to true.
 367      *
 368      * @param   name    A name for the logger.  This should
 369      *                          be a dot-separated name and should normally
 370      *                          be based on the package name or class name
 371      *                          of the subsystem, such as java.net
 372      *                          or javax.swing.  It may be null for anonymous Loggers.
 373      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
 374      *                          messages for this logger.  May be null if none
 375      *                          of the messages require localization.
 376      * @throws MissingResourceException if the resourceBundleName is non-null and
 377      *             no corresponding resource can be found.
 378      */
 379     protected Logger(String name, String resourceBundleName) {
 380         this(name, resourceBundleName, null, LogManager.getLogManager(), false);
 381     }
 382 
 383     Logger(String name, String resourceBundleName, Module caller,
 384            LogManager manager, boolean isSystemLogger) {
 385         this.manager = manager;
 386         this.isSystemLogger = isSystemLogger;
 387         setupResourceInfo(resourceBundleName, caller);
 388         this.name = name;
 389         levelValue = Level.INFO.intValue();
 390     }
 391 
 392     private void setCallerModuleRef(Module callerModule) {



 393         if (callerModule != null) {
 394             this.callerModuleRef = new WeakReference<>(callerModule);
 395         }
 396     }
 397 
 398     private Module getCallerModule() {
 399         return (callerModuleRef != null)
 400                 ? callerModuleRef.get()
 401                 : null;
 402     }
 403 
 404     // This constructor is used only to create the global Logger.
 405     // It is needed to break a cyclic dependence between the LogManager
 406     // and Logger static initializers causing deadlocks.
 407     private Logger(String name) {
 408         // The manager field is not initialized here.
 409         this.name = name;
 410         this.isSystemLogger = true;
 411         levelValue = Level.INFO.intValue();
 412     }


 600         // We have to set the callers ClassLoader here in case demandLogger
 601         // above found a previously created Logger.  This can happen, for
 602         // example, if Logger.getLogger(name) is called and subsequently
 603         // Logger.getLogger(name, resourceBundleName) is called.  In this case
 604         // we won't necessarily have the correct classloader saved away, so
 605         // we need to set it here, too.
 606 
 607         result.setupResourceInfo(resourceBundleName, callerClass);
 608         return result;
 609     }
 610 
 611     // package-private
 612     // Add a platform logger to the system context.
 613     // i.e. caller of sun.util.logging.PlatformLogger.getLogger
 614     static Logger getPlatformLogger(String name) {
 615         LogManager manager = LogManager.getLogManager();
 616 
 617         // all loggers in the system context will default to
 618         // the system logger's resource bundle - therefore the caller won't
 619         // be needed and can be null.
 620         Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME, (Module)null);
 621         return result;
 622     }
 623 
 624     /**
 625      * Create an anonymous Logger.  The newly created Logger is not
 626      * registered in the LogManager namespace.  There will be no
 627      * access checks on updates to the logger.
 628      * <p>
 629      * This factory method is primarily intended for use from applets.
 630      * Because the resulting Logger is anonymous it can be kept private
 631      * by the creating class.  This removes the need for normal security
 632      * checks, which in turn allows untrusted applet code to update
 633      * the control state of the Logger.  For example an applet can do
 634      * a setLevel or an addHandler on an anonymous Logger.
 635      * <p>
 636      * Even although the new logger is anonymous, it is configured
 637      * to have the root logger ("") as its parent.  This means that
 638      * by default it inherits its effective level and handlers
 639      * from the root logger. Changing its parent via the
 640      * {@link #setParent(java.util.logging.Logger) setParent} method


 663      * by default it inherits its effective level and handlers
 664      * from the root logger.  Changing its parent via the
 665      * {@link #setParent(java.util.logging.Logger) setParent} method
 666      * will still require the security permission specified by that method.
 667      *
 668      * @param   resourceBundleName  name of ResourceBundle to be used for localizing
 669      *                          messages for this logger.
 670      *          May be null if none of the messages require localization.
 671      * @return a newly created private Logger
 672      * @throws MissingResourceException if the resourceBundleName is non-null and
 673      *             no corresponding resource can be found.
 674      */
 675 
 676     // Synchronization is not required here. All synchronization for
 677     // adding a new anonymous Logger object is handled by doSetParent().
 678     @CallerSensitive
 679     public static Logger getAnonymousLogger(String resourceBundleName) {
 680         LogManager manager = LogManager.getLogManager();
 681         // cleanup some Loggers that have been GC'ed
 682         manager.drainLoggerRefQueueBounded();
 683         final Class<?> callerClass = Reflection.getCallerClass();
 684         final Module module = callerClass.getModule();
 685         Logger result = new Logger(null, resourceBundleName,
 686                                    module, manager, false);
 687         result.anonymous = true;
 688         Logger root = manager.getLogger("");
 689         result.doSetParent(root);
 690         return result;
 691     }
 692 
 693     /**
 694      * Retrieve the localization resource bundle for this
 695      * logger.
 696      * This method will return a {@code ResourceBundle} that was either
 697      * set by the {@link
 698      * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or
 699      * <a href="#ResourceBundleMapping">mapped from the
 700      * the resource bundle name</a> set via the {@link
 701      * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory
 702      * method for the current default locale.
 703      * <br>Note that if the result is {@code null}, then the Logger will use a resource
 704      * bundle or resource bundle name inherited from its parent.
 705      *
 706      * @return localization bundle (may be {@code null})


2030                 }
2031             }
2032         } else {
2033             // we should have:
2034             //  useCallersModule && callerModule != null && callerModule.isNamed();
2035             // Try with the caller's module
2036             try {
2037                 // Use the caller's module
2038                 PrivilegedAction<ResourceBundle> pa = () ->
2039                     ResourceBundle.getBundle(name, currentLocale, callerModule);
2040                 catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION);
2041                 catalogName = name;
2042                 catalogLocale = currentLocale;
2043                 return catalog;
2044             } catch (MissingResourceException ex) {
2045                 return null; // no luck
2046             }
2047         }
2048     }
2049 
2050     private void setupResourceInfo(String name, Class<?> caller) {
2051         final Module module = caller == null ? null : caller.getModule();
2052         setupResourceInfo(name, module);
2053     }
2054 
2055     // Private utility method to initialize our one entry
2056     // resource bundle name cache and the callers Module
2057     // Note: for consistency reasons, we are careful to check
2058     // that a suitable ResourceBundle exists before setting the
2059     // resourceBundleName field.
2060     // Synchronized to prevent races in setting the fields.
2061     private synchronized void setupResourceInfo(String name,
2062                                                 Module callerModule) {
2063         final LoggerBundle lb = loggerBundle;
2064         if (lb.resourceBundleName != null) {
2065             // this Logger already has a ResourceBundle
2066 
2067             if (lb.resourceBundleName.equals(name)) {
2068                 // the names match so there is nothing more to do
2069                 return;
2070             }
2071 
2072             // cannot change ResourceBundles once they are set
2073             throw new IllegalArgumentException(
2074                 lb.resourceBundleName + " != " + name);
2075         }
2076 
2077         if (name == null) {
2078             return;
2079         }
2080 
2081         setCallerModuleRef(callerModule);
2082 
2083         if (isSystemLogger && (callerModule != null && !isSystem(callerModule))) {
2084             checkPermission();
2085         }
2086 
2087         if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
2088             loggerBundle = SYSTEM_BUNDLE;
2089         } else {
2090             ResourceBundle bundle = findResourceBundle(name, true);
2091             if (bundle == null) {
2092                 // We've failed to find an expected ResourceBundle.
2093                 // unset the caller's module since we were unable to find the
2094                 // the bundle using it
2095                 this.callerModuleRef = null;
2096                 throw new MissingResourceException("Can't find " + name + " bundle from ",
2097                         name, "");
2098             }
2099 
2100             loggerBundle = LoggerBundle.get(name, null);
2101         }
2102     }
2103 


< prev index next >