Save This Page
Home » openjdk-7 » java » util » logging » [javadoc | source]
    1   /*
    2    * Copyright 2000-2007 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   
   27   package java.util.logging;
   28   
   29   import java.io;
   30   import java.util;
   31   import java.security;
   32   import java.lang.ref.WeakReference;
   33   import java.beans.PropertyChangeListener;
   34   import java.beans.PropertyChangeSupport;
   35   import java.net.URL;
   36   import sun.security.action.GetPropertyAction;
   37   
   38   /**
   39    * There is a single global LogManager object that is used to
   40    * maintain a set of shared state about Loggers and log services.
   41    * <p>
   42    * This LogManager object:
   43    * <ul>
   44    * <li> Manages a hierarchical namespace of Logger objects.  All
   45    *      named Loggers are stored in this namespace.
   46    * <li> Manages a set of logging control properties.  These are
   47    *      simple key-value pairs that can be used by Handlers and
   48    *      other logging objects to configure themselves.
   49    * </ul>
   50    * <p>
   51    * The global LogManager object can be retrieved using LogManager.getLogManager().
   52    * The LogManager object is created during class initialization and
   53    * cannot subsequently be changed.
   54    * <p>
   55    * At startup the LogManager class is located using the
   56    * java.util.logging.manager system property.
   57    * <p>
   58    * By default, the LogManager reads its initial configuration from
   59    * a properties file "lib/logging.properties" in the JRE directory.
   60    * If you edit that property file you can change the default logging
   61    * configuration for all uses of that JRE.
   62    * <p>
   63    * In addition, the LogManager uses two optional system properties that
   64    * allow more control over reading the initial configuration:
   65    * <ul>
   66    * <li>"java.util.logging.config.class"
   67    * <li>"java.util.logging.config.file"
   68    * </ul>
   69    * These two properties may be set via the Preferences API, or as
   70    * command line property definitions to the "java" command, or as
   71    * system property definitions passed to JNI_CreateJavaVM.
   72    * <p>
   73    * If the "java.util.logging.config.class" property is set, then the
   74    * property value is treated as a class name.  The given class will be
   75    * loaded, an object will be instantiated, and that object's constructor
   76    * is responsible for reading in the initial configuration.  (That object
   77    * may use other system properties to control its configuration.)  The
   78    * alternate configuration class can use <tt>readConfiguration(InputStream)</tt>
   79    * to define properties in the LogManager.
   80    * <p>
   81    * If "java.util.logging.config.class" property is <b>not</b> set,
   82    * then the "java.util.logging.config.file" system property can be used
   83    * to specify a properties file (in java.util.Properties format). The
   84    * initial logging configuration will be read from this file.
   85    * <p>
   86    * If neither of these properties is defined then, as described
   87    * above, the LogManager will read its initial configuration from
   88    * a properties file "lib/logging.properties" in the JRE directory.
   89    * <p>
   90    * The properties for loggers and Handlers will have names starting
   91    * with the dot-separated name for the handler or logger.
   92    * <p>
   93    * The global logging properties may include:
   94    * <ul>
   95    * <li>A property "handlers".  This defines a whitespace or comma separated
   96    * list of class names for handler classes to load and register as
   97    * handlers on the root Logger (the Logger named "").  Each class
   98    * name must be for a Handler class which has a default constructor.
   99    * Note that these Handlers may be created lazily, when they are
  100    * first used.
  101    *
  102    * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
  103    * comma separated list of class names for handlers classes to
  104    * load and register as handlers to the specified logger. Each class
  105    * name must be for a Handler class which has a default constructor.
  106    * Note that these Handlers may be created lazily, when they are
  107    * first used.
  108    *
  109    * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
  110    * value. By default every logger calls its parent in addition to
  111    * handling the logging message itself, this often result in messages
  112    * being handled by the root logger as well. When setting this property
  113    * to false a Handler needs to be configured for this logger otherwise
  114    * no logging messages are delivered.
  115    *
  116    * <li>A property "config".  This property is intended to allow
  117    * arbitrary configuration code to be run.  The property defines a
  118    * whitespace or comma separated list of class names.  A new instance will be
  119    * created for each named class.  The default constructor of each class
  120    * may execute arbitrary code to update the logging configuration, such as
  121    * setting logger levels, adding handlers, adding filters, etc.
  122    * </ul>
  123    * <p>
  124    * Note that all classes loaded during LogManager configuration are
  125    * first searched on the system class path before any user class path.
  126    * That includes the LogManager class, any config classes, and any
  127    * handler classes.
  128    * <p>
  129    * Loggers are organized into a naming hierarchy based on their
  130    * dot separated names.  Thus "a.b.c" is a child of "a.b", but
  131    * "a.b1" and a.b2" are peers.
  132    * <p>
  133    * All properties whose names end with ".level" are assumed to define
  134    * log levels for Loggers.  Thus "foo.level" defines a log level for
  135    * the logger called "foo" and (recursively) for any of its children
  136    * in the naming hierarchy.  Log Levels are applied in the order they
  137    * are defined in the properties file.  Thus level settings for child
  138    * nodes in the tree should come after settings for their parents.
  139    * The property name ".level" can be used to set the level for the
  140    * root of the tree.
  141    * <p>
  142    * All methods on the LogManager object are multi-thread safe.
  143    *
  144    * @since 1.4
  145   */
  146   
  147   public class LogManager {
  148       // The global LogManager object
  149       private static LogManager manager;
  150   
  151       private final static Handler[] emptyHandlers = { };
  152       private Properties props = new Properties();
  153       private PropertyChangeSupport changes
  154                            = new PropertyChangeSupport(LogManager.class);
  155       private final static Level defaultLevel = Level.INFO;
  156   
  157       // Table of known loggers.  Maps names to Loggers.
  158       private Hashtable<String,WeakReference<Logger>> loggers =
  159           new Hashtable<String,WeakReference<Logger>>();
  160       // Tree of known loggers
  161       private LogNode root = new LogNode(null);
  162       private Logger rootLogger;
  163   
  164       // Have we done the primordial reading of the configuration file?
  165       // (Must be done after a suitable amount of java.lang.System
  166       // initialization has been done)
  167       private volatile boolean readPrimordialConfiguration;
  168       // Have we initialized global (root) handlers yet?
  169       // This gets set to false in readConfiguration
  170       private boolean initializedGlobalHandlers = true;
  171       // True if JVM death is imminent and the exit hook has been called.
  172       private boolean deathImminent;
  173   
  174       static {
  175           AccessController.doPrivileged(new PrivilegedAction<Object>() {
  176                   public Object run() {
  177                       String cname = null;
  178                       try {
  179                           cname = System.getProperty("java.util.logging.manager");
  180                           if (cname != null) {
  181                               try {
  182                                   Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
  183                                   manager = (LogManager) clz.newInstance();
  184                               } catch (ClassNotFoundException ex) {
  185                                   Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
  186                                   manager = (LogManager) clz.newInstance();
  187                               }
  188                           }
  189                       } catch (Exception ex) {
  190                           System.err.println("Could not load Logmanager \"" + cname + "\"");
  191                           ex.printStackTrace();
  192                       }
  193                       if (manager == null) {
  194                           manager = new LogManager();
  195                       }
  196   
  197                       // Create and retain Logger for the root of the namespace.
  198                       manager.rootLogger = manager.new RootLogger();
  199                       manager.addLogger(manager.rootLogger);
  200   
  201                       // Adding the global Logger. Doing so in the Logger.<clinit>
  202                       // would deadlock with the LogManager.<clinit>.
  203                       Logger.global.setLogManager(manager);
  204                       manager.addLogger(Logger.global);
  205   
  206                       // We don't call readConfiguration() here, as we may be running
  207                       // very early in the JVM startup sequence.  Instead readConfiguration
  208                       // will be called lazily in getLogManager().
  209                       return null;
  210                   }
  211               });
  212       }
  213   
  214   
  215       // This private class is used as a shutdown hook.
  216       // It does a "reset" to close all open handlers.
  217       private class Cleaner extends Thread {
  218           public void run() {
  219               // This is to ensure the LogManager.<clinit> is completed
  220               // before synchronized block. Otherwise deadlocks are possible.
  221               LogManager mgr = manager;
  222   
  223               // If the global handlers haven't been initialized yet, we
  224               // don't want to initialize them just so we can close them!
  225               synchronized (LogManager.this) {
  226                   // Note that death is imminent.
  227                   deathImminent = true;
  228                   initializedGlobalHandlers = true;
  229               }
  230   
  231               // Do a reset to close all active handlers.
  232               reset();
  233           }
  234       }
  235   
  236   
  237       /**
  238        * Protected constructor.  This is protected so that container applications
  239        * (such as J2EE containers) can subclass the object.  It is non-public as
  240        * it is intended that there only be one LogManager object, whose value is
  241        * retrieved by calling Logmanager.getLogManager.
  242        */
  243       protected LogManager() {
  244           // Add a shutdown hook to close the global handlers.
  245           try {
  246               Runtime.getRuntime().addShutdownHook(new Cleaner());
  247           } catch (IllegalStateException e) {
  248               // If the VM is already shutting down,
  249               // We do not need to register shutdownHook.
  250           }
  251       }
  252   
  253       /**
  254        * Return the global LogManager object.
  255        */
  256       public static LogManager getLogManager() {
  257           if (manager != null) {
  258               manager.readPrimordialConfiguration();
  259           }
  260           return manager;
  261       }
  262   
  263       private void readPrimordialConfiguration() {
  264           if (!readPrimordialConfiguration) {
  265               synchronized (this) {
  266                   if (!readPrimordialConfiguration) {
  267                       // If System.in/out/err are null, it's a good
  268                       // indication that we're still in the
  269                       // bootstrapping phase
  270                       if (System.out == null) {
  271                           return;
  272                       }
  273                       readPrimordialConfiguration = true;
  274                       try {
  275                           AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
  276                                   public Object run() throws Exception {
  277                                       readConfiguration();
  278                                       return null;
  279                                   }
  280                               });
  281                       } catch (Exception ex) {
  282                           // System.err.println("Can't read logging configuration:");
  283                           // ex.printStackTrace();
  284                       }
  285                   }
  286               }
  287           }
  288       }
  289   
  290       /**
  291        * Adds an event listener to be invoked when the logging
  292        * properties are re-read. Adding multiple instances of
  293        * the same event Listener results in multiple entries
  294        * in the property event listener table.
  295        *
  296        * @param l  event listener
  297        * @exception  SecurityException  if a security manager exists and if
  298        *             the caller does not have LoggingPermission("control").
  299        * @exception NullPointerException if the PropertyChangeListener is null.
  300        */
  301       public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException {
  302           if (l == null) {
  303               throw new NullPointerException();
  304           }
  305           checkAccess();
  306           changes.addPropertyChangeListener(l);
  307       }
  308   
  309       /**
  310        * Removes an event listener for property change events.
  311        * If the same listener instance has been added to the listener table
  312        * through multiple invocations of <CODE>addPropertyChangeListener</CODE>,
  313        * then an equivalent number of
  314        * <CODE>removePropertyChangeListener</CODE> invocations are required to remove
  315        * all instances of that listener from the listener table.
  316        * <P>
  317        * Returns silently if the given listener is not found.
  318        *
  319        * @param l  event listener (can be null)
  320        * @exception  SecurityException  if a security manager exists and if
  321        *             the caller does not have LoggingPermission("control").
  322        */
  323       public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException {
  324           checkAccess();
  325           changes.removePropertyChangeListener(l);
  326       }
  327   
  328       // Package-level method.
  329       // Find or create a specified logger instance. If a logger has
  330       // already been created with the given name it is returned.
  331       // Otherwise a new logger instance is created and registered
  332       // in the LogManager global namespace.
  333       synchronized Logger demandLogger(String name) {
  334           Logger result = getLogger(name);
  335           if (result == null) {
  336               result = new Logger(name, null);
  337               addLogger(result);
  338               result = getLogger(name);
  339           }
  340           return result;
  341       }
  342   
  343       // If logger.getUseParentHandlers() returns 'true' and any of the logger's
  344       // parents have levels or handlers defined, make sure they are instantiated.
  345       private void processParentHandlers(Logger logger, String name) {
  346           int ix = 1;
  347           for (;;) {
  348               int ix2 = name.indexOf(".", ix);
  349               if (ix2 < 0) {
  350                   break;
  351               }
  352               String pname = name.substring(0,ix2);
  353   
  354               if (getProperty(pname+".level")    != null ||
  355                   getProperty(pname+".handlers") != null) {
  356                   // This pname has a level/handlers definition.
  357                   // Make sure it exists.
  358                   demandLogger(pname);
  359               }
  360               ix = ix2+1;
  361           }
  362       }
  363   
  364       // Add new per logger handlers.
  365       // We need to raise privilege here. All our decisions will
  366       // be made based on the logging configuration, which can
  367       // only be modified by trusted code.
  368       private void loadLoggerHandlers(final Logger logger, final String name,
  369                                       final String handlersPropertyName) {
  370           AccessController.doPrivileged(new PrivilegedAction<Object>() {
  371               public Object run() {
  372                   if (logger != rootLogger) {
  373                       boolean useParent = getBooleanProperty(name + ".useParentHandlers", true);
  374                       if (!useParent) {
  375                           logger.setUseParentHandlers(false);
  376                       }
  377                   }
  378   
  379                   String names[] = parseClassNames(handlersPropertyName);
  380                   for (int i = 0; i < names.length; i++) {
  381                       String word = names[i];
  382                       try {
  383                           Class   clz = ClassLoader.getSystemClassLoader().loadClass(word);
  384                           Handler hdl = (Handler) clz.newInstance();
  385                           try {
  386                               // Check if there is a property defining the
  387                               // this handler's level.
  388                               String levs = getProperty(word + ".level");
  389                               if (levs != null) {
  390                                   hdl.setLevel(Level.parse(levs));
  391                               }
  392                           } catch (Exception ex) {
  393                               System.err.println("Can't set level for " + word);
  394                               // Probably a bad level. Drop through.
  395                           }
  396                           // Add this Handler to the logger
  397                           logger.addHandler(hdl);
  398                       } catch (Exception ex) {
  399                           System.err.println("Can't load log handler \"" + word + "\"");
  400                           System.err.println("" + ex);
  401                           ex.printStackTrace();
  402                       }
  403                   }
  404                   return null;
  405               }});
  406       }
  407   
  408       /**
  409        * Add a named logger.  This does nothing and returns false if a logger
  410        * with the same name is already registered.
  411        * <p>
  412        * The Logger factory methods call this method to register each
  413        * newly created Logger.
  414        * <p>
  415        * The application should retain its own reference to the Logger
  416        * object to avoid it being garbage collected.  The LogManager
  417        * may only retain a weak reference.
  418        *
  419        * @param   logger the new logger.
  420        * @return  true if the argument logger was registered successfully,
  421        *          false if a logger of that name already exists.
  422        * @exception NullPointerException if the logger name is null.
  423        */
  424       public synchronized boolean addLogger(Logger logger) {
  425           final String name = logger.getName();
  426           if (name == null) {
  427               throw new NullPointerException();
  428           }
  429   
  430           WeakReference<Logger> ref = loggers.get(name);
  431           if (ref != null) {
  432               if (ref.get() == null) {
  433                   // Hashtable holds stale weak reference
  434                   // to a logger which has been GC-ed.
  435                   // Allow to register new one.
  436                   loggers.remove(name);
  437               } else {
  438                   // We already have a registered logger with the given name.
  439                   return false;
  440               }
  441           }
  442   
  443           // We're adding a new logger.
  444           // Note that we are creating a weak reference here.
  445           loggers.put(name, new WeakReference<Logger>(logger));
  446   
  447           // Apply any initial level defined for the new logger.
  448           Level level = getLevelProperty(name+".level", null);
  449           if (level != null) {
  450               doSetLevel(logger, level);
  451           }
  452   
  453           // Do we have a per logger handler too?
  454           // Note: this will add a 200ms penalty
  455           loadLoggerHandlers(logger, name, name+".handlers");
  456           processParentHandlers(logger, name);
  457   
  458           // Find the new node and its parent.
  459           LogNode node = findNode(name);
  460           node.loggerRef = new WeakReference<Logger>(logger);
  461           Logger parent = null;
  462           LogNode nodep = node.parent;
  463           while (nodep != null) {
  464               WeakReference<Logger> nodeRef = nodep.loggerRef;
  465               if (nodeRef != null) {
  466                   parent = nodeRef.get();
  467                   if (parent != null) {
  468                       break;
  469                   }
  470               }
  471               nodep = nodep.parent;
  472           }
  473   
  474           if (parent != null) {
  475               doSetParent(logger, parent);
  476           }
  477           // Walk over the children and tell them we are their new parent.
  478           node.walkAndSetParent(logger);
  479   
  480           return true;
  481       }
  482   
  483   
  484       // Private method to set a level on a logger.
  485       // If necessary, we raise privilege before doing the call.
  486       private static void doSetLevel(final Logger logger, final Level level) {
  487           SecurityManager sm = System.getSecurityManager();
  488           if (sm == null) {
  489               // There is no security manager, so things are easy.
  490               logger.setLevel(level);
  491               return;
  492           }
  493           // There is a security manager.  Raise privilege before
  494           // calling setLevel.
  495           AccessController.doPrivileged(new PrivilegedAction<Object>() {
  496               public Object run() {
  497                   logger.setLevel(level);
  498                   return null;
  499               }});
  500       }
  501   
  502   
  503   
  504       // Private method to set a parent on a logger.
  505       // If necessary, we raise privilege before doing the setParent call.
  506       private static void doSetParent(final Logger logger, final Logger parent) {
  507           SecurityManager sm = System.getSecurityManager();
  508           if (sm == null) {
  509               // There is no security manager, so things are easy.
  510               logger.setParent(parent);
  511               return;
  512           }
  513           // There is a security manager.  Raise privilege before
  514           // calling setParent.
  515           AccessController.doPrivileged(new PrivilegedAction<Object>() {
  516               public Object run() {
  517                   logger.setParent(parent);
  518                   return null;
  519               }});
  520       }
  521   
  522       // Find a node in our tree of logger nodes.
  523       // If necessary, create it.
  524       private LogNode findNode(String name) {
  525           if (name == null || name.equals("")) {
  526               return root;
  527           }
  528           LogNode node = root;
  529           while (name.length() > 0) {
  530               int ix = name.indexOf(".");
  531               String head;
  532               if (ix > 0) {
  533                   head = name.substring(0,ix);
  534                   name = name.substring(ix+1);
  535               } else {
  536                   head = name;
  537                   name = "";
  538               }
  539               if (node.children == null) {
  540                   node.children = new HashMap<String,LogNode>();
  541               }
  542               LogNode child = node.children.get(head);
  543               if (child == null) {
  544                   child = new LogNode(node);
  545                   node.children.put(head, child);
  546               }
  547               node = child;
  548           }
  549           return node;
  550       }
  551   
  552       /**
  553        * Method to find a named logger.
  554        * <p>
  555        * Note that since untrusted code may create loggers with
  556        * arbitrary names this method should not be relied on to
  557        * find Loggers for security sensitive logging.
  558        * <p>
  559        * @param name name of the logger
  560        * @return  matching logger or null if none is found
  561        */
  562       public synchronized Logger getLogger(String name) {
  563           WeakReference<Logger> ref = loggers.get(name);
  564           if (ref == null) {
  565               return null;
  566           }
  567           Logger logger = ref.get();
  568           if (logger == null) {
  569               // Hashtable holds stale weak reference
  570               // to a logger which has been GC-ed.
  571               loggers.remove(name);
  572           }
  573           return logger;
  574       }
  575   
  576       /**
  577        * Get an enumeration of known logger names.
  578        * <p>
  579        * Note:  Loggers may be added dynamically as new classes are loaded.
  580        * This method only reports on the loggers that are currently registered.
  581        * <p>
  582        * @return  enumeration of logger name strings
  583        */
  584       public synchronized Enumeration<String> getLoggerNames() {
  585           return loggers.keys();
  586       }
  587   
  588       /**
  589        * Reinitialize the logging properties and reread the logging configuration.
  590        * <p>
  591        * The same rules are used for locating the configuration properties
  592        * as are used at startup.  So normally the logging properties will
  593        * be re-read from the same file that was used at startup.
  594        * <P>
  595        * Any log level definitions in the new configuration file will be
  596        * applied using Logger.setLevel(), if the target Logger exists.
  597        * <p>
  598        * A PropertyChangeEvent will be fired after the properties are read.
  599        *
  600        * @exception  SecurityException  if a security manager exists and if
  601        *             the caller does not have LoggingPermission("control").
  602        * @exception  IOException if there are IO problems reading the configuration.
  603        */
  604       public void readConfiguration() throws IOException, SecurityException {
  605           checkAccess();
  606   
  607           // if a configuration class is specified, load it and use it.
  608           String cname = System.getProperty("java.util.logging.config.class");
  609           if (cname != null) {
  610               try {
  611                   // Instantiate the named class.  It is its constructor's
  612                   // responsibility to initialize the logging configuration, by
  613                   // calling readConfiguration(InputStream) with a suitable stream.
  614                   try {
  615                       Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
  616                       clz.newInstance();
  617                       return;
  618                   } catch (ClassNotFoundException ex) {
  619                       Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
  620                       clz.newInstance();
  621                       return;
  622                   }
  623               } catch (Exception ex) {
  624                   System.err.println("Logging configuration class \"" + cname + "\" failed");
  625                   System.err.println("" + ex);
  626                   // keep going and useful config file.
  627               }
  628           }
  629   
  630           String fname = System.getProperty("java.util.logging.config.file");
  631           if (fname == null) {
  632               fname = System.getProperty("java.home");
  633               if (fname == null) {
  634                   throw new Error("Can't find java.home ??");
  635               }
  636               File f = new File(fname, "lib");
  637               f = new File(f, "logging.properties");
  638               fname = f.getCanonicalPath();
  639           }
  640           InputStream in = new FileInputStream(fname);
  641           BufferedInputStream bin = new BufferedInputStream(in);
  642           try {
  643               readConfiguration(bin);
  644           } finally {
  645               if (in != null) {
  646                   in.close();
  647               }
  648           }
  649       }
  650   
  651       /**
  652        * Reset the logging configuration.
  653        * <p>
  654        * For all named loggers, the reset operation removes and closes
  655        * all Handlers and (except for the root logger) sets the level
  656        * to null.  The root logger's level is set to Level.INFO.
  657        *
  658        * @exception  SecurityException  if a security manager exists and if
  659        *             the caller does not have LoggingPermission("control").
  660        */
  661   
  662       public void reset() throws SecurityException {
  663           checkAccess();
  664           synchronized (this) {
  665               props = new Properties();
  666               // Since we are doing a reset we no longer want to initialize
  667               // the global handlers, if they haven't been initialized yet.
  668               initializedGlobalHandlers = true;
  669           }
  670           Enumeration enum_ = getLoggerNames();
  671           while (enum_.hasMoreElements()) {
  672               String name = (String)enum_.nextElement();
  673               resetLogger(name);
  674           }
  675       }
  676   
  677   
  678       // Private method to reset an individual target logger.
  679       private void resetLogger(String name) {
  680           Logger logger = getLogger(name);
  681           if (logger == null) {
  682               return;
  683           }
  684           // Close all the Logger's handlers.
  685           Handler[] targets = logger.getHandlers();
  686           for (int i = 0; i < targets.length; i++) {
  687               Handler h = targets[i];
  688               logger.removeHandler(h);
  689               try {
  690                   h.close();
  691               } catch (Exception ex) {
  692                   // Problems closing a handler?  Keep going...
  693               }
  694           }
  695           if (name != null && name.equals("")) {
  696               // This is the root logger.
  697               logger.setLevel(defaultLevel);
  698           } else {
  699               logger.setLevel(null);
  700           }
  701       }
  702   
  703       // get a list of whitespace separated classnames from a property.
  704       private String[] parseClassNames(String propertyName) {
  705           String hands = getProperty(propertyName);
  706           if (hands == null) {
  707               return new String[0];
  708           }
  709           hands = hands.trim();
  710           int ix = 0;
  711           Vector<String> result = new Vector<String>();
  712           while (ix < hands.length()) {
  713               int end = ix;
  714               while (end < hands.length()) {
  715                   if (Character.isWhitespace(hands.charAt(end))) {
  716                       break;
  717                   }
  718                   if (hands.charAt(end) == ',') {
  719                       break;
  720                   }
  721                   end++;
  722               }
  723               String word = hands.substring(ix, end);
  724               ix = end+1;
  725               word = word.trim();
  726               if (word.length() == 0) {
  727                   continue;
  728               }
  729               result.add(word);
  730           }
  731           return result.toArray(new String[result.size()]);
  732       }
  733   
  734       /**
  735        * Reinitialize the logging properties and reread the logging configuration
  736        * from the given stream, which should be in java.util.Properties format.
  737        * A PropertyChangeEvent will be fired after the properties are read.
  738        * <p>
  739        * Any log level definitions in the new configuration file will be
  740        * applied using Logger.setLevel(), if the target Logger exists.
  741        *
  742        * @param ins       stream to read properties from
  743        * @exception  SecurityException  if a security manager exists and if
  744        *             the caller does not have LoggingPermission("control").
  745        * @exception  IOException if there are problems reading from the stream.
  746        */
  747       public void readConfiguration(InputStream ins) throws IOException, SecurityException {
  748           checkAccess();
  749           reset();
  750   
  751           // Load the properties
  752           props.load(ins);
  753           // Instantiate new configuration objects.
  754           String names[] = parseClassNames("config");
  755   
  756           for (int i = 0; i < names.length; i++) {
  757               String word = names[i];
  758               try {
  759                   Class clz = ClassLoader.getSystemClassLoader().loadClass(word);
  760                   clz.newInstance();
  761               } catch (Exception ex) {
  762                   System.err.println("Can't load config class \"" + word + "\"");
  763                   System.err.println("" + ex);
  764                   // ex.printStackTrace();
  765               }
  766           }
  767   
  768           // Set levels on any pre-existing loggers, based on the new properties.
  769           setLevelsOnExistingLoggers();
  770   
  771           // Notify any interested parties that our properties have changed.
  772           changes.firePropertyChange(null, null, null);
  773   
  774           // Note that we need to reinitialize global handles when
  775           // they are first referenced.
  776           synchronized (this) {
  777               initializedGlobalHandlers = false;
  778           }
  779       }
  780   
  781       /**
  782        * Get the value of a logging property.
  783        * The method returns null if the property is not found.
  784        * @param name      property name
  785        * @return          property value
  786        */
  787       public String getProperty(String name) {
  788           return props.getProperty(name);
  789       }
  790   
  791       // Package private method to get a String property.
  792       // If the property is not defined we return the given
  793       // default value.
  794       String getStringProperty(String name, String defaultValue) {
  795           String val = getProperty(name);
  796           if (val == null) {
  797               return defaultValue;
  798           }
  799           return val.trim();
  800       }
  801   
  802       // Package private method to get an integer property.
  803       // If the property is not defined or cannot be parsed
  804       // we return the given default value.
  805       int getIntProperty(String name, int defaultValue) {
  806           String val = getProperty(name);
  807           if (val == null) {
  808               return defaultValue;
  809           }
  810           try {
  811               return Integer.parseInt(val.trim());
  812           } catch (Exception ex) {
  813               return defaultValue;
  814           }
  815       }
  816   
  817       // Package private method to get a boolean property.
  818       // If the property is not defined or cannot be parsed
  819       // we return the given default value.
  820       boolean getBooleanProperty(String name, boolean defaultValue) {
  821           String val = getProperty(name);
  822           if (val == null) {
  823               return defaultValue;
  824           }
  825           val = val.toLowerCase();
  826           if (val.equals("true") || val.equals("1")) {
  827               return true;
  828           } else if (val.equals("false") || val.equals("0")) {
  829               return false;
  830           }
  831           return defaultValue;
  832       }
  833   
  834       // Package private method to get a Level property.
  835       // If the property is not defined or cannot be parsed
  836       // we return the given default value.
  837       Level getLevelProperty(String name, Level defaultValue) {
  838           String val = getProperty(name);
  839           if (val == null) {
  840               return defaultValue;
  841           }
  842           try {
  843               return Level.parse(val.trim());
  844           } catch (Exception ex) {
  845               return defaultValue;
  846           }
  847       }
  848   
  849       // Package private method to get a filter property.
  850       // We return an instance of the class named by the "name"
  851       // property. If the property is not defined or has problems
  852       // we return the defaultValue.
  853       Filter getFilterProperty(String name, Filter defaultValue) {
  854           String val = getProperty(name);
  855           try {
  856               if (val != null) {
  857                   Class clz = ClassLoader.getSystemClassLoader().loadClass(val);
  858                   return (Filter) clz.newInstance();
  859               }
  860           } catch (Exception ex) {
  861               // We got one of a variety of exceptions in creating the
  862               // class or creating an instance.
  863               // Drop through.
  864           }
  865           // We got an exception.  Return the defaultValue.
  866           return defaultValue;
  867       }
  868   
  869   
  870       // Package private method to get a formatter property.
  871       // We return an instance of the class named by the "name"
  872       // property. If the property is not defined or has problems
  873       // we return the defaultValue.
  874       Formatter getFormatterProperty(String name, Formatter defaultValue) {
  875           String val = getProperty(name);
  876           try {
  877               if (val != null) {
  878                   Class clz = ClassLoader.getSystemClassLoader().loadClass(val);
  879                   return (Formatter) clz.newInstance();
  880               }
  881           } catch (Exception ex) {
  882               // We got one of a variety of exceptions in creating the
  883               // class or creating an instance.
  884               // Drop through.
  885           }
  886           // We got an exception.  Return the defaultValue.
  887           return defaultValue;
  888       }
  889   
  890       // Private method to load the global handlers.
  891       // We do the real work lazily, when the global handlers
  892       // are first used.
  893       private synchronized void initializeGlobalHandlers() {
  894           if (initializedGlobalHandlers) {
  895               return;
  896           }
  897   
  898           initializedGlobalHandlers = true;
  899   
  900           if (deathImminent) {
  901               // Aaargh...
  902               // The VM is shutting down and our exit hook has been called.
  903               // Avoid allocating global handlers.
  904               return;
  905           }
  906           loadLoggerHandlers(rootLogger, null, "handlers");
  907       }
  908   
  909   
  910       private Permission ourPermission = new LoggingPermission("control", null);
  911   
  912       /**
  913        * Check that the current context is trusted to modify the logging
  914        * configuration.  This requires LoggingPermission("control").
  915        * <p>
  916        * If the check fails we throw a SecurityException, otherwise
  917        * we return normally.
  918        *
  919        * @exception  SecurityException  if a security manager exists and if
  920        *             the caller does not have LoggingPermission("control").
  921        */
  922       public void checkAccess() throws SecurityException {
  923           SecurityManager sm = System.getSecurityManager();
  924           if (sm == null) {
  925               return;
  926           }
  927           sm.checkPermission(ourPermission);
  928       }
  929   
  930       // Nested class to represent a node in our tree of named loggers.
  931       private static class LogNode {
  932           HashMap<String,LogNode> children;
  933           WeakReference<Logger> loggerRef;
  934           LogNode parent;
  935   
  936           LogNode(LogNode parent) {
  937               this.parent = parent;
  938           }
  939   
  940           // Recursive method to walk the tree below a node and set
  941           // a new parent logger.
  942           void walkAndSetParent(Logger parent) {
  943               if (children == null) {
  944                   return;
  945               }
  946               Iterator<LogNode> values = children.values().iterator();
  947               while (values.hasNext()) {
  948                   LogNode node = values.next();
  949                   WeakReference<Logger> ref = node.loggerRef;
  950                   Logger logger = (ref == null) ? null : ref.get();
  951                   if (logger == null) {
  952                       node.walkAndSetParent(parent);
  953                   } else {
  954                       doSetParent(logger, parent);
  955                   }
  956               }
  957           }
  958       }
  959   
  960       // We use a subclass of Logger for the root logger, so
  961       // that we only instantiate the global handlers when they
  962       // are first needed.
  963       private class RootLogger extends Logger {
  964   
  965           private RootLogger() {
  966               super("", null);
  967               setLevel(defaultLevel);
  968           }
  969   
  970           public void log(LogRecord record) {
  971               // Make sure that the global handlers have been instantiated.
  972               initializeGlobalHandlers();
  973               super.log(record);
  974           }
  975   
  976           public void addHandler(Handler h) {
  977               initializeGlobalHandlers();
  978               super.addHandler(h);
  979           }
  980   
  981           public void removeHandler(Handler h) {
  982               initializeGlobalHandlers();
  983               super.removeHandler(h);
  984           }
  985   
  986           public Handler[] getHandlers() {
  987               initializeGlobalHandlers();
  988               return super.getHandlers();
  989           }
  990       }
  991   
  992   
  993       // Private method to be called when the configuration has
  994       // changed to apply any level settings to any pre-existing loggers.
  995       synchronized private void setLevelsOnExistingLoggers() {
  996           Enumeration enum_ = props.propertyNames();
  997           while (enum_.hasMoreElements()) {
  998               String key = (String)enum_.nextElement();
  999               if (!key.endsWith(".level")) {
 1000                   // Not a level definition.
 1001                   continue;
 1002               }
 1003               int ix = key.length() - 6;
 1004               String name = key.substring(0, ix);
 1005               Level level = getLevelProperty(key, null);
 1006               if (level == null) {
 1007                   System.err.println("Bad level value for property: " + key);
 1008                   continue;
 1009               }
 1010               Logger l = getLogger(name);
 1011               if (l == null) {
 1012                   continue;
 1013               }
 1014               l.setLevel(level);
 1015           }
 1016       }
 1017   
 1018       // Management Support
 1019       private static LoggingMXBean loggingMXBean = null;
 1020       /**
 1021        * String representation of the
 1022        * {@link javax.management.ObjectName} for {@link LoggingMXBean}.
 1023        * @since 1.5
 1024        */
 1025       public final static String LOGGING_MXBEAN_NAME
 1026           = "java.util.logging:type=Logging";
 1027   
 1028       /**
 1029        * Returns <tt>LoggingMXBean</tt> for managing loggers.
 1030        * The <tt>LoggingMXBean</tt> can also obtained from the
 1031        * {@link java.lang.management.ManagementFactory#getPlatformMBeanServer
 1032        * platform <tt>MBeanServer</tt>} method.
 1033        *
 1034        * @return a {@link LoggingMXBean} object.
 1035        *
 1036        * @see java.lang.management.ManagementFactory
 1037        * @since 1.5
 1038        */
 1039       public static synchronized LoggingMXBean  getLoggingMXBean() {
 1040           if (loggingMXBean == null) {
 1041               loggingMXBean =  new Logging();
 1042           }
 1043           return loggingMXBean;
 1044       }
 1045   
 1046   }

Save This Page
Home » openjdk-7 » java » util » logging » [javadoc | source]