Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » juli » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.juli;
   19   
   20   import java.io.File;
   21   import java.io.FileInputStream;
   22   import java.io.IOException;
   23   import java.io.InputStream;
   24   import java.net.URLClassLoader;
   25   import java.security.AccessController;
   26   import java.security.PrivilegedAction;
   27   import java.util.Collections;
   28   import java.util.Enumeration;
   29   import java.util.HashMap;
   30   import java.util.Iterator;
   31   import java.util.Map;
   32   import java.util.Properties;
   33   import java.util.StringTokenizer;
   34   import java.util.WeakHashMap;
   35   import java.util.logging.Handler;
   36   import java.util.logging.Level;
   37   import java.util.logging.LogManager;
   38   import java.util.logging.Logger;
   39   
   40   
   41   /**
   42    * Per classloader LogManager implementation.
   43    */
   44   public class ClassLoaderLogManager extends LogManager {
   45   
   46   
   47       // -------------------------------------------------------------- Variables
   48   
   49   
   50       /**
   51        * Map containing the classloader information, keyed per classloader. A
   52        * weak hashmap is used to ensure no classloader reference is leaked from 
   53        * application redeployment.
   54        */
   55       protected final Map<ClassLoader, ClassLoaderLogInfo> classLoaderLoggers = 
   56           new WeakHashMap<ClassLoader, ClassLoaderLogInfo>();
   57   
   58       
   59       /**
   60        * This prefix is used to allow using prefixes for the properties names
   61        * of handlers and their subcomponents.
   62        */
   63       protected ThreadLocal<String> prefix = new ThreadLocal<String>();
   64   
   65       
   66       // --------------------------------------------------------- Public Methods
   67   
   68   
   69       /**
   70        * Add the specified logger to the classloader local configuration.
   71        * 
   72        * @param logger The logger to be added
   73        */
   74       public synchronized boolean addLogger(final Logger logger) {
   75   
   76           final String loggerName = logger.getName();
   77   
   78           ClassLoader classLoader = 
   79               Thread.currentThread().getContextClassLoader();
   80           ClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
   81           if (info.loggers.containsKey(loggerName)) {
   82               return false;
   83           }
   84           info.loggers.put(loggerName, logger);
   85   
   86           // Apply initial level for new logger
   87           final String levelString = getProperty(loggerName + ".level");
   88           if (levelString != null) {
   89               try {
   90                   AccessController.doPrivileged(new PrivilegedAction() {
   91                       public Object run() {
   92                           logger.setLevel(Level.parse(levelString.trim()));
   93                           return null;
   94                       }
   95                   });
   96               } catch (IllegalArgumentException e) {
   97                   // Leave level set to null
   98               }
   99           }
  100   
  101           // If any parent loggers have levels definied, make sure they are
  102           // instantiated
  103           int dotIndex = loggerName.lastIndexOf('.');
  104           while (dotIndex >= 0) {
  105               final String parentName = loggerName.substring(0, dotIndex);
  106               if (getProperty(parentName + ".level") != null) {
  107                   Logger.getLogger(parentName);
  108                   break;
  109               }
  110               dotIndex = loggerName.lastIndexOf('.', dotIndex - 1);
  111           }
  112   
  113           // Find associated node
  114           LogNode node = info.rootNode.findNode(loggerName);
  115           node.logger = logger;
  116   
  117           // Set parent logger
  118           Logger parentLogger = node.findParentLogger();
  119           if (parentLogger != null) {
  120               doSetParentLogger(logger, parentLogger);
  121           }
  122   
  123           // Tell children we are their new parent
  124           node.setParentLogger(logger);
  125   
  126           // Add associated handlers, if any are defined using the .handlers property.
  127           // In this case, handlers of the parent logger(s) will not be used
  128           String handlers = getProperty(loggerName + ".handlers");
  129           if (handlers != null) {
  130               logger.setUseParentHandlers(false);
  131               StringTokenizer tok = new StringTokenizer(handlers, ",");
  132               while (tok.hasMoreTokens()) {
  133                   String handlerName = (tok.nextToken().trim());
  134                   Handler handler = null;
  135                   ClassLoader current = classLoader;
  136                   while (current != null) {
  137                       info = (ClassLoaderLogInfo) classLoaderLoggers.get(current);
  138                       if (info != null) {
  139                           handler = (Handler) info.handlers.get(handlerName);
  140                           if (handler != null) {
  141                               break;
  142                           }
  143                       }
  144                       current = current.getParent();
  145                   }
  146                   if (handler != null) {
  147                       logger.addHandler(handler);
  148                   }
  149               }
  150           }
  151   
  152           // Parse useParentHandlers to set if the logger should delegate to its parent.
  153           // Unlike java.util.logging, the default is to not delegate if a list of handlers
  154           // has been specified for the logger.
  155           String useParentHandlersString = getProperty(loggerName + ".useParentHandlers");
  156           if (Boolean.valueOf(useParentHandlersString).booleanValue()) {
  157               logger.setUseParentHandlers(true);
  158           }
  159           
  160           return true;
  161       }
  162   
  163       
  164       /**
  165        * Get the logger associated with the specified name inside 
  166        * the classloader local configuration. If this returns null,
  167        * and the call originated for Logger.getLogger, a new
  168        * logger with the specified name will be instantiated and
  169        * added using addLogger.
  170        * 
  171        * @param name The name of the logger to retrieve
  172        */
  173       public synchronized Logger getLogger(final String name) {
  174           ClassLoader classLoader = Thread.currentThread()
  175                   .getContextClassLoader();
  176           return (Logger) getClassLoaderInfo(classLoader).loggers.get(name);
  177       }
  178       
  179       
  180       /**
  181        * Get an enumeration of the logger names currently defined in the 
  182        * classloader local configuration.
  183        */
  184       public synchronized Enumeration<String> getLoggerNames() {
  185           ClassLoader classLoader = Thread.currentThread()
  186                   .getContextClassLoader();
  187           return Collections.enumeration(getClassLoaderInfo(classLoader).loggers.keySet());
  188       }
  189   
  190       
  191       /**
  192        * Get the value of the specified property in the classloader local
  193        * configuration.
  194        * 
  195        * @param name The property name
  196        */    
  197       public String getProperty(String name) {
  198           ClassLoader classLoader = Thread.currentThread()
  199               .getContextClassLoader();
  200           String prefix = (String) this.prefix.get();
  201           if (prefix != null) {
  202               name = prefix + name;
  203           }
  204           ClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
  205           String result = info.props.getProperty(name);
  206           // If the property was not found, and the current classloader had no 
  207           // configuration (property list is empty), look for the parent classloader
  208           // properties.
  209           if ((result == null) && (info.props.isEmpty())) {
  210               ClassLoader current = classLoader.getParent();
  211               while (current != null) {
  212                   info = (ClassLoaderLogInfo) classLoaderLoggers.get(current);
  213                   if (info != null) {
  214                       result = info.props.getProperty(name);
  215                       if ((result != null) || (!info.props.isEmpty())) {
  216                           break;
  217                       }
  218                   }
  219                   current = current.getParent();
  220               }
  221               if (result == null) {
  222                   result = super.getProperty(name);
  223               }
  224           }
  225           // Simple property replacement (mostly for folder names)
  226           if (result != null) {
  227               result = replace(result);
  228           }
  229           return result;
  230       }
  231       
  232       
  233       public void readConfiguration()
  234           throws IOException, SecurityException {
  235           
  236           checkAccess();
  237           
  238           readConfiguration(Thread.currentThread().getContextClassLoader());
  239           
  240       }
  241           
  242       public void readConfiguration(InputStream is)
  243           throws IOException, SecurityException {
  244           
  245           checkAccess();
  246           reset();
  247   
  248           readConfiguration(is, Thread.currentThread().getContextClassLoader());
  249       
  250       }
  251           
  252       // ------------------------------------------------------ Protected Methods
  253   
  254   
  255       /**
  256        * Retrieve the configuration associated with the specified classloader. If
  257        * it does not exist, it will be created.
  258        * 
  259        * @param classLoader The classloader for which we will retrieve or build the 
  260        *                    configuration
  261        */
  262       protected ClassLoaderLogInfo getClassLoaderInfo(ClassLoader classLoader) {
  263           
  264           if (classLoader == null) {
  265               classLoader = ClassLoader.getSystemClassLoader();
  266           }
  267           ClassLoaderLogInfo info = (ClassLoaderLogInfo) classLoaderLoggers
  268                   .get(classLoader);
  269           if (info == null) {
  270               final ClassLoader classLoaderParam = classLoader;
  271               AccessController.doPrivileged(new PrivilegedAction() {
  272                   public Object run() {
  273                       try {
  274                           readConfiguration(classLoaderParam);
  275                       } catch (IOException e) {
  276                           // Ignore
  277                       }
  278                       return null;
  279                   }
  280               });
  281               info = (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader);
  282           }
  283           return info;
  284       }
  285   
  286       
  287       /**
  288        * Read configuration for the specified classloader.
  289        * 
  290        * @param classLoader 
  291        * @throws IOException Errot
  292        */
  293       protected void readConfiguration(ClassLoader classLoader)
  294           throws IOException {
  295           
  296           InputStream is = null;
  297           // Special case for URL classloaders which are used in containers: 
  298           // only look in the local repositories to avoid redefining loggers 20 times
  299           if ((classLoader instanceof URLClassLoader) 
  300                   && (((URLClassLoader) classLoader).findResource("logging.properties") != null)) {
  301               is = classLoader.getResourceAsStream("logging.properties");
  302           }
  303           if ((is == null) && (classLoader == ClassLoader.getSystemClassLoader())) {
  304               String configFileStr = System.getProperty("java.util.logging.config.file");
  305               if (configFileStr != null) {
  306                   try {
  307                       is = new FileInputStream(replace(configFileStr));
  308                   } catch (IOException e) {
  309                       // Ignore
  310                   }
  311               }
  312               // Try the default JVM configuration
  313               if (is == null) {
  314                   File defaultFile = new File(new File(System.getProperty("java.home"), "lib"), 
  315                       "logging.properties");
  316                   try {
  317                       is = new FileInputStream(defaultFile);
  318                   } catch (IOException e) {
  319                       // Critical problem, do something ...
  320                   }
  321               }
  322           }
  323           
  324           Logger localRootLogger = new RootLogger();
  325           if (is == null) {
  326               // Retrieve the root logger of the parent classloader instead
  327               ClassLoader current = classLoader.getParent();
  328               ClassLoaderLogInfo info = null;
  329               while (current != null && info == null) {
  330                   info = getClassLoaderInfo(current);
  331                   current = current.getParent();
  332               }
  333               if (info != null) {
  334                   localRootLogger.setParent(info.rootNode.logger);
  335               }
  336           }
  337           ClassLoaderLogInfo info = 
  338               new ClassLoaderLogInfo(new LogNode(null, localRootLogger));
  339           classLoaderLoggers.put(classLoader, info);
  340           
  341           if (is != null) {
  342               readConfiguration(is, classLoader);
  343           }
  344           addLogger(localRootLogger);
  345           
  346       }
  347       
  348       
  349       /**
  350        * Load specified configuration.
  351        * 
  352        * @param is InputStream to the properties file
  353        * @param classLoader for which the configuration will be loaded
  354        * @throws IOException If something wrong happens during loading
  355        */
  356       protected void readConfiguration(InputStream is, ClassLoader classLoader)
  357           throws IOException {
  358           
  359           ClassLoaderLogInfo info = 
  360               (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader);
  361           
  362           try {
  363               info.props.load(is);
  364           } catch (IOException e) {
  365               // Report error
  366               System.err.println("Configuration error");
  367               e.printStackTrace();
  368           } finally {
  369               try {
  370                   is.close();
  371               } catch (Throwable t) {}
  372           }
  373           
  374           // Create handlers for the root logger of this classloader
  375           String rootHandlers = info.props.getProperty(".handlers");
  376           String handlers = info.props.getProperty("handlers");
  377           Logger localRootLogger = info.rootNode.logger;
  378           if (handlers != null) {
  379               StringTokenizer tok = new StringTokenizer(handlers, ",");
  380               while (tok.hasMoreTokens()) {
  381                   String handlerName = (tok.nextToken().trim());
  382                   String handlerClassName = handlerName;
  383                   String prefix = "";
  384                   if (handlerClassName.length() <= 0) {
  385                       continue;
  386                   }
  387                   // Parse and remove a prefix (prefix start with a digit, such as 
  388                   // "10WebappFooHanlder.")
  389                   if (Character.isDigit(handlerClassName.charAt(0))) {
  390                       int pos = handlerClassName.indexOf('.');
  391                       if (pos >= 0) {
  392                           prefix = handlerClassName.substring(0, pos + 1);
  393                           handlerClassName = handlerClassName.substring(pos + 1);
  394                       }
  395                   }
  396                   try {
  397                       this.prefix.set(prefix);
  398                       Handler handler = 
  399                           (Handler) classLoader.loadClass(handlerClassName).newInstance();
  400                       // The specification strongly implies all configuration should be done 
  401                       // during the creation of the handler object.
  402                       // This includes setting level, filter, formatter and encoding.
  403                       this.prefix.set(null);
  404                       info.handlers.put(handlerName, handler);
  405                       if (rootHandlers == null) {
  406                           localRootLogger.addHandler(handler);
  407                       }
  408                   } catch (Exception e) {
  409                       // Report error
  410                       System.err.println("Handler error");
  411                       e.printStackTrace();
  412                   }
  413               }
  414               
  415           }
  416           
  417       }
  418       
  419       
  420       /**
  421        * Set parent child relationship between the two specified loggers.
  422        * 
  423        * @param logger
  424        * @param parent
  425        */
  426       protected static void doSetParentLogger(final Logger logger,
  427               final Logger parent) {
  428           AccessController.doPrivileged(new PrivilegedAction() {
  429               public Object run() {
  430                   logger.setParent(parent);
  431                   return null;
  432               }
  433           });
  434       }
  435   
  436       
  437       /**
  438        * System property replacement in the given string.
  439        * 
  440        * @param str The original string
  441        * @return the modified string
  442        */
  443       protected String replace(String str) {
  444           String result = str;
  445           int pos_start = result.indexOf("${");
  446           if (pos_start != -1) {
  447               int pos_end = result.indexOf('}');
  448               if (pos_end != -1) {
  449                   String propName = result.substring(pos_start + 2, pos_end);
  450                   String replacement = System.getProperty(propName);
  451                   if (replacement != null) {
  452                       if(pos_start >0) {
  453                           result = result.substring(0,pos_start) + 
  454                               replacement + replace(result.substring(pos_end + 1));
  455                       } else {                       
  456                           result = replacement + replace(result.substring(pos_end + 1));
  457                       }
  458                   }
  459               }
  460           }
  461           return result;
  462       }
  463       
  464   
  465       // ---------------------------------------------------- LogNode Inner Class
  466   
  467   
  468       protected static final class LogNode {
  469           Logger logger;
  470   
  471           protected final Map<String, LogNode> children = 
  472               new HashMap<String, LogNode>();
  473   
  474           protected final LogNode parent;
  475   
  476           LogNode(final LogNode parent, final Logger logger) {
  477               this.parent = parent;
  478               this.logger = logger;
  479           }
  480   
  481           LogNode(final LogNode parent) {
  482               this(parent, null);
  483           }
  484   
  485           LogNode findNode(String name) {
  486               LogNode currentNode = this;
  487               if (logger.getName().equals(name)) {
  488                   return this;
  489               }
  490               while (name != null) {
  491                   final int dotIndex = name.indexOf('.');
  492                   final String nextName;
  493                   if (dotIndex < 0) {
  494                       nextName = name;
  495                       name = null;
  496                   } else {
  497                       nextName = name.substring(0, dotIndex);
  498                       name = name.substring(dotIndex + 1);
  499                   }
  500                   LogNode childNode = (LogNode) currentNode.children
  501                           .get(nextName);
  502                   if (childNode == null) {
  503                       childNode = new LogNode(currentNode);
  504                       currentNode.children.put(nextName, childNode);
  505                   }
  506                   currentNode = childNode;
  507               }
  508               return currentNode;
  509           }
  510   
  511           Logger findParentLogger() {
  512               Logger logger = null;
  513               LogNode node = parent;
  514               while (node != null && logger == null) {
  515                   logger = node.logger;
  516                   node = node.parent;
  517               }
  518               return logger;
  519           }
  520   
  521           void setParentLogger(final Logger parent) {
  522               for (final Iterator iter = children.values().iterator(); iter
  523                       .hasNext();) {
  524                   final LogNode childNode = (LogNode) iter.next();
  525                   if (childNode.logger == null) {
  526                       childNode.setParentLogger(parent);
  527                   } else {
  528                       doSetParentLogger(childNode.logger, parent);
  529                   }
  530               }
  531           }
  532   
  533       }
  534   
  535   
  536       // -------------------------------------------- ClassLoaderInfo Inner Class
  537   
  538   
  539       protected static final class ClassLoaderLogInfo {
  540           final LogNode rootNode;
  541           final Map<String, Logger> loggers = new HashMap<String, Logger>();
  542           final Map<String, Handler> handlers = new HashMap<String, Handler>();
  543           final Properties props = new Properties();
  544   
  545           ClassLoaderLogInfo(final LogNode rootNode) {
  546               this.rootNode = rootNode;
  547           }
  548   
  549       }
  550   
  551   
  552       // ------------------------------------------------- RootLogger Inner Class
  553   
  554   
  555       /**
  556        * This class is needed to instantiate the root of each per classloader 
  557        * hierarchy.
  558        */
  559       protected class RootLogger extends Logger {
  560           public RootLogger() {
  561               super("", null);
  562           }
  563       }
  564   
  565   
  566   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » juli » [javadoc | source]