hoju 2003/08/27 00:54:38 Modified: src/java/org/apache/log4j/servlet InitContextListener.java InitServlet.java Added: src/java/org/apache/log4j/servlet InitShutdownController.java Log: Finally broke the logic for initializing and shutting down Log4j loggers and appenders into a separate class to be used by the InitcontextListener, the InitServlet, and any other class that wants to use this functionality. All configuration is done via context params (even for the InitServlet). For arbitrary classes using the new InitShutdownController class, configuration can be done via manipulating context params in memory at runtime before sending the ServletContext object to the InitShutdownController.initializeLog4j(ServletContext) method. Keys for the various context params are provided as static constants in InitShutdownController. This change allowed for a significant cleanup of the InitContextListener and InitServlet making both vastly simpler. Updated Javadoc in all files and Jalopied and checkstyled everything. All is well :-) Jake Revision Changes Path 1.9 +31 -347 jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/InitContextListener.java Index: InitContextListener.java =================================================================== RCS file: /home/cvs/jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/InitContextListener.java,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- InitContextListener.java 26 Aug 2003 15:42:12 -0000 1.8 +++ InitContextListener.java 27 Aug 2003 07:54:38 -0000 1.9 @@ -49,20 +49,6 @@ package org.apache.log4j.servlet; -import org.apache.log4j.LogManager; -import org.apache.log4j.PropertyConfigurator; -import org.apache.log4j.helpers.LogLog; -import org.apache.log4j.spi.RepositorySelector; -import org.apache.log4j.xml.DOMConfigurator; - -import java.io.File; - -import java.net.MalformedURLException; -import java.net.URL; - -import java.util.Properties; - -import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; @@ -112,12 +98,17 @@ * <context-param> * <!-- config file re-reading specified in milliseconds... * Note that if the webapp is served directly from a - * .war file, configureAndWatch() cannot be used because + * .war file and the log4j-log-home path is set to within the + * webapp (default), configureAndWatch() cannot be used because * it requires a system file path. In that case, this * param will be ignored. Set to 0 or don't specify this - * param to do a normal configure(). --> + * param to do a normal configure(). Additionally, the watchdogs + * in Log4j-1.2.x have no lifecycle, meaning that they can't be + * shut down, even by a call to LogManager.shutdown(). For this + * reason, it is recommended that this param not be used or set + * to 0. --> * <param-name>log4j-cron</param-name> - * <param-value>5000</param-value> + * <param-value>0</param-value> * </context-param> * <!-- Below are optional context params for use with a File Appender. * "log4j-log-home" specifies a path to be read from a @@ -169,6 +160,23 @@ * </h4> * <p> * <dl> + * <dt><code>log4j-selector</code></dt> + * <dd> + * The <code>log4j-selector</code> init parameter specifies the preferred + * repository selector for Log4j. Log4j only uses a single repository + * selector at a time and if one is already installed, a new one will not + * be installed except if one has a reference to the original guard object + * that can unlock the mechanism to re-set the repository selector. We make + * no attempt to store a handle to the guard object, so once it is set, there + * is no re-setting possible. The first application to set the repository + * selector will force that repository selector upon all other applications + * using a particular instance of log4j.jar. This is actually fine since + * any of the available repository selectors should provide a unique logging + * environment for each application. Just be ready to use all possible + * repository selectors. Of the classes in the [EMAIL PROTECTED] org.apache.log4j.selector selector} + * package, only the [EMAIL PROTECTED] org.apache.log4j.selector.ContextJNDISelector} requires + * any special setup. + * </dd> * <dt><code>log4j-config</code></dt> * <dd> * The <code>log4j-config</code> init parameter specifies the location of the @@ -186,7 +194,10 @@ * milliseconds to wait in between reads of the config file using * <code>configureAndWatch()</code>. If omitted, given a value of 0, or given * a value that is other than something that which can be converted to a Java - * long value a normal <code>configure()</code> is used. + * long value a normal <code>configure()</code> is used. Additionally, the watchdogs + * in Log4j-1.2.x have no lifecycle, meaning that they can't be shut down, even by a + * call to LogManager.shutdown(). For this + * reason, it is recommended that this param not be used or set to 0. * </dd> * <dt><code>log4j-log-home</code></dt> * <dd> @@ -246,52 +257,12 @@ */ public class InitContextListener implements ServletContextListener { /** - * preferred repository selector config param - */ - private static final String PARAM_LOG4J_PREF_SELECTOR = "log4j-selector"; - - /** - * relative path to config file within current webapp config param - */ - private static final String PARAM_LOG4J_CONFIG_PATH = "log4j-config"; - - /** - * config file re-reading specified in milliseconds config param - */ - private static final String PARAM_LOG4J_WATCH_INTERVAL = "log4j-cron"; - - /** - * path to be read from a log4j xml config file as a system property - * config param - */ - private static final String PARAM_LOG4J_LOG_HOME = "log4j-log-home"; - - /** - * system property to be used in a log4j xml config file config param - */ - private static final String PARAM_LOG4J_SYSPROP_NAME = "log4j-sysprop-name"; - - /** - * default path to write log files if using a file appender - */ - private static final String DEFAULT_LOG_HOME = - "WEB-INF" + File.separator + "logs"; - - /** - * preferred selector specified via config param - */ - private String selector = null; - - /** * Application Startup Event * * @param sce the context event provided by the container */ public void contextInitialized(ServletContextEvent sce) { - ServletContext context = sce.getServletContext(); - - selector = context.getInitParameter(PARAM_LOG4J_PREF_SELECTOR); - initializeLog4j(context); + InitShutdownController.initializeLog4j(sce.getServletContext()); } /** @@ -300,293 +271,6 @@ * @param sce the context event provided by the container */ public void contextDestroyed(ServletContextEvent sce) { - ServletContext context = sce.getServletContext(); - - cleanupLog4j(context); - } - - /** - * Log4j specific cleanup. Shuts down all loggers and appenders and - * removes the hierarchy associated with the current classloader. - * - * @param context the current servlet context - */ - private void cleanupLog4j(ServletContext context) { - //shutdown this webapp's logger repository - context.log( - "Cleaning up Log4j resources for context: " - + context.getServletContextName() + "..."); - context.log("Shutting down all loggers and appenders..."); - org.apache.log4j.LogManager.shutdown(); - context.log("Log4j cleaned up."); - } - - /** - * Log4j specific initialization. Sets up log4j for the current - * servlet context. Installs a custom repository selector if one hasn't - * already been installed. - * - * @param context the current servlet context - */ - private void initializeLog4j(ServletContext context) { - String configPath = context.getInitParameter(PARAM_LOG4J_CONFIG_PATH); - - // if the log4j-config parameter is not set, then no point in trying - if (configPath != null) { - if (configPath.startsWith("/")) { - configPath = (configPath.length() > 1) ? configPath.substring(1) : ""; - } - - // if the configPath is an empty string, then no point in trying - if (configPath.length() >= 1) { - // set up log path System property - String logHome = context.getInitParameter(PARAM_LOG4J_LOG_HOME); - - if (logHome != null) { - // set up custom log path system property - setFileAppenderSystemProperty(logHome, context); - } - - boolean isXMLConfigFile = (configPath.endsWith(".xml")) ? true : false; - String contextPath = context.getRealPath("/"); - - if (contextPath != null) { - // The webapp is deployed directly off the filesystem, - // not from a .war file so we *can* do File IO. - // This means we can use configureAndWatch() to re-read - // the the config file at defined intervals. - // Now let's check if the given configPath actually exists. - if (logHome == null) { - // no log path specified in web.xml. Setting to default - logHome = contextPath + DEFAULT_LOG_HOME; - setFileAppenderSystemProperty(logHome, context); - } - - String systemConfigPath = - configPath.replace('/', File.separatorChar); - File log4jFile = new File(contextPath + systemConfigPath); - - if (log4jFile.canRead()) { - log4jFile = null; - - String timerInterval = - context.getInitParameter(PARAM_LOG4J_WATCH_INTERVAL); - long timerIntervalVal = 0L; - - if (timerInterval != null) { - try { - timerIntervalVal = Integer.valueOf(timerInterval).longValue(); - } catch (NumberFormatException nfe) { - //ignore...we just won't use configureAndWatch if there is no - //valid int - ; - } - } - - setSelector(); - context.log( - "Configuring Log4j from File: " + contextPath + systemConfigPath); - - if (timerIntervalVal > 0) { - context.log( - "Configuring Log4j with watch interval: " + timerIntervalVal - + "ms"); - - if (isXMLConfigFile) { - DOMConfigurator.configureAndWatch( - contextPath + systemConfigPath, timerIntervalVal); - } else { - PropertyConfigurator.configureAndWatch( - contextPath + systemConfigPath, timerIntervalVal); - } - } else { - if (isXMLConfigFile) { - DOMConfigurator.configure(contextPath + systemConfigPath); - } else { - PropertyConfigurator.configure(contextPath + systemConfigPath); - } - } - } else { - //The given configPath does not exist. So, let's just let Log4j - //look for the default files (log4j.properties or log4j.xml) on - //its own. - displayConfigNotFoundMessage(); - } - - //end log4jFile.canRead() check - } else { - //The webapp is deployed from a .war file, not directly - //off the file system so we *cannot* do File IO. - //Note that we *won't* be able to use configureAndWatch() here - //because that requires an absolute system file path. - //Now let's check if the given configPath actually exists. - URL log4jURL = null; - - try { - log4jURL = context.getResource("/" + configPath); - } catch (MalformedURLException murle) { - //ignore...we check for null later - ; - } - - if (log4jURL != null) { - setSelector(); - context.log("Configuring Log4j from URL at path: /" + configPath); - - if (isXMLConfigFile) { - try { - DOMConfigurator.configure(log4jURL); - - //catch (javax.xml.parsers.FactoryConfigurationError fce) {} - } catch (Exception e) { - //report errors to server logs - LogLog.error(e.getMessage()); - } - } else { - Properties log4jProps = new Properties(); - - try { - log4jProps.load(log4jURL.openStream()); - PropertyConfigurator.configure(log4jProps); - - //catch (java.io.IOException ioe) {} - } catch (Exception e) { - //report errors to server logs - LogLog.error(e.getMessage()); - } - } - } else { - //The given configPath does not exist. So, let's just let Log4j - //look for the default files (log4j.properties or log4j.xml) on - //its own. - displayConfigNotFoundMessage(); - } - - //end log4jURL null check - } - - //end contextPath null check - } else { - LogLog.error("Zero length Log4j config file path given."); - displayConfigNotFoundMessage(); - } - - //end configPath length check - } else { - LogLog.error("Missing log4j-config servlet parameter missing."); - displayConfigNotFoundMessage(); - } - - //end configPath null check - } - - /** - * standard configuration not found message - */ - private void displayConfigNotFoundMessage() { - LogLog.warn( - "No Log4j configuration file found at given path. " - + "Falling back to Log4j auto-configuration."); - } - - /** - * sets the [webapp].log.home system property for use with a file appender. - * - * @param logHome the path to a logging directory - * @param context the current servlet context - */ - private void setFileAppenderSystemProperty( - String logHome, ServletContext context) { - String logHomePropName = null; - String customPropName = context.getInitParameter(PARAM_LOG4J_SYSPROP_NAME); - - if (customPropName != null) { - logHomePropName = customPropName; - } else { - File logHomeDir = new File(logHome); - - if (logHomeDir.exists() || logHomeDir.mkdirs()) { - /*String tempdir = - "" + context.getAttribute("javax.servlet.context.tempdir"); - int lastSlash = tempdir.lastIndexOf(File.separator); - - if ((tempdir.length() - 1) > lastSlash) { - logHomePropName = tempdir.substring(lastSlash + 1) + ".log.home"; - }*/ - String contextPath = ""; - - try { - //use a more standard way to obtain the context path name - //which should work across all servers. The tmpdir technique - //(above) depends upon the naming scheme that Tomcat uses. - String path = context.getResource("/").getPath(); - - //first remove trailing slash, then take what's left over - //which should be the context path less the preceeding - //slash such as "MyContext" - contextPath = path.substring(0, path.lastIndexOf("/")); - contextPath = - contextPath.substring(contextPath.lastIndexOf("/") + 1); - } catch (Exception e) { - ; - } - - logHomePropName = contextPath + ".log.home"; - } - } - - if (logHomePropName != null) { - context.log( - "Setting system property [ " + logHomePropName + " ] to [ " + logHome - + " ]"); - System.setProperty(logHomePropName, logHome); - } else { - context.log( - "Unable to derive log4j system property name. Consider setting the " - + "\"log4j-sysprop-name\" context parameter. No system property set."); - } - } - - /** - * Do idempotent initialization of the the logger repository. Only one - * repository selector may be set during runtime of log4j. Therefore, this - * method is only a guarantee that a repository selector will have been set. - * It does not guarantee that your preferred selector will be used. If - * some other code sets the selector first, that is the selector that all - * applications using Log4j will use, assuming log4j is running in a shared - * class loader. - */ - private void setSelector() { - if (selector == null) { - LogLog.warn( - "No preferred selector supplied. Using default repository selector..."); - - return; - } - - try { - Object guard = new Object(); - - Class clazz = - Class.forName( - selector, true, Thread.currentThread().getContextClassLoader()); - LogManager.setRepositorySelector( - (RepositorySelector) clazz.newInstance(), guard); - } catch (ClassNotFoundException cnfe) { - LogLog.warn( - "Preferred selector not found. Using default repository selector..."); - } catch (InstantiationException ie) { - LogLog.warn( - "Error in instantiation of preferred selector. Using default " - + "repository selector..."); - } catch (IllegalAccessException iae) { - LogLog.warn( - "Unable to access preferred selector. Using default repository " - + "selector..."); - } catch (IllegalArgumentException iae) { - LogLog.warn( - "Preferred repository selector not installed because one has already " - + "exists. No problem, using existing selector..."); - } + InitShutdownController.shutdownLog4j(sce.getServletContext()); } } 1.10 +6 -392 jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/InitServlet.java Index: InitServlet.java =================================================================== RCS file: /home/cvs/jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/InitServlet.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- InitServlet.java 26 Aug 2003 23:00:11 -0000 1.9 +++ InitServlet.java 27 Aug 2003 07:54:38 -0000 1.10 @@ -49,22 +49,8 @@ package org.apache.log4j.servlet; -import org.apache.log4j.LogManager; -import org.apache.log4j.PropertyConfigurator; -import org.apache.log4j.helpers.LogLog; -import org.apache.log4j.spi.RepositorySelector; -import org.apache.log4j.xml.DOMConfigurator; - -import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; - -import java.util.Properties; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -83,42 +69,7 @@ * initialization. If you really need to use this class, read on...</p> * <p> * This servlet is never called by a client, but should be called during - * web application initialization, i.e. when the servlet engine starts. The - * following code should be inserted in the web.xml file for the web - * application: - * <p> - * <pre> - * <servlet> - * <servlet-name>log4j-init</servlet-name> - * <servlet-class> - * org.apache.log4j.servlet.InitServlet - * </servlet-class> - * <init-param> - * <param-name>log4j-selector</param-name> - * <param-value> - * org.apache.log4j.selector.ContextClassLoaderSelector - * </param-value> - * </init-param> - * <init-param> - * <param-name>log4j-config</param-name> - * <param-value>WEB-INF/log4j.xml</param-value> - * </init-param> - * <init-param> - * <param-name>log4j-cron</param-name> - * <param-value>5000</param-value> - * </init-param> - * <init-param> - * <param-name>log4j-log-home</param-name> - * <param-value>/usr/local/logs/tomcat</param-value> - * </init-param> - * <init-param> - * <param-name>log4j-sysprop-name</param-name> - * <param-value>Barracuda.log.home</param-value> - * </init-param> - * <load-on-startup>1</load-on-startup> - * </servlet> - * </pre> - * </p> + * web application initialization, i.e. when the servlet engine starts.</p> * <p> * See [EMAIL PROTECTED] InitContextListener} for detailed information about these * parameters. @@ -129,48 +80,11 @@ */ public class InitServlet extends HttpServlet { /** - * preferred repository selector config param - */ - private static final String PARAM_LOG4J_PREF_SELECTOR = "log4j-selector"; - - /** - * relative path to config file within current webapp config param - */ - private static final String PARAM_LOG4J_CONFIG_PATH = "log4j-config"; - - /** - * config file re-reading specified in milliseconds config param - */ - private static final String PARAM_LOG4J_WATCH_INTERVAL = "log4j-cron"; - - /** - * path to be read from a log4j xml config file as a system property - * config param - */ - private static final String PARAM_LOG4J_LOG_HOME = "log4j-log-home"; - - /** - * system property to be used in a log4j xml config file config param - */ - private static final String PARAM_LOG4J_SYSPROP_NAME = "log4j-sysprop-name"; - - /** - * default path to write log files if using a file appender - */ - private static final String DEFAULT_LOG_HOME = - "WEB-INF" + File.separator + "logs"; - - /** * variable used to syncronize upon */ private static Boolean configured = Boolean.FALSE; /** - * preferred selector specified via config param - */ - private String selector = null; - - /** * Log4j specific initialization. Sets up log4j for the current * servlet context. Installs a custom repository selector if one hasn't * already been installed. @@ -179,298 +93,12 @@ */ public void init() throws ServletException { if (configured.equals(Boolean.FALSE)) { - String configPath = getInitParameter(PARAM_LOG4J_CONFIG_PATH); - selector = getInitParameter(PARAM_LOG4J_PREF_SELECTOR); - - // if the log4j-config parameter is not set, then no point in trying - if (configPath != null) { - if (configPath.startsWith("/")) { - configPath = - (configPath.length() > 1) ? configPath.substring(1) : ""; - } - - // if the configPath is an empty string, then no point in trying - if (configPath.length() >= 1) { - // set up log path System property - String logHome = getInitParameter(PARAM_LOG4J_LOG_HOME); - - if (logHome != null) { - // set up custom log path system property - setFileAppenderSystemProperty(logHome, this); - } - - boolean isXMLConfigFile = - (configPath.endsWith(".xml")) ? true : false; - String contextPath = getServletContext().getRealPath("/"); - - if (contextPath != null) { - // The webapp is deployed directly off the filesystem, - // not from a .war file so we *can* do File IO. - // This means we can use configureAndWatch() to re-read - // the the config file at defined intervals. - // Now let's check if the given configPath actually exists. - if (logHome == null) { - // no log path specified in web.xml. Setting to default - logHome = contextPath + DEFAULT_LOG_HOME; - setFileAppenderSystemProperty(logHome, this); - } - - String systemConfigPath = - configPath.replace('/', File.separatorChar); - File log4jFile = new File(contextPath + systemConfigPath); - - if (log4jFile.canRead()) { - log4jFile = null; - - String timerInterval = - getInitParameter(PARAM_LOG4J_WATCH_INTERVAL); - long timerIntervalVal = 0L; - - if (timerInterval != null) { - try { - timerIntervalVal = - Integer.valueOf(timerInterval).longValue(); - } catch (NumberFormatException nfe) { - //ignore...we just won't use configureAndWatch if there is no - //valid int - ; - } - } - - synchronized (configured) { - if (configured.equals(Boolean.FALSE)) { - setSelector(); - log( - "Configuring Log4j from File: " + contextPath - + systemConfigPath); - - if (timerIntervalVal > 0) { - log( - "Configuring Log4j with watch interval: " - + timerIntervalVal + "ms"); - - if (isXMLConfigFile) { - DOMConfigurator.configureAndWatch( - contextPath + systemConfigPath, timerIntervalVal); - } else { - PropertyConfigurator.configureAndWatch( - contextPath + systemConfigPath, timerIntervalVal); - } - } else { - if (isXMLConfigFile) { - DOMConfigurator.configure( - contextPath + systemConfigPath); - } else { - PropertyConfigurator.configure( - contextPath + systemConfigPath); - } - } - - configured = Boolean.TRUE; - } - - //end configured check - } - - //end syncronized block - } else { - //The given configPath does not exist. So, let's just let Log4j - //look for the default files (log4j.properties or log4j.xml) on - //its own. - displayConfigNotFoundMessage(); - } - - //end log4jFile.canRead() check - } else { - // The webapp is deployed from a .war file, not directly - // off the file system so we *cannot* do File IO. - // Note that we *won't* be able to use configureAndWatch() here - // because that requires an absolute system file path. - // Now let's check if the given configPath actually exists. - URL log4jURL = null; - - try { - log4jURL = getServletContext().getResource("/" + configPath); - } catch (MalformedURLException murle) { - //ignore...we check for null later - ; - } - - if (log4jURL != null) { - synchronized (configured) { - if (configured.equals(Boolean.FALSE)) { - setSelector(); - log("Configuring Log4j from URL at path: /" + configPath); - - if (isXMLConfigFile) { - try { - DOMConfigurator.configure(log4jURL); - configured = Boolean.TRUE; - - //catch (javax.xml.parsers.FactoryConfigurationError fce - // ) {} - } catch (Exception e) { - //report errors to server logs - LogLog.error(e.getMessage()); - } - } else { - Properties log4jProps = new Properties(); - - try { - log4jProps.load(log4jURL.openStream()); - PropertyConfigurator.configure(log4jProps); - configured = Boolean.TRUE; - - //catch (IOException ioe) {} - } catch (Exception e) { - //report errors to server logs - LogLog.error(e.getMessage()); - } - } - } - - //end configured check - } - - //end syncronized block - } else { - //The given configPath does not exist. So, let's just let Log4j - //look for the default files (log4j.properties or log4j.xml) on - //its own. - displayConfigNotFoundMessage(); - } - - //end log4jURL null check - } - - //end contextPath null check - } else { - LogLog.error("Zero length Log4j config file path given."); - displayConfigNotFoundMessage(); + synchronized (configured) { + if (configured.equals(Boolean.FALSE)) { + InitShutdownController.initializeLog4j(this.getServletContext()); + configured = Boolean.TRUE; } - - //end configPath length check - } else { - LogLog.error("Missing log4j-config servlet parameter missing."); - displayConfigNotFoundMessage(); } - - //end configPath null check - } - - //end configured check - } - - //end init() method - - /** - * standard configuration not found message - */ - private void displayConfigNotFoundMessage() { - LogLog.warn( - "No Log4j configuration file found at given path. " - + "Falling back to Log4j auto-configuration."); - } - - /** - * sets the [webapp].log.home system property for use with a file appender. - * - * @param logHome the path to a logging directory - * @param config the servlet config object for this servlet - */ - private void setFileAppenderSystemProperty( - String logHome, ServletConfig config) { - String logHomePropName = null; - String customPropName = config.getInitParameter(PARAM_LOG4J_SYSPROP_NAME); - ServletContext context = config.getServletContext(); - - if (customPropName != null) { - logHomePropName = customPropName; - } else { - File logHomeDir = new File(logHome); - - if (logHomeDir.exists() || logHomeDir.mkdirs()) { - /*String tempdir = - "" + context.getAttribute("javax.servlet.context.tempdir"); - int lastSlash = tempdir.lastIndexOf(File.separator); - - if ((tempdir.length() - 1) > lastSlash) { - logHomePropName = tempdir.substring(lastSlash + 1) + ".log.home"; - }*/ - String contextPath = ""; - - try { - //use a more standard way to obtain the context path name - //which should work across all servers. The tmpdir technique - //(above) depends upon the naming scheme that Tomcat uses. - String path = context.getResource("/").getPath(); - - //first remove trailing slash, then take what's left over - //which should be the context path less the preceeding - //slash such as "MyContext" - contextPath = path.substring(0, path.lastIndexOf("/")); - contextPath = - contextPath.substring(contextPath.lastIndexOf("/") + 1); - } catch (Exception e) { - ; - } - - logHomePropName = contextPath + ".log.home"; - } - } - - if (logHomePropName != null) { - context.log( - "Setting system property [ " + logHomePropName + " ] to [ " + logHome - + " ]"); - System.setProperty(logHomePropName, logHome); - } else { - context.log( - "Unable to derive log4j system property name. Consider setting the " - + "\"log4j-sysprop-name\" context parameter. No system property set."); - } - } - - /** - * Do idempotent initialization of the the logger repository. Only one - * repository selector may be set during runtime of log4j. Therefore, this - * method is only a guarantee that a repository selector will have been set. - * It does not guarantee that your preferred selector will be used. If - * some other code sets the selector first, that is the selector that all - * applications using Log4j will use, assuming log4j is running in a shared - * class loader. - */ - private void setSelector() { - if (selector == null) { - LogLog.warn( - "No preferred selector supplied. Using default repository selector..."); - - return; - } - - try { - Object guard = new Object(); - - Class clazz = - Class.forName( - selector, true, Thread.currentThread().getContextClassLoader()); - LogManager.setRepositorySelector( - (RepositorySelector) clazz.newInstance(), guard); - } catch (ClassNotFoundException cnfe) { - LogLog.warn( - "Preferred selector not found. Using default repository selector..."); - } catch (InstantiationException ie) { - LogLog.warn( - "Error in instantiation of preferred selector. Using default " - + "repository selector..."); - } catch (IllegalAccessException iae) { - LogLog.warn( - "Unable to access preferred selector. Using default repository " - + "selector..."); - } catch (IllegalArgumentException iae) { - LogLog.warn( - "Preferred repository selector not installed because one has already " - + "exists. No problem, using existing selector..."); } } @@ -483,22 +111,8 @@ * @throws ServletException indicates problem running servlet * @throws IOException indicates communication problem */ - public void doGet(HttpServletRequest req, HttpServletResponse res) + public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { throw new ServletException("Servlet only used for Log4j initialization"); - } - - /** - * Throws a ServletException because this servlet is not meant to be - * accessed from the web. - * - * @param req the http servlet request - * @param res the http servlet response - * @throws ServletException indicates problem running servlet - * @throws IOException indicates communication problem - */ - public void doPost(HttpServletRequest req, HttpServletResponse res) - throws ServletException, IOException { - doGet(req, res); } } 1.1 jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/InitShutdownController.java Index: InitShutdownController.java =================================================================== /* * ============================================================================ * The Apache Software License, Version 1.1 * ============================================================================ * * Copyright (C) 1999 The Apache Software Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowledgment: "This product includes software * developed by the Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, if * and wherever such third-party acknowledgments normally appear. * * 4. The names "log4j" and "Apache Software Foundation" must not be used to * endorse or promote products derived from this software without prior * written permission. For written permission, please contact * [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", nor may * "Apache" appear in their name, without prior written permission of the * Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This software consists of voluntary contributions made by many individuals * on behalf of the Apache Software Foundation. For more information on the * Apache Software Foundation, please see <http://www.apache.org/>. * */ package org.apache.log4j.servlet; import org.apache.log4j.LogManager; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.RepositorySelector; import org.apache.log4j.xml.DOMConfigurator; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.Properties; import javax.servlet.ServletContext; /** * Used to initialize and cleanup Log4j in a servlet environment. * <p>See [EMAIL PROTECTED] InitContextListener} for web.xml configuration instructions.</p> * <p>Besides basic webapp lifecycle control when used with InitContextListener * and [EMAIL PROTECTED] InitServlet}, this class can be used by any class at runtime to * control initialization and shutdown of Log4j loggers and appenders.</p> * * @author <a href="mailto:[EMAIL PROTECTED]">Jacob Kjome</a> * @since 1.3 */ public class InitShutdownController { /** * preferred repository selector config param. * Maps to web.xml <context-param> with * <param-name>log4j-selector</param-name> */ public static final String PARAM_LOG4J_PREF_SELECTOR = "log4j-selector"; /** * relative path to config file within current webapp config param. * Maps to web.xml <context-param> with * <param-name>log4j-config</param-name> */ public static final String PARAM_LOG4J_CONFIG_PATH = "log4j-config"; /** * config file re-reading specified in milliseconds config param. * Maps to web.xml <context-param> with * <param-name>log4j-cron</param-name> */ public static final String PARAM_LOG4J_WATCH_INTERVAL = "log4j-cron"; /** * path to be read from a log4j xml config file as a system property * config param. Maps to web.xml <context-param> with * <param-name>log4j-log-home</param-name> */ public static final String PARAM_LOG4J_LOG_HOME = "log4j-log-home"; /** * system property to be used in a log4j xml config file config param. * Maps to web.xml <context-param> with * <param-name>log4j-sysprop-name</param-name> */ public static final String PARAM_LOG4J_SYSPROP_NAME = "log4j-sysprop-name"; /** * default path to write log files if using a file appender */ private static final String DEFAULT_LOG_HOME = "WEB-INF" + File.separator + "logs"; /** * Log4j specific cleanup. Shuts down all loggers and appenders and * removes the hierarchy associated with the current classloader. * * @param context the current servlet context */ public static void shutdownLog4j(final ServletContext context) { //shutdown this webapp's logger repository context.log( "Cleaning up Log4j resources for context: " + context.getServletContextName() + "..."); context.log("Shutting down all loggers and appenders..."); org.apache.log4j.LogManager.shutdown(); context.log("Log4j cleaned up."); } /** * Log4j specific initialization. Sets up log4j for the current * servlet context. Installs a custom repository selector if one hasn't * already been installed. * * @param context the current servlet context */ public static void initializeLog4j(final ServletContext context) { String configPath = context.getInitParameter(PARAM_LOG4J_CONFIG_PATH); // if the log4j-config parameter is not set, then no point in trying if (configPath != null) { if (configPath.startsWith("/")) { configPath = (configPath.length() > 1) ? configPath.substring(1) : ""; } // if the configPath is an empty string, then no point in trying if (configPath.length() >= 1) { // set up log path System property String logHome = context.getInitParameter(PARAM_LOG4J_LOG_HOME); if (logHome != null) { // set up custom log path system property setFileAppenderSystemProperty(logHome, context); } boolean isXMLConfigFile = (configPath.endsWith(".xml")) ? true : false; String contextPath = context.getRealPath("/"); if (contextPath != null) { // The webapp is deployed directly off the filesystem, // not from a .war file so we *can* do File IO. // This means we can use configureAndWatch() to re-read // the the config file at defined intervals. // Now let's check if the given configPath actually exists. if (logHome == null) { // no log path specified in web.xml. Setting to default logHome = contextPath + DEFAULT_LOG_HOME; setFileAppenderSystemProperty(logHome, context); } String systemConfigPath = configPath.replace('/', File.separatorChar); File log4jFile = new File(contextPath + systemConfigPath); if (log4jFile.canRead()) { log4jFile = null; String timerInterval = context.getInitParameter(PARAM_LOG4J_WATCH_INTERVAL); long timerIntervalVal = 0L; if (timerInterval != null) { try { timerIntervalVal = Integer.valueOf(timerInterval).longValue(); } catch (NumberFormatException nfe) { //ignore...we just won't use configureAndWatch if there is no //valid int ; } } setSelector(context); context.log( "Configuring Log4j from File: " + contextPath + systemConfigPath); if (timerIntervalVal > 0) { context.log( "Configuring Log4j with watch interval: " + timerIntervalVal + "ms"); if (isXMLConfigFile) { DOMConfigurator.configureAndWatch( contextPath + systemConfigPath, timerIntervalVal); } else { PropertyConfigurator.configureAndWatch( contextPath + systemConfigPath, timerIntervalVal); } } else { if (isXMLConfigFile) { DOMConfigurator.configure(contextPath + systemConfigPath); } else { PropertyConfigurator.configure(contextPath + systemConfigPath); } } } else { //The given configPath does not exist. So, let's just let Log4j //look for the default files (log4j.properties or log4j.xml) on //its own. displayConfigNotFoundMessage(); } //end log4jFile.canRead() check } else { //The webapp is deployed from a .war file, not directly //off the file system so we *cannot* do File IO. //Note that we *won't* be able to use configureAndWatch() here //because that requires an absolute system file path. //Now let's check if the given configPath actually exists. URL log4jURL = null; try { log4jURL = context.getResource("/" + configPath); } catch (MalformedURLException murle) { //ignore...we check for null later ; } if (log4jURL != null) { setSelector(context); context.log("Configuring Log4j from URL at path: /" + configPath); if (isXMLConfigFile) { try { DOMConfigurator.configure(log4jURL); //catch (javax.xml.parsers.FactoryConfigurationError fce) {} } catch (Exception e) { //report errors to server logs LogLog.error(e.getMessage()); } } else { Properties log4jProps = new Properties(); try { log4jProps.load(log4jURL.openStream()); PropertyConfigurator.configure(log4jProps); //catch (java.io.IOException ioe) {} } catch (Exception e) { //report errors to server logs LogLog.error(e.getMessage()); } } } else { //The given configPath does not exist. So, let's just let Log4j //look for the default files (log4j.properties or log4j.xml) on //its own. displayConfigNotFoundMessage(); } //end log4jURL null check } //end contextPath null check } else { LogLog.error("Zero length Log4j config file path given."); displayConfigNotFoundMessage(); } //end configPath length check } else { LogLog.error("Missing log4j-config servlet parameter missing."); displayConfigNotFoundMessage(); } //end configPath null check } /** * standard configuration not found message */ private static void displayConfigNotFoundMessage() { LogLog.warn( "No Log4j configuration file found at given path. " + "Falling back to Log4j auto-configuration."); } /** * sets the [webapp].log.home system property for use with a file appender. * * @param logHome the path to a logging directory * @param context the current servlet context */ private static void setFileAppenderSystemProperty( final String logHome, final ServletContext context) { String logHomePropName = null; String customPropName = context.getInitParameter(PARAM_LOG4J_SYSPROP_NAME); if (customPropName != null) { logHomePropName = customPropName; } else { File logHomeDir = new File(logHome); if (logHomeDir.exists() || logHomeDir.mkdirs()) { /*String tempdir = "" + context.getAttribute("javax.servlet.context.tempdir"); int lastSlash = tempdir.lastIndexOf(File.separator); if ((tempdir.length() - 1) > lastSlash) { logHomePropName = tempdir.substring(lastSlash + 1) + ".log.home"; }*/ String contextPath = ""; try { //use a more standard way to obtain the context path name //which should work across all servers. The tmpdir technique //(above) depends upon the naming scheme that Tomcat uses. String path = context.getResource("/").getPath(); //first remove trailing slash, then take what's left over //which should be the context path less the preceeding //slash such as "MyContext" contextPath = path.substring(0, path.lastIndexOf("/")); contextPath = contextPath.substring(contextPath.lastIndexOf("/") + 1); } catch (Exception e) { ; } logHomePropName = contextPath + ".log.home"; } } if (logHomePropName != null) { context.log( "Setting system property [ " + logHomePropName + " ] to [ " + logHome + " ]"); System.setProperty(logHomePropName, logHome); } else { context.log( "Unable to derive log4j system property name. Consider setting the " + "\"log4j-sysprop-name\" context parameter. No system property set."); } } /** * Do idempotent initialization of the the logger repository. Only one * repository selector may be set during runtime of log4j. Therefore, this * method is only a guarantee that a repository selector will have been set. * It does not guarantee that your preferred selector will be used. If * some other code sets the selector first, that is the selector that all * applications using Log4j will use, assuming log4j is running in a shared * class loader. * * @param context the current servlet context */ private static void setSelector(final ServletContext context) { String selector = context.getInitParameter(PARAM_LOG4J_PREF_SELECTOR); if (selector == null) { LogLog.warn( "No preferred selector supplied. Using default repository selector..."); return; } try { Object guard = new Object(); Class clazz = Class.forName( selector, true, Thread.currentThread().getContextClassLoader()); LogManager.setRepositorySelector( (RepositorySelector) clazz.newInstance(), guard); } catch (ClassNotFoundException cnfe) { LogLog.warn( "Preferred selector not found. Using default repository selector..."); } catch (InstantiationException ie) { LogLog.warn( "Error in instantiation of preferred selector. Using default " + "repository selector..."); } catch (IllegalAccessException iae) { LogLog.warn( "Unable to access preferred selector. Using default repository " + "selector..."); } catch (IllegalArgumentException iae) { LogLog.warn( "Preferred repository selector not installed because one has already " + "exists. No problem, using existing selector..."); } } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]